Loading Documentation/devicetree/bindings/input/misc/akm09911.txt +5 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,10 @@ Required properties: 8: 1st pin is right down (from top view) - akm,gpio_rstn : The gpio pin to reset the sensor chip. Optional properites: - akm,auto-report : Enable auto-report mode. Example: akm@c { compatible = "ak,ak09911"; Loading @@ -33,5 +37,6 @@ Required properties: vio-supply = <&pm8110_l14>; akm,layout = <0x0>; akm,gpio_rstn = <&msmgpio 82 0x0>; akm,auto-report; }; drivers/input/misc/akm09911.c +120 −4 Original line number Diff line number Diff line Loading @@ -47,6 +47,8 @@ #define AKM09911_VIO_MIN_UV 1750000 #define AKM09911_VIO_MAX_UV 1950000 #define STATUS_ERROR(st) (((st)&0x19) != 0x01) struct akm_compass_data { struct i2c_client *i2c; struct input_dev *input; Loading @@ -56,6 +58,7 @@ struct akm_compass_data { struct pinctrl_state *pin_default; struct pinctrl_state *pin_sleep; struct sensors_classdev cdev; struct delayed_work dwork; wait_queue_head_t drdy_wq; wait_queue_head_t open_wq; Loading Loading @@ -86,6 +89,7 @@ struct akm_compass_data { int irq; int gpio_rstn; int power_enabled; int auto_report; struct regulator *vdd; struct regulator *vio; }; Loading Loading @@ -844,6 +848,18 @@ static int akm_enable_set(struct sensors_classdev *sensors_cdev, akm_compass_sysfs_update_status(akm); if (akm->auto_report) { if (enable) { AKECS_SetMode(akm, AKM_MODE_SNG_MEASURE); schedule_delayed_work(&akm->dwork, (unsigned long)nsecs_to_jiffies64( akm->delay[MAG_DATA_FLAG])); } else { cancel_delayed_work_sync(&akm->dwork); AKECS_SetMode(akm, AKM_MODE_POWERDOWN); } } return 0; } Loading Loading @@ -1556,6 +1572,11 @@ static int akm_compass_parse_dt(struct device *dev, s_akm->layout = temp_val; } if (of_property_read_bool(np, "akm,auto-report")) s_akm->auto_report = 1; else s_akm->auto_report = 0; s_akm->gpio_rstn = of_get_named_gpio_flags(dev->of_node, "akm,gpio_rstn", 0, NULL); Loading Loading @@ -1600,6 +1621,96 @@ static int akm_pinctrl_init(struct akm_compass_data *s_akm) return 0; } static void akm_dev_poll(struct work_struct *work) { struct akm_compass_data *akm; uint8_t dat_buf[AKM_SENSOR_DATA_SIZE];/* for GET_DATA */ int ret; int mag_x, mag_y, mag_z; int tmp; akm = container_of((struct delayed_work *)work, struct akm_compass_data, dwork); ret = AKECS_GetData_Poll(akm, dat_buf, AKM_SENSOR_DATA_SIZE); if (ret < 0) { dev_warn(&s_akm->i2c->dev, "Get data failed\n"); goto exit; } tmp = dat_buf[0] | dat_buf[7]; if (STATUS_ERROR(tmp)) { dev_warn(&s_akm->i2c->dev, "Status error(0x%x). Reset...\n", tmp); AKECS_Reset(akm, 0); goto exit; } tmp = (int)((int16_t)(dat_buf[2]<<8)+((int16_t)dat_buf[1])); tmp = tmp * akm->sense_conf[0] / 256 + tmp / 2; mag_x = tmp; tmp = (int)((int16_t)(dat_buf[4]<<8)+((int16_t)dat_buf[3])); tmp = tmp * akm->sense_conf[1] / 256 + tmp / 2; mag_y = tmp; tmp = (int)((int16_t)(dat_buf[6]<<8)+((int16_t)dat_buf[5])); tmp = tmp * akm->sense_conf[2] / 256 + tmp / 2; mag_z = tmp; switch (akm->layout) { case 0: case 1: /* Fall into the default direction */ break; case 2: tmp = mag_x; mag_x = mag_y; mag_y = -tmp; break; case 3: mag_x = -mag_x; mag_y = -mag_y; break; case 4: tmp = mag_x; mag_x = -mag_y; mag_y = tmp; break; case 5: mag_x = -mag_x; mag_z = -mag_z; break; case 6: tmp = mag_x; mag_x = mag_y; mag_y = tmp; mag_z = -mag_z; break; case 7: mag_y = -mag_y; mag_z = -mag_z; break; case 8: tmp = mag_x; mag_x = -mag_y; mag_y = -tmp; mag_z = -mag_z; break; } input_report_abs(akm->input, ABS_X, mag_x); input_report_abs(akm->input, ABS_Y, mag_y); input_report_abs(akm->input, ABS_Z, mag_z); input_report_abs(akm->input, ABS_MISC, 3); exit: ret = AKECS_SetMode(akm, AKM_MODE_SNG_MEASURE); if (ret < 0) dev_warn(&s_akm->i2c->dev, "Failed to set mode\n"); schedule_delayed_work(&akm->dwork, (unsigned long)nsecs_to_jiffies64(akm->delay[MAG_DATA_FLAG])); } int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct akm09911_platform_data *pdata; Loading Loading @@ -1722,6 +1833,8 @@ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) "%s: request irq failed.", __func__); goto exit4; } } else if (s_akm->auto_report) { INIT_DELAYED_WORK(&s_akm->dwork, akm_dev_poll); } /***** misc *****/ Loading @@ -1743,6 +1856,9 @@ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) s_akm->cdev = sensors_cdev; s_akm->cdev.sensors_enable = akm_enable_set; s_akm->cdev.sensors_poll_delay = akm_poll_delay_set; s_akm->delay[MAG_DATA_FLAG] = sensors_cdev.delay_msec * 1000000; err = sensors_classdev_register(&client->dev, &s_akm->cdev); if (err) { Loading Loading
Documentation/devicetree/bindings/input/misc/akm09911.txt +5 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,10 @@ Required properties: 8: 1st pin is right down (from top view) - akm,gpio_rstn : The gpio pin to reset the sensor chip. Optional properites: - akm,auto-report : Enable auto-report mode. Example: akm@c { compatible = "ak,ak09911"; Loading @@ -33,5 +37,6 @@ Required properties: vio-supply = <&pm8110_l14>; akm,layout = <0x0>; akm,gpio_rstn = <&msmgpio 82 0x0>; akm,auto-report; };
drivers/input/misc/akm09911.c +120 −4 Original line number Diff line number Diff line Loading @@ -47,6 +47,8 @@ #define AKM09911_VIO_MIN_UV 1750000 #define AKM09911_VIO_MAX_UV 1950000 #define STATUS_ERROR(st) (((st)&0x19) != 0x01) struct akm_compass_data { struct i2c_client *i2c; struct input_dev *input; Loading @@ -56,6 +58,7 @@ struct akm_compass_data { struct pinctrl_state *pin_default; struct pinctrl_state *pin_sleep; struct sensors_classdev cdev; struct delayed_work dwork; wait_queue_head_t drdy_wq; wait_queue_head_t open_wq; Loading Loading @@ -86,6 +89,7 @@ struct akm_compass_data { int irq; int gpio_rstn; int power_enabled; int auto_report; struct regulator *vdd; struct regulator *vio; }; Loading Loading @@ -844,6 +848,18 @@ static int akm_enable_set(struct sensors_classdev *sensors_cdev, akm_compass_sysfs_update_status(akm); if (akm->auto_report) { if (enable) { AKECS_SetMode(akm, AKM_MODE_SNG_MEASURE); schedule_delayed_work(&akm->dwork, (unsigned long)nsecs_to_jiffies64( akm->delay[MAG_DATA_FLAG])); } else { cancel_delayed_work_sync(&akm->dwork); AKECS_SetMode(akm, AKM_MODE_POWERDOWN); } } return 0; } Loading Loading @@ -1556,6 +1572,11 @@ static int akm_compass_parse_dt(struct device *dev, s_akm->layout = temp_val; } if (of_property_read_bool(np, "akm,auto-report")) s_akm->auto_report = 1; else s_akm->auto_report = 0; s_akm->gpio_rstn = of_get_named_gpio_flags(dev->of_node, "akm,gpio_rstn", 0, NULL); Loading Loading @@ -1600,6 +1621,96 @@ static int akm_pinctrl_init(struct akm_compass_data *s_akm) return 0; } static void akm_dev_poll(struct work_struct *work) { struct akm_compass_data *akm; uint8_t dat_buf[AKM_SENSOR_DATA_SIZE];/* for GET_DATA */ int ret; int mag_x, mag_y, mag_z; int tmp; akm = container_of((struct delayed_work *)work, struct akm_compass_data, dwork); ret = AKECS_GetData_Poll(akm, dat_buf, AKM_SENSOR_DATA_SIZE); if (ret < 0) { dev_warn(&s_akm->i2c->dev, "Get data failed\n"); goto exit; } tmp = dat_buf[0] | dat_buf[7]; if (STATUS_ERROR(tmp)) { dev_warn(&s_akm->i2c->dev, "Status error(0x%x). Reset...\n", tmp); AKECS_Reset(akm, 0); goto exit; } tmp = (int)((int16_t)(dat_buf[2]<<8)+((int16_t)dat_buf[1])); tmp = tmp * akm->sense_conf[0] / 256 + tmp / 2; mag_x = tmp; tmp = (int)((int16_t)(dat_buf[4]<<8)+((int16_t)dat_buf[3])); tmp = tmp * akm->sense_conf[1] / 256 + tmp / 2; mag_y = tmp; tmp = (int)((int16_t)(dat_buf[6]<<8)+((int16_t)dat_buf[5])); tmp = tmp * akm->sense_conf[2] / 256 + tmp / 2; mag_z = tmp; switch (akm->layout) { case 0: case 1: /* Fall into the default direction */ break; case 2: tmp = mag_x; mag_x = mag_y; mag_y = -tmp; break; case 3: mag_x = -mag_x; mag_y = -mag_y; break; case 4: tmp = mag_x; mag_x = -mag_y; mag_y = tmp; break; case 5: mag_x = -mag_x; mag_z = -mag_z; break; case 6: tmp = mag_x; mag_x = mag_y; mag_y = tmp; mag_z = -mag_z; break; case 7: mag_y = -mag_y; mag_z = -mag_z; break; case 8: tmp = mag_x; mag_x = -mag_y; mag_y = -tmp; mag_z = -mag_z; break; } input_report_abs(akm->input, ABS_X, mag_x); input_report_abs(akm->input, ABS_Y, mag_y); input_report_abs(akm->input, ABS_Z, mag_z); input_report_abs(akm->input, ABS_MISC, 3); exit: ret = AKECS_SetMode(akm, AKM_MODE_SNG_MEASURE); if (ret < 0) dev_warn(&s_akm->i2c->dev, "Failed to set mode\n"); schedule_delayed_work(&akm->dwork, (unsigned long)nsecs_to_jiffies64(akm->delay[MAG_DATA_FLAG])); } int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct akm09911_platform_data *pdata; Loading Loading @@ -1722,6 +1833,8 @@ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) "%s: request irq failed.", __func__); goto exit4; } } else if (s_akm->auto_report) { INIT_DELAYED_WORK(&s_akm->dwork, akm_dev_poll); } /***** misc *****/ Loading @@ -1743,6 +1856,9 @@ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) s_akm->cdev = sensors_cdev; s_akm->cdev.sensors_enable = akm_enable_set; s_akm->cdev.sensors_poll_delay = akm_poll_delay_set; s_akm->delay[MAG_DATA_FLAG] = sensors_cdev.delay_msec * 1000000; err = sensors_classdev_register(&client->dev, &s_akm->cdev); if (err) { Loading