Loading Documentation/devicetree/bindings/input/misc/akm09911.txt 0 → 100644 +31 −0 Original line number Diff line number Diff line AKM AK09911 3-axis electronic compass driver Required properties: - compatible : Should be "ak,ak09911" or "akm,akm09911". - reg : i2c address of the device. - vdd-supply : Analog power supply needed to power up the device. - vio-supply : Digital IO power supply needed for IO and I2C. - akm,layout : The layout of the ecompass sensor chip. There are 8 patterns of layout described as below: 0: Indicate the invalid pattern, The userspace will decide the pattern. 1: 1st pin is right down 2: 1st pin is left down 3: 1st pin is left top 4: 1st pin is right top 5: 1st pin is left down (from top view) 6: 1st pin is left top (from top view) 7: 1st pin is right top (from top view) 8: 1st pin is right down (from top view) - akm,gpio_rstn : The gpio pin to reset the sensor chip. Example: akm@c { compatible = "ak,ak09911"; reg = <0x0c>; vdd-supply = <&pm8110_l19>; vio-supply = <&pm8110_l14>; akm,layout = <0x0>; akm,gpio_rstn = <&msmgpio 82 0x0>; }; drivers/input/misc/akm09911.c +169 −15 Original line number Diff line number Diff line Loading @@ -31,6 +31,9 @@ #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/workqueue.h> #include <linux/regulator/consumer.h> #include <linux/of_gpio.h> #include <linux/sensors.h> #define AKM_DEBUG_IF 0 #define AKM_HAS_RESET 1 Loading @@ -38,6 +41,12 @@ #define AKM_DRDY_TIMEOUT_MS 100 #define AKM_BASE_NUM 10 /* POWER SUPPLY VOLTAGE RANGE */ #define AKM09911_VDD_MIN_UV 2000000 #define AKM09911_VDD_MAX_UV 3300000 #define AKM09911_VIO_MIN_UV 1750000 #define AKM09911_VIO_MAX_UV 1950000 struct akm_compass_data { struct i2c_client *i2c; struct input_dev *input; Loading Loading @@ -72,12 +81,13 @@ struct akm_compass_data { char layout; int irq; int gpio_rstn; int power_enabled; struct regulator *vdd; struct regulator *vio; }; static struct akm_compass_data *s_akm; /***** I2C I/O function ***********************************************/ static int akm_i2c_rxdata( struct i2c_client *i2c, Loading Loading @@ -324,10 +334,10 @@ static void AKECS_SetYPR( } /* Report magnetic vector information */ if (ready & MAG_DATA_READY) { input_report_abs(akm->input, ABS_RY, rbuf[5]); input_report_abs(akm->input, ABS_RZ, rbuf[6]); input_report_abs(akm->input, ABS_THROTTLE, rbuf[7]); input_report_abs(akm->input, ABS_RUDDER, rbuf[8]); input_report_abs(akm->input, ABS_X, rbuf[5]); input_report_abs(akm->input, ABS_Y, rbuf[6]); input_report_abs(akm->input, ABS_Z, rbuf[7]); input_report_abs(akm->input, ABS_MISC, rbuf[8]); } /* Report fusion sensor information */ if (ready & FUSION_DATA_READY) { Loading Loading @@ -1391,6 +1401,129 @@ static int akm09911_i2c_check_device( return err; } static int akm_compass_power_set(struct akm_compass_data *data, bool on) { int rc; if (!on) { if (regulator_count_voltages(data->vdd) > 0) regulator_set_voltage(data->vdd, 0, AKM09911_VDD_MAX_UV); regulator_put(data->vdd); regulator_disable(data->vdd); if (regulator_count_voltages(data->vio) > 0) regulator_set_voltage(data->vio, 0, AKM09911_VIO_MAX_UV); regulator_put(data->vio); regulator_disable(data->vio); } else { data->vdd = regulator_get(&data->i2c->dev, "vdd"); if (IS_ERR(data->vdd)) { rc = PTR_ERR(data->vdd); dev_err(&data->i2c->dev, "Regulator get failed vdd rc=%d\n", rc); return rc; } if (regulator_count_voltages(data->vdd) > 0) { rc = regulator_set_voltage(data->vdd, AKM09911_VDD_MIN_UV, AKM09911_VDD_MAX_UV); if (rc) { dev_err(&data->i2c->dev, "Regulator set failed vdd rc=%d\n", rc); goto reg_vdd_put; } } rc = regulator_enable(data->vdd); if (rc) { dev_err(&data->i2c->dev, "Regulator enable vdd failed rc=%d\n", rc); goto reg_vdd_put; } data->vio = regulator_get(&data->i2c->dev, "vio"); if (IS_ERR(data->vio)) { rc = PTR_ERR(data->vio); dev_err(&data->i2c->dev, "Regulator get failed vio rc=%d\n", rc); goto reg_vdd_set; } if (regulator_count_voltages(data->vio) > 0) { rc = regulator_set_voltage(data->vio, AKM09911_VIO_MIN_UV, AKM09911_VIO_MAX_UV); if (rc) { dev_err(&data->i2c->dev, "Regulator set failed vio rc=%d\n", rc); goto reg_vio_put; } } rc = regulator_enable(data->vio); if (rc) { dev_err(&data->i2c->dev, "Regulator enable vio failed rc=%d\n", rc); goto reg_vio_put; } } /* * The max time for the power supply rise time is 50ms. * Use 80ms to make sure it meets the requirements. */ msleep(80); return 0; reg_vio_put: regulator_put(data->vio); reg_vdd_set: if (regulator_count_voltages(data->vdd) > 0) regulator_set_voltage(data->vdd, 0, AKM09911_VDD_MAX_UV); reg_vdd_put: regulator_put(data->vdd); return rc; } #ifdef CONFIG_OF static int akm_compass_parse_dt(struct device *dev, struct akm_compass_data *pdata) { struct device_node *np = dev->of_node; u32 temp_val; int rc; rc = of_property_read_u32(np, "akm,layout", &temp_val); if (rc && (rc != -EINVAL)) { dev_err(dev, "Unable to read akm,layout\n"); return rc; } else { s_akm->layout = temp_val; } s_akm->gpio_rstn = of_get_named_gpio_flags(dev->of_node, "akm,gpio_rstn", 0, NULL); if (!gpio_is_valid(s_akm->gpio_rstn)) { dev_err(dev, "gpio reset pin %d is invalid.\n", s_akm->gpio_rstn); return -EINVAL; } return 0; } #else static int akm_compass_parse_dt(struct device *dev, struct akm_compass_data *pdata) { return -EINVAL; } #endif /* !CONFIG_OF */ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct akm09911_platform_data *pdata; Loading Loading @@ -1437,18 +1570,27 @@ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) for (i = 0; i < AKM_NUM_SENSORS; i++) s_akm->delay[i] = -1; /***** Set platform information *****/ if (client->dev.of_node) { err = akm_compass_parse_dt(&client->dev, s_akm); if (err) { dev_err(&client->dev, "Unable to parse platfrom data err=%d\n", err); return err; } } else { if (client->dev.platform_data) { /* Copy platform data to local. */ pdata = client->dev.platform_data; if (pdata) { /* Platform data is available. copy its value to local. */ s_akm->layout = pdata->layout; s_akm->gpio_rstn = pdata->gpio_RSTN; } else { /* Platform data is not available. Layout and information should be set by each application. */ dev_dbg(&client->dev, "%s: No platform data.", __func__); s_akm->layout = 0; s_akm->gpio_rstn = 0; dev_warn(&client->dev, "%s: No platform data.", __func__); } } /***** I2C initialization *****/ Loading @@ -1456,6 +1598,9 @@ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) /* set client data */ i2c_set_clientdata(client, s_akm); /* check connection */ err = akm_compass_power_set(s_akm, 1); if (err < 0) goto exit2; err = akm09911_i2c_check_device(client); if (err < 0) goto exit2; Loading Loading @@ -1528,6 +1673,7 @@ static int akm_compass_remove(struct i2c_client *client) { struct akm_compass_data *akm = i2c_get_clientdata(client); akm_compass_power_set(akm, 0); remove_sysfs_interfaces(akm); if (misc_deregister(&akm_compass_dev) < 0) dev_err(&client->dev, "misc deregister failed."); Loading @@ -1549,12 +1695,20 @@ static const struct dev_pm_ops akm_compass_pm_ops = { .resume = akm_compass_resume, }; static struct of_device_id akm09911_match_table[] = { { .compatible = "ak,ak09911", }, { .compatible = "akm,akm09911", }, { }, }; static struct i2c_driver akm_compass_driver = { .probe = akm_compass_probe, .remove = akm_compass_remove, .id_table = akm_compass_id, .driver = { .name = AKM_I2C_NAME, .owner = THIS_MODULE, .of_match_table = akm09911_match_table, .pm = &akm_compass_pm_ops, }, }; Loading Loading
Documentation/devicetree/bindings/input/misc/akm09911.txt 0 → 100644 +31 −0 Original line number Diff line number Diff line AKM AK09911 3-axis electronic compass driver Required properties: - compatible : Should be "ak,ak09911" or "akm,akm09911". - reg : i2c address of the device. - vdd-supply : Analog power supply needed to power up the device. - vio-supply : Digital IO power supply needed for IO and I2C. - akm,layout : The layout of the ecompass sensor chip. There are 8 patterns of layout described as below: 0: Indicate the invalid pattern, The userspace will decide the pattern. 1: 1st pin is right down 2: 1st pin is left down 3: 1st pin is left top 4: 1st pin is right top 5: 1st pin is left down (from top view) 6: 1st pin is left top (from top view) 7: 1st pin is right top (from top view) 8: 1st pin is right down (from top view) - akm,gpio_rstn : The gpio pin to reset the sensor chip. Example: akm@c { compatible = "ak,ak09911"; reg = <0x0c>; vdd-supply = <&pm8110_l19>; vio-supply = <&pm8110_l14>; akm,layout = <0x0>; akm,gpio_rstn = <&msmgpio 82 0x0>; };
drivers/input/misc/akm09911.c +169 −15 Original line number Diff line number Diff line Loading @@ -31,6 +31,9 @@ #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/workqueue.h> #include <linux/regulator/consumer.h> #include <linux/of_gpio.h> #include <linux/sensors.h> #define AKM_DEBUG_IF 0 #define AKM_HAS_RESET 1 Loading @@ -38,6 +41,12 @@ #define AKM_DRDY_TIMEOUT_MS 100 #define AKM_BASE_NUM 10 /* POWER SUPPLY VOLTAGE RANGE */ #define AKM09911_VDD_MIN_UV 2000000 #define AKM09911_VDD_MAX_UV 3300000 #define AKM09911_VIO_MIN_UV 1750000 #define AKM09911_VIO_MAX_UV 1950000 struct akm_compass_data { struct i2c_client *i2c; struct input_dev *input; Loading Loading @@ -72,12 +81,13 @@ struct akm_compass_data { char layout; int irq; int gpio_rstn; int power_enabled; struct regulator *vdd; struct regulator *vio; }; static struct akm_compass_data *s_akm; /***** I2C I/O function ***********************************************/ static int akm_i2c_rxdata( struct i2c_client *i2c, Loading Loading @@ -324,10 +334,10 @@ static void AKECS_SetYPR( } /* Report magnetic vector information */ if (ready & MAG_DATA_READY) { input_report_abs(akm->input, ABS_RY, rbuf[5]); input_report_abs(akm->input, ABS_RZ, rbuf[6]); input_report_abs(akm->input, ABS_THROTTLE, rbuf[7]); input_report_abs(akm->input, ABS_RUDDER, rbuf[8]); input_report_abs(akm->input, ABS_X, rbuf[5]); input_report_abs(akm->input, ABS_Y, rbuf[6]); input_report_abs(akm->input, ABS_Z, rbuf[7]); input_report_abs(akm->input, ABS_MISC, rbuf[8]); } /* Report fusion sensor information */ if (ready & FUSION_DATA_READY) { Loading Loading @@ -1391,6 +1401,129 @@ static int akm09911_i2c_check_device( return err; } static int akm_compass_power_set(struct akm_compass_data *data, bool on) { int rc; if (!on) { if (regulator_count_voltages(data->vdd) > 0) regulator_set_voltage(data->vdd, 0, AKM09911_VDD_MAX_UV); regulator_put(data->vdd); regulator_disable(data->vdd); if (regulator_count_voltages(data->vio) > 0) regulator_set_voltage(data->vio, 0, AKM09911_VIO_MAX_UV); regulator_put(data->vio); regulator_disable(data->vio); } else { data->vdd = regulator_get(&data->i2c->dev, "vdd"); if (IS_ERR(data->vdd)) { rc = PTR_ERR(data->vdd); dev_err(&data->i2c->dev, "Regulator get failed vdd rc=%d\n", rc); return rc; } if (regulator_count_voltages(data->vdd) > 0) { rc = regulator_set_voltage(data->vdd, AKM09911_VDD_MIN_UV, AKM09911_VDD_MAX_UV); if (rc) { dev_err(&data->i2c->dev, "Regulator set failed vdd rc=%d\n", rc); goto reg_vdd_put; } } rc = regulator_enable(data->vdd); if (rc) { dev_err(&data->i2c->dev, "Regulator enable vdd failed rc=%d\n", rc); goto reg_vdd_put; } data->vio = regulator_get(&data->i2c->dev, "vio"); if (IS_ERR(data->vio)) { rc = PTR_ERR(data->vio); dev_err(&data->i2c->dev, "Regulator get failed vio rc=%d\n", rc); goto reg_vdd_set; } if (regulator_count_voltages(data->vio) > 0) { rc = regulator_set_voltage(data->vio, AKM09911_VIO_MIN_UV, AKM09911_VIO_MAX_UV); if (rc) { dev_err(&data->i2c->dev, "Regulator set failed vio rc=%d\n", rc); goto reg_vio_put; } } rc = regulator_enable(data->vio); if (rc) { dev_err(&data->i2c->dev, "Regulator enable vio failed rc=%d\n", rc); goto reg_vio_put; } } /* * The max time for the power supply rise time is 50ms. * Use 80ms to make sure it meets the requirements. */ msleep(80); return 0; reg_vio_put: regulator_put(data->vio); reg_vdd_set: if (regulator_count_voltages(data->vdd) > 0) regulator_set_voltage(data->vdd, 0, AKM09911_VDD_MAX_UV); reg_vdd_put: regulator_put(data->vdd); return rc; } #ifdef CONFIG_OF static int akm_compass_parse_dt(struct device *dev, struct akm_compass_data *pdata) { struct device_node *np = dev->of_node; u32 temp_val; int rc; rc = of_property_read_u32(np, "akm,layout", &temp_val); if (rc && (rc != -EINVAL)) { dev_err(dev, "Unable to read akm,layout\n"); return rc; } else { s_akm->layout = temp_val; } s_akm->gpio_rstn = of_get_named_gpio_flags(dev->of_node, "akm,gpio_rstn", 0, NULL); if (!gpio_is_valid(s_akm->gpio_rstn)) { dev_err(dev, "gpio reset pin %d is invalid.\n", s_akm->gpio_rstn); return -EINVAL; } return 0; } #else static int akm_compass_parse_dt(struct device *dev, struct akm_compass_data *pdata) { return -EINVAL; } #endif /* !CONFIG_OF */ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct akm09911_platform_data *pdata; Loading Loading @@ -1437,18 +1570,27 @@ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) for (i = 0; i < AKM_NUM_SENSORS; i++) s_akm->delay[i] = -1; /***** Set platform information *****/ if (client->dev.of_node) { err = akm_compass_parse_dt(&client->dev, s_akm); if (err) { dev_err(&client->dev, "Unable to parse platfrom data err=%d\n", err); return err; } } else { if (client->dev.platform_data) { /* Copy platform data to local. */ pdata = client->dev.platform_data; if (pdata) { /* Platform data is available. copy its value to local. */ s_akm->layout = pdata->layout; s_akm->gpio_rstn = pdata->gpio_RSTN; } else { /* Platform data is not available. Layout and information should be set by each application. */ dev_dbg(&client->dev, "%s: No platform data.", __func__); s_akm->layout = 0; s_akm->gpio_rstn = 0; dev_warn(&client->dev, "%s: No platform data.", __func__); } } /***** I2C initialization *****/ Loading @@ -1456,6 +1598,9 @@ int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) /* set client data */ i2c_set_clientdata(client, s_akm); /* check connection */ err = akm_compass_power_set(s_akm, 1); if (err < 0) goto exit2; err = akm09911_i2c_check_device(client); if (err < 0) goto exit2; Loading Loading @@ -1528,6 +1673,7 @@ static int akm_compass_remove(struct i2c_client *client) { struct akm_compass_data *akm = i2c_get_clientdata(client); akm_compass_power_set(akm, 0); remove_sysfs_interfaces(akm); if (misc_deregister(&akm_compass_dev) < 0) dev_err(&client->dev, "misc deregister failed."); Loading @@ -1549,12 +1695,20 @@ static const struct dev_pm_ops akm_compass_pm_ops = { .resume = akm_compass_resume, }; static struct of_device_id akm09911_match_table[] = { { .compatible = "ak,ak09911", }, { .compatible = "akm,akm09911", }, { }, }; static struct i2c_driver akm_compass_driver = { .probe = akm_compass_probe, .remove = akm_compass_remove, .id_table = akm_compass_id, .driver = { .name = AKM_I2C_NAME, .owner = THIS_MODULE, .of_match_table = akm09911_match_table, .pm = &akm_compass_pm_ops, }, }; Loading