| /* |
| * Copyright (c) 2014-2015 Yamaha Corporation |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version 2 |
| * of the License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
| * MA 02110-1301, USA. |
| */ |
| |
| #include <linux/delay.h> |
| #include <linux/errno.h> |
| #include <linux/i2c.h> |
| #include <linux/init.h> |
| #include <linux/input.h> |
| #include <linux/kernel.h> |
| #include <linux/list.h> |
| #include <linux/module.h> |
| #include <linux/mutex.h> |
| #include <linux/poll.h> |
| #include <linux/slab.h> |
| #include <linux/types.h> |
| #include <linux/uaccess.h> |
| #include <linux/workqueue.h> |
| |
| #include <linux/sensor/sensors_core.h> |
| #include "yas.h" |
| |
| static struct i2c_client *this_client; |
| |
| enum { |
| OFF = 0, |
| ON = 1 |
| }; |
| |
| #define MAG_LOG_TIME 15 /* 15 sec */ |
| |
| struct yas_state { |
| struct mutex lock; |
| struct mutex enable_lock; |
| struct yas_mag_driver mag; |
| struct input_dev *input; |
| struct i2c_client *client; |
| |
| ktime_t delay; |
| struct work_struct mag_work; |
| struct workqueue_struct *wq; |
| struct hrtimer mag_timer; |
| int time_count; |
| |
| struct device *yas_device; |
| int poll_delay; |
| int enable; |
| #if defined(CONFIG_SENSORS_YAS_RESET_DEFENCE_CODE) |
| int reset_state; |
| #endif |
| int32_t compass_data[3]; |
| |
| int reset_flag; |
| int position; |
| int16_t m[9]; |
| }; |
| |
| static int yas_device_open(int32_t type) |
| { |
| return 0; |
| } |
| |
| static int yas_device_close(int32_t type) |
| { |
| return 0; |
| } |
| |
| static int yas_device_write(int32_t type, uint8_t addr, const uint8_t *buf, |
| int len) |
| { |
| uint8_t tmp[2]; |
| if (sizeof(tmp) - 1 < len) |
| return -1; |
| tmp[0] = addr; |
| memcpy(&tmp[1], buf, len); |
| if (i2c_master_send(this_client, tmp, len + 1) < 0) |
| return -1; |
| return 0; |
| } |
| |
| static int yas_device_read(int32_t type, uint8_t addr, uint8_t *buf, int len) |
| { |
| struct i2c_msg msg[2]; |
| int err; |
| msg[0].addr = this_client->addr; |
| msg[0].flags = 0; |
| msg[0].len = 1; |
| msg[0].buf = &addr; |
| msg[1].addr = this_client->addr; |
| msg[1].flags = I2C_M_RD; |
| msg[1].len = len; |
| msg[1].buf = buf; |
| |
| err = i2c_transfer(this_client->adapter, msg, 2); |
| if (err != 2) { |
| dev_err(&this_client->dev, |
| "i2c_transfer() read error: " |
| "slave_addr=%02x, reg_addr=%02x, err=%d\n", |
| this_client->addr, addr, err); |
| return err; |
| } |
| return 0; |
| } |
| |
| static void yas_usleep(int us) |
| { |
| usleep_range(us, us + 1000); |
| } |
| |
| static uint32_t yas_current_time(void) |
| { |
| return jiffies_to_msecs(jiffies); |
| } |
| |
| /* Sysfs interface */ |
| static ssize_t yas_enable_show(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct yas_state *data = dev_get_drvdata(dev); |
| |
| return snprintf(buf, PAGE_SIZE, "%d\n", data->enable); |
| } |
| |
| static ssize_t yas_enable_store(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t size) |
| { |
| struct yas_state *data = dev_get_drvdata(dev); |
| int ret, pre_enable; |
| u8 enable; |
| |
| SENSOR_INFO("pre_enable=%d\n", data->enable); |
| |
| ret = kstrtou8(buf, 2, &enable); |
| if (ret) { |
| SENSOR_ERR("Invalid Argument\n"); |
| return ret; |
| } |
| |
| #if defined(CONFIG_SENSORS_YAS_RESET_DEFENCE_CODE) |
| if (data->reset_state) { |
| data->enable = enable; |
| return size; |
| } |
| #endif |
| mutex_lock(&data->enable_lock); |
| |
| SENSOR_INFO("new_value = %u\n", enable); |
| pre_enable = data->enable; |
| |
| if (enable) { |
| if (pre_enable == OFF) { |
| data->mag.set_enable(1); |
| data->enable = ON; |
| hrtimer_start(&data->mag_timer, data->delay, |
| HRTIMER_MODE_REL); |
| } |
| } else { |
| if (pre_enable == ON) { |
| hrtimer_cancel(&data->mag_timer); |
| cancel_work_sync(&data->mag_work); |
| data->mag.set_enable(0); |
| data->enable = OFF; |
| } |
| } |
| mutex_unlock(&data->enable_lock); |
| |
| return size; |
| } |
| |
| static ssize_t yas_delay_show(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct yas_state *data = dev_get_drvdata(dev); |
| |
| return snprintf(buf, 16, "%lld\n", ktime_to_ns(data->delay)); |
| } |
| |
| static ssize_t yas_delay_store(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t size) |
| { |
| struct yas_state *data = dev_get_drvdata(dev); |
| int ret, delay; |
| ret = kstrtoint(buf, 10, &delay); |
| if (ret) |
| return ret; |
| SENSOR_INFO("delay = %d\n", delay); |
| if (delay <= 0) |
| return -EINVAL; |
| else if (delay >= 200000000) |
| delay = 200000000; |
| |
| #if defined(CONFIG_SENSORS_YAS_RESET_DEFENCE_CODE) |
| if (data->reset_state) { |
| data->delay = ns_to_ktime(delay); |
| data->poll_delay = delay / NSEC_PER_MSEC; |
| data->mag.set_delay(data->poll_delay); |
| return size; |
| } |
| #endif |
| |
| SENSOR_INFO("+ mutex_lock\n"); |
| mutex_lock(&data->lock); |
| data->delay = ns_to_ktime(delay); |
| data->poll_delay = delay / NSEC_PER_MSEC; |
| data->mag.set_delay(data->poll_delay); |
| mutex_unlock(&data->lock); |
| SENSOR_INFO("- mutex_unlock\n"); |
| |
| return size; |
| } |
| |
| static DEVICE_ATTR(poll_delay, S_IRUGO | S_IWUSR | S_IWGRP, |
| yas_delay_show, yas_delay_store); |
| static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP, |
| yas_enable_show, yas_enable_store); |
| |
| static struct attribute *yas_attributes[] = { |
| &dev_attr_poll_delay.attr, |
| &dev_attr_enable.attr, |
| NULL |
| }; |
| |
| static const struct attribute_group yas_attribute_group = { |
| .attrs = yas_attributes, |
| }; |
| |
| static ssize_t yas_vendor_show(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR_NAME); |
| } |
| |
| static ssize_t yas_name_show(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| return snprintf(buf, PAGE_SIZE, "%s\n", DEV_NAME); |
| } |
| |
| static ssize_t yas_self_test_show(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct yas_state *data = i2c_get_clientdata(this_client); |
| struct yas539_self_test_result r; |
| s8 err[7] = { 0, }; |
| #ifdef CONFIG_SENSORS_YAS539_A20E |
| int vector_sum; |
| #endif |
| int ret; |
| |
| mutex_lock(&data->lock); |
| ret = data->mag.ext(YAS539_SELF_TEST, &r); |
| if (ret < 0) { |
| SENSOR_ERR("YAS539_SELF_TEST err : %d\n", ret); |
| if (ret == YAS_ERROR_BUSY |
| || ret == YAS_ERROR_DEVICE_COMMUNICATION |
| || ret == YAS_ERROR_CHIP_ID) |
| err[0] = -1; |
| else if (ret == YAS_ERROR_OVERFLOW |
| || ret == YAS_ERROR_UNDERFLOW) |
| err[6] = -1; |
| mutex_unlock(&data->lock); |
| goto exit; |
| } |
| mutex_unlock(&data->lock); |
| |
| if (unlikely(r.id != 0x8)) |
| err[0] = -1; |
| if (unlikely(r.sxy1y2[0] > 17024 || r.sxy1y2[0] < 16544)) |
| err[5] = -1; |
| if (unlikely(r.sxy1y2[1] > 17184 || r.sxy1y2[1] < 16517)) |
| err[5] = -2; |
| if (unlikely(r.sxy1y2[2] > 16251 || r.sxy1y2[2] < 15584)) |
| err[5] = -4; |
| #ifdef CONFIG_SENSORS_YAS539_A20E |
| if (unlikely(r.xyz[0] < -1500 || r.xyz[0] > 1500)) |
| err[6] = -1; |
| if (unlikely(r.xyz[1] < -1500 || r.xyz[1] > 1500)) |
| err[6] = -1; |
| if (unlikely(r.xyz[2] < -1500 || r.xyz[2] > 1500)) |
| err[6] = -1; |
| vector_sum = r.xyz[0] * r.xyz[0] + r.xyz[1] * r.xyz[1] + r.xyz[2] * r.xyz[2]; |
| if (unlikely(vector_sum >= 2250000)) { |
| err[6] = -1; |
| pr_info("[SENSOR] Fail vetor_sum^2= %d\n", vector_sum); |
| } |
| #else |
| if (unlikely(r.xyz[0] < -1000 || r.xyz[0] > 1000)) |
| err[6] = -1; |
| if (unlikely(r.xyz[1] < -1000 || r.xyz[1] > 1000)) |
| err[6] = -1; |
| if (unlikely(r.xyz[2] < -1000 || r.xyz[2] > 1000)) |
| err[6] = -1; |
| #endif |
| |
| pr_info("[SENSOR] %s\n" |
| "[SENSOR] Test1 - err = %d, id = %d\n" |
| "[SENSOR] Test3 - err = %d\n" |
| "[SENSOR] Test4 - err = %d, offset = %d,%d,%d\n" |
| "[SENSOR] Test5 - err = %d, direction = %d\n" |
| "[SENSOR] Test6 - err = %d, sensitivity = %d,%d,%d\n" |
| "[SENSOR] Test7 - err = %d, offset = %d,%d,%d\n" |
| "[SENSOR] Test2 - err = %d\n", __func__, |
| err[0], r.id, err[2], err[3], err[4], err[4], |
| err[4], err[4], err[4], err[5],r.sxy1y2[0], r.sxy1y2[1],r.sxy1y2[2], |
| err[6], r.xyz[0], r.xyz[1], r.xyz[2], err[1]); |
| |
| exit: |
| data->reset_flag = 1; |
| |
| return sprintf(buf, |
| "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", |
| err[0], r.id, err[2], err[3], err[4], |
| err[4], err[4], err[4], err[4], |
| err[5],r.sxy1y2[0], r.sxy1y2[1],r.sxy1y2[2], err[6], |
| r.xyz[0], r.xyz[1], r.xyz[2], err[1]); |
| } |
| |
| static ssize_t yas_self_test_noise_show(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct yas_state *data = i2c_get_clientdata(this_client); |
| int32_t xyz_raw[3]; |
| int ret; |
| |
| mutex_lock(&data->lock); |
| ret = data->mag.ext(YAS539_SELF_TEST_NOISE, xyz_raw); |
| mutex_unlock(&data->lock); |
| |
| if (ret < 0) |
| return -EFAULT; |
| |
| return sprintf(buf, "%d,%d,%d\n", xyz_raw[0], xyz_raw[1], xyz_raw[2]); |
| } |
| |
| static ssize_t yas_self_test_noise_store(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t size) |
| { |
| u8 enable; |
| int ret; |
| struct yas_state *data = dev_get_drvdata(dev); |
| |
| ret = kstrtou8(buf, 2, &enable); |
| if (ret) { |
| SENSOR_ERR("Invalid Argument\n"); |
| return size; |
| } |
| |
| SENSOR_INFO("%u\n", enable); |
| if (enable == 1) |
| data->reset_flag = 1; |
| |
| return size; |
| } |
| |
| static ssize_t yas_dhr_sensor_info_show(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| int16_t m[9] = { 0, }; |
| struct yas_state *data = dev_get_drvdata(dev); |
| |
| data->mag.ext(YAS539_GET_STATIC_MATRIX, m); |
| |
| return snprintf(buf, PAGE_SIZE, |
| "\"SI_PARAMETER\":\"%d %d %d %d %d %d %d %d %d\"\n", |
| m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]); |
| } |
| |
| static ssize_t yas_static_matrix_store(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t size) |
| { |
| int m[9], i; |
| int16_t m_buf[9], ret; |
| struct yas_state *data = dev_get_drvdata(dev); |
| |
| if (sscanf(buf, "%6d,%6d,%6d,%6d,%6d,%6d,%6d,%6d,%6d", &m[0], &m[1], |
| &m[2], &m[3], &m[4], &m[5], &m[6], &m[7], &m[8]) != 9) { |
| SENSOR_ERR("invalid value\n"); |
| return size; |
| } |
| |
| for (i = 0; i < 9; i++) |
| m_buf[i] = (int16_t)m[i]; |
| |
| ret = data->mag.ext(YAS539_SET_STATIC_MATRIX, m_buf); |
| if (ret < 0) |
| SENSOR_ERR("matrix writing failed %d\n", ret); |
| |
| return size; |
| } |
| |
| static ssize_t yas_static_matrix_show(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| int16_t m[9], ret; |
| struct yas_state *data = dev_get_drvdata(dev); |
| |
| data->mag.ext(YAS539_GET_STATIC_MATRIX, m); |
| |
| ret = snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d,%d,%d,%d,%d,%d\n", |
| m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]); |
| |
| return ret; |
| } |
| |
| |
| |
| #if defined(CONFIG_SENSORS_YAS_RESET_DEFENCE_CODE) |
| static ssize_t yas_power_reset_show(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct yas_state *data = dev_get_drvdata(dev); |
| |
| data->reset_state = ON; |
| mutex_lock(&data->enable_lock); |
| SENSOR_INFO("Start!\n"); |
| if (data->enable) { |
| hrtimer_cancel(&data->mag_timer); |
| cancel_work_sync(&data->mag_work); |
| } |
| mutex_unlock(&data->enable_lock); |
| SENSOR_INFO("Done!\n"); |
| return sprintf(buf, "1"); |
| } |
| |
| static ssize_t yas_sw_reset_show(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct yas_state *data = dev_get_drvdata(dev); |
| int position, i; |
| int16_t m[9]; |
| |
| mutex_lock(&data->enable_lock); |
| SENSOR_INFO("Start!\n"); |
| data->reset_state = OFF; |
| |
| data->mag.term(); |
| data->mag.init(); |
| position = data->position; |
| data->mag.set_position(position); |
| for (i = 0; i < 9; i++) |
| m[i] = data->m[i]; |
| data->mag.ext(YAS539_SET_STATIC_MATRIX, m); |
| |
| if (data->enable) { |
| SENSOR_INFO("Magnetic enable\n"); |
| data->mag.set_enable(1); |
| data->mag.set_delay(data->poll_delay); |
| hrtimer_start(&data->mag_timer, data->delay, |
| HRTIMER); |
| } else { |
| data->mag.set_enable(0); |
| } |
| |
| mutex_unlock(&data->enable_lock); |
| SENSOR_INFO("Done!\n"); |
| return sprintf(buf, "1"); |
| } |
| static DEVICE_ATTR(power_reset, S_IRUSR | S_IRGRP, yas_power_reset_show, NULL); |
| static DEVICE_ATTR(sw_reset, S_IRUSR | S_IRGRP, yas_sw_reset_show, NULL); |
| #endif |
| static DEVICE_ATTR(vendor, S_IRUGO, yas_vendor_show, NULL); |
| static DEVICE_ATTR(name, S_IRUGO, yas_name_show, NULL); |
| static DEVICE_ATTR(selftest, S_IRUSR, yas_self_test_show, NULL); |
| static DEVICE_ATTR(raw_data, S_IRUGO | S_IWUSR | S_IWGRP, |
| yas_self_test_noise_show, yas_self_test_noise_store); |
| static DEVICE_ATTR(dhr_sensor_info, S_IRUSR | S_IRGRP, |
| yas_dhr_sensor_info_show, NULL); |
| static DEVICE_ATTR(matrix, S_IRUGO | S_IWUSR | S_IWGRP, |
| yas_static_matrix_show, yas_static_matrix_store); |
| |
| static struct device_attribute *mag_sensor_attrs[] = { |
| &dev_attr_vendor, |
| &dev_attr_name, |
| &dev_attr_selftest, |
| &dev_attr_raw_data, |
| &dev_attr_dhr_sensor_info, |
| &dev_attr_matrix, |
| #if defined(CONFIG_SENSORS_YAS_RESET_DEFENCE_CODE) |
| &dev_attr_power_reset, |
| &dev_attr_sw_reset, |
| #endif |
| NULL |
| }; |
| |
| static enum hrtimer_restart yas_timer_func(struct hrtimer *timer) |
| { |
| struct yas_state *data = container_of(timer, |
| struct yas_state, mag_timer); |
| |
| if (!work_pending(&data->mag_work)) |
| queue_work(data->wq, &data->mag_work); |
| |
| hrtimer_forward_now(&data->mag_timer, data->delay); |
| |
| return HRTIMER_RESTART; |
| } |
| |
| static void yas_work_func(struct work_struct *work) |
| { |
| struct yas_data mag[1]; |
| struct yas_state *data = container_of(work, |
| struct yas_state, mag_work); |
| int ret, i; |
| |
| mutex_lock(&data->lock); |
| |
| ret = data->mag.measure(mag, 1); |
| if (ret <= 0) { |
| mutex_unlock(&data->lock); |
| goto exit; |
| } |
| |
| for (i = 0; i < 3; i++) |
| data->compass_data[i] = mag[0].xyz.v[i]; |
| |
| mutex_unlock(&data->lock); |
| |
| input_report_rel(data->input, REL_X, data->compass_data[0]); |
| input_report_rel(data->input, REL_Y, data->compass_data[1]); |
| input_report_rel(data->input, REL_Z, data->compass_data[2]); |
| if (data->reset_flag) { |
| SENSOR_INFO("Magnetic cal reset!\n"); |
| input_report_rel(data->input, REL_RZ, data->reset_flag); |
| data->reset_flag = 0; |
| } |
| input_sync(data->input); |
| |
| exit: |
| if ((ktime_to_ns(data->delay) * data->time_count) |
| >= ((int64_t)MAG_LOG_TIME * NSEC_PER_SEC)) { |
| SENSOR_INFO("x = %d, y = %d, z = %d\n", |
| data->compass_data[0], data->compass_data[1], data->compass_data[2]); |
| data->time_count = 0; |
| } else { |
| data->time_count++; |
| } |
| |
| } |
| |
| static int yas_input_init(struct yas_state *data) |
| { |
| struct input_dev *dev; |
| int ret = 0; |
| |
| dev = input_allocate_device(); |
| if (!dev) |
| return -ENOMEM; |
| |
| dev->name = MODULE_NAME_MAG; |
| dev->id.bustype = BUS_I2C; |
| |
| input_set_capability(dev, EV_REL, REL_X); |
| input_set_capability(dev, EV_REL, REL_Y); |
| input_set_capability(dev, EV_REL, REL_Z); |
| input_set_capability(dev, EV_REL, REL_RZ); |
| input_set_drvdata(dev, data); |
| |
| ret = input_register_device(dev); |
| if (ret < 0) |
| goto err_register_input_dev; |
| |
| ret = sensors_create_symlink(&dev->dev.kobj, dev->name); |
| if (ret < 0) |
| goto err_create_sensor_symlink; |
| |
| /* sysfs node creation */ |
| ret = sysfs_create_group(&dev->dev.kobj, &yas_attribute_group); |
| if (ret < 0) |
| goto err_create_sysfs_group; |
| |
| data->input = dev; |
| |
| return 0; |
| |
| err_create_sysfs_group: |
| sensors_remove_symlink(&dev->dev.kobj, dev->name); |
| err_create_sensor_symlink: |
| input_unregister_device(dev); |
| err_register_input_dev: |
| input_free_device(dev); |
| return ret; |
| } |
| |
| static int yas_parse_dt(struct device *dev, struct yas_state *data) |
| { |
| struct device_node *np = dev->of_node; |
| u32 softiron[9] = {10000, 0, 0, 0, 10000, 0, 0, 0, 10000}; |
| u32 sign[9] = {2, 1, 1, 1, 2, 1, 1, 1, 2}; |
| int i = 0; |
| |
| if (!of_property_read_u32(np, "yas,orientation", &data->position)) |
| SENSOR_INFO("yas,orientation = %d\n", data->position); |
| else |
| return -EINVAL; |
| |
| if (of_property_read_u32_array(np, "yas,softiron", softiron, 9) < 0) |
| SENSOR_ERR("get softiron(%d) error\n", softiron[0]); |
| |
| if (of_property_read_u32_array(np, "yas,softiron_sign", sign, 9) < 0) |
| SENSOR_ERR("get softiron(%d) error\n", sign[0]); |
| |
| for (i = 0; i < 9; i++) { |
| data->m[i] = (softiron[i])*(sign[i]-1); |
| SENSOR_ERR("softiron = %d, sign = %d\n", softiron[i], sign[i]); |
| } |
| |
| return 0; |
| } |
| |
| static int yas_probe(struct i2c_client *i2c, const struct i2c_device_id *id) |
| { |
| struct yas_state *data; |
| int ret, i; |
| int position; |
| int16_t m[9]; |
| |
| SENSOR_INFO("PROBE START\n"); |
| |
| this_client = i2c; |
| data = kzalloc(sizeof(struct yas_state), GFP_KERNEL); |
| if (!data) { |
| SENSOR_ERR("kzalloc error\n"); |
| ret = -ENOMEM; |
| goto err_ret; |
| } |
| i2c_set_clientdata(i2c, data); |
| |
| data->client = i2c; |
| data->poll_delay = YAS_DEFAULT_SENSOR_DELAY; |
| data->mag.callback.device_open = yas_device_open; |
| data->mag.callback.device_close = yas_device_close; |
| data->mag.callback.device_write = yas_device_write; |
| data->mag.callback.device_read = yas_device_read; |
| data->mag.callback.usleep = yas_usleep; |
| data->mag.callback.current_time = yas_current_time; |
| |
| /* workqueue init */ |
| hrtimer_init(&data->mag_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| data->delay = ns_to_ktime(YAS_DEFAULT_SENSOR_DELAY); |
| data->mag_timer.function = yas_timer_func; |
| |
| data->wq = create_singlethread_workqueue("mag_wq"); |
| if (!data->wq) { |
| ret = -ENOMEM; |
| SENSOR_ERR("could not create accel workqueue\n"); |
| goto err_ret; |
| } |
| |
| INIT_WORK(&data->mag_work, yas_work_func); |
| |
| data->enable = OFF; |
| #if defined(CONFIG_SENSORS_YAS_RESET_DEFENCE_CODE) |
| data->reset_state = OFF; |
| #endif |
| mutex_init(&data->lock); |
| mutex_init(&data->enable_lock); |
| |
| for (i = 0; i < 3; i++) |
| data->compass_data[i] = 0; |
| |
| /* input device init */ |
| ret = yas_input_init(data); |
| if (ret < 0) { |
| SENSOR_ERR("input init fail (%d)\n", ret); |
| goto err_input_init; |
| } |
| |
| ret = yas_mag_driver_init(&data->mag); |
| if (ret < 0) { |
| ret = -EFAULT; |
| goto err_unregister; |
| } |
| ret = data->mag.init(); |
| if (ret < 0) { |
| ret = -EFAULT; |
| goto err_unregister; |
| } |
| |
| ret = yas_parse_dt(&i2c->dev, data); |
| if (!ret) { |
| position = data->position; |
| ret = data->mag.set_position(position); |
| SENSOR_INFO("set_position (%d)\n", position); |
| |
| for (i = 0; i < 9; i++) |
| m[i] = data->m[i]; |
| |
| ret = data->mag.ext(YAS539_SET_STATIC_MATRIX, m); |
| } else { |
| SENSOR_ERR("parse_dt error\n"); |
| ret = -ENODEV; |
| goto err_parse_dt; |
| } |
| |
| ret = sensors_register(&data->yas_device, data, mag_sensor_attrs, |
| MODULE_NAME_MAG); |
| if (ret < 0) { |
| SENSOR_ERR("cound not register mag sensor device(%d).\n", ret); |
| goto err_mag_sensor_register_failed; |
| } |
| |
| SENSOR_INFO("PROBE END\n"); |
| return 0; |
| |
| err_mag_sensor_register_failed: |
| err_parse_dt: |
| err_unregister: |
| sensors_remove_symlink(&data->input->dev.kobj, data->input->name); |
| sysfs_remove_group(&data->input->dev.kobj, &yas_attribute_group); |
| input_unregister_device(data->input); |
| err_input_init: |
| i2c_set_clientdata(i2c, NULL); |
| mutex_destroy(&data->enable_lock); |
| mutex_destroy(&data->lock); |
| kfree(data); |
| err_ret: |
| this_client = NULL; |
| SENSOR_ERR("PROBE FAILED\n"); |
| return ret; |
| } |
| |
| static int yas_remove(struct i2c_client *i2c) |
| { |
| struct yas_state *data = (struct yas_state *)i2c_get_clientdata(i2c); |
| |
| if (data->enable) { |
| /* destroy workqueue */ |
| hrtimer_cancel(&data->mag_timer); |
| cancel_work_sync(&data->mag_work); |
| data->mag.term(); |
| /* sysfs destroy */ |
| sensors_unregister(data->yas_device, mag_sensor_attrs); |
| sysfs_remove_group(&data->input->dev.kobj, |
| &yas_attribute_group); |
| /* lock destroy */ |
| mutex_destroy(&data->enable_lock); |
| mutex_destroy(&data->lock); |
| |
| sensors_remove_symlink(&data->input->dev.kobj, |
| data->input->name); |
| input_unregister_device(data->input); |
| |
| kfree(data); |
| this_client = NULL; |
| } |
| return 0; |
| } |
| |
| static void yas_shutdown(struct i2c_client *i2c) |
| { |
| struct yas_state *data = (struct yas_state *)i2c_get_clientdata(i2c); |
| |
| SENSOR_INFO("is called.\n"); |
| if (data->enable) { |
| hrtimer_cancel(&data->mag_timer); |
| cancel_work_sync(&data->mag_work); |
| data->mag.set_enable(0); |
| } |
| } |
| |
| static int yas_suspend(struct device *dev) |
| { |
| struct yas_state *data = dev_get_drvdata(dev); |
| if (data->enable) { |
| hrtimer_cancel(&data->mag_timer); |
| cancel_work_sync(&data->mag_work); |
| data->mag.set_enable(0); |
| } |
| return 0; |
| } |
| |
| static int yas_resume(struct device *dev) |
| { |
| struct yas_state *data = dev_get_drvdata(dev); |
| if (data->enable) { |
| data->mag.set_enable(1); |
| hrtimer_start(&data->mag_timer, data->delay, |
| HRTIMER_MODE_REL); |
| } |
| return 0; |
| } |
| |
| static struct of_device_id yas_match_table[] = { |
| { .compatible = "yas_magnetometer",}, |
| {}, |
| }; |
| |
| static const struct i2c_device_id yas_id[] = { |
| {YAS_MAG_NAME, 0}, |
| { } |
| }; |
| MODULE_DEVICE_TABLE(i2c, yas_id); |
| |
| static const struct dev_pm_ops yas_pm_ops = { |
| .suspend = yas_suspend, |
| .resume = yas_resume |
| }; |
| |
| static struct i2c_driver yas_driver = { |
| .driver = { |
| .name = YAS_MAG_NAME, |
| .owner = THIS_MODULE, |
| .pm = &yas_pm_ops, |
| .of_match_table = yas_match_table, |
| }, |
| .probe = yas_probe, |
| .remove = yas_remove, |
| .shutdown = yas_shutdown, |
| .id_table = yas_id, |
| }; |
| module_i2c_driver(yas_driver); |
| |
| MODULE_DESCRIPTION("Yamaha Magnetometer I2C driver"); |
| MODULE_LICENSE("GPL v2"); |
| MODULE_VERSION("1.0.0.1200"); |