diff options
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/misc/bma2x2.c | 420 |
1 files changed, 299 insertions, 121 deletions
diff --git a/drivers/input/misc/bma2x2.c b/drivers/input/misc/bma2x2.c index 0c8b5c6dedda..3feec6fe8c38 100644 --- a/drivers/input/misc/bma2x2.c +++ b/drivers/input/misc/bma2x2.c @@ -30,6 +30,8 @@ #include <linux/delay.h> #include <asm/irq.h> #include <asm/mach/irq.h> +#include <linux/regulator/consumer.h> +#include <linux/of_gpio.h> #ifdef CONFIG_HAS_EARLYSUSPEND #include <linux/earlysuspend.h> @@ -1357,6 +1359,11 @@ static const struct interrupt_map_t int_map[] = { #endif/*End of CONFIG_SENSORS_BMI058*/ +/*BMA power supply VDD 1.62V-3.6V VIO 1.2-3.6V */ +#define BMA2x2_VDD_MIN_UV 2000000 +#define BMA2x2_VDD_MAX_UV 3400000 +#define BMA2x2_VIO_MIN_UV 1500000 +#define BMA2x2_VIO_MAX_UV 3400000 struct bma2x2_type_map_t { @@ -1381,19 +1388,6 @@ static const struct bma2x2_type_map_t sensor_type_map[] = { }; /*! -* Bst sensor common definition, -* please give parameters in BSP file. -*/ -struct bosch_sensor_specific { - char *name; - /* 0 to 7 */ - unsigned int place:3; - int irq; - int (*irq_gpio_cfg)(void); -}; - - -/*! * we use a typedef to hide the detail, * because this type might be changed */ @@ -1431,6 +1425,14 @@ struct bma2x2acc { s16 z; }; +struct bma2x2_platform_data { + int poll_interval; + int gpio_int1; + int gpio_int2; + u8 place; + bool use_int; +}; + struct bma2x2_data { struct i2c_client *bma2x2_client; atomic_t delay; @@ -1451,11 +1453,14 @@ struct bma2x2_data { struct mutex mode_mutex; struct delayed_work work; struct work_struct irq_work; + struct regulator *vdd; + struct regulator *vio; + bool power_enabled; #ifdef CONFIG_HAS_EARLYSUSPEND struct early_suspend early_suspend; #endif int IRQ; - struct bosch_sensor_specific *bst_pd; + struct bma2x2_platform_data *pdata; int ref_count; struct input_dev *dev_interrupt; @@ -1537,11 +1542,6 @@ static void bma2x2_remap_sensor_data(struct bma2x2acc *val, { struct bosch_sensor_data bsd; - if ((NULL == client_data->bst_pd) || - (BOSCH_SENSOR_PLACE_UNKNOWN - == client_data->bst_pd->place)) - return; - #ifdef CONFIG_SENSORS_BMI058 /*x,y need to be invesed becase of HW Register for BMI058*/ bsd.y = val->x; @@ -1554,7 +1554,7 @@ static void bma2x2_remap_sensor_data(struct bma2x2acc *val, #endif bst_remap_sensor_data_dft_tab(&bsd, - client_data->bst_pd->place); + client_data->pdata->place); val->x = bsd.x; val->y = bsd.y; @@ -5002,8 +5002,7 @@ static ssize_t bma2x2_place_show(struct device *dev, struct bma2x2_data *bma2x2 = i2c_get_clientdata(client); int place = BOSCH_SENSOR_PLACE_UNKNOWN; - if (NULL != bma2x2->bst_pd) - place = bma2x2->bst_pd->place; + place = bma2x2->pdata->place; return snprintf(buf, PAGE_SIZE, "%d\n", place); } @@ -5437,19 +5436,16 @@ static ssize_t bma2x2_fifo_data_sel_show(struct device *dev, #endif /*remaping fifo_dat_sel if define virtual place in BSP files*/ - if ((NULL != bma2x2->bst_pd) && - (BOSCH_SENSOR_PLACE_UNKNOWN != bma2x2->bst_pd->place)) { - place = bma2x2->bst_pd->place; - /* sensor with place 0 needs not to be remapped */ - if ((place > 0) && (place < MAX_AXIS_REMAP_TAB_SZ)) { - /* BMA2X2_FIFO_DAT_SEL_X: 1, Y:2, Z:3; - * but bst_axis_remap_tab_dft[i].src_x:0, y:1, z:2 - * so we need to +1*/ - if (BMA2X2_FIFO_DAT_SEL_X == data) - data = bst_axis_remap_tab_dft[place].src_x + 1; - else if (BMA2X2_FIFO_DAT_SEL_Y == data) - data = bst_axis_remap_tab_dft[place].src_y + 1; - } + place = bma2x2->pdata->place; + /* sensor with place 0 needs not to be remapped */ + if ((place > 0) && (place < MAX_AXIS_REMAP_TAB_SZ)) { + /* BMA2X2_FIFO_DAT_SEL_X: 1, Y:2, Z:3; + * but bst_axis_remap_tab_dft[i].src_x:0, y:1, z:2 + * so we need to +1*/ + if (BMA2X2_FIFO_DAT_SEL_X == data) + data = bst_axis_remap_tab_dft[place].src_x + 1; + else if (BMA2X2_FIFO_DAT_SEL_Y == data) + data = bst_axis_remap_tab_dft[place].src_y + 1; } return snprintf(buf, PAGE_SIZE, "%d\n", data); @@ -5525,27 +5521,24 @@ static ssize_t bma2x2_fifo_data_sel_store(struct device *dev, bma2x2->fifo_datasel = (unsigned char) data; /*remaping fifo_dat_sel if define virtual place*/ - if ((NULL != bma2x2->bst_pd) && - (BOSCH_SENSOR_PLACE_UNKNOWN != bma2x2->bst_pd->place)) { - place = bma2x2->bst_pd->place; - /* sensor with place 0 needs not to be remapped */ - if ((place > 0) && (place < MAX_AXIS_REMAP_TAB_SZ)) { - /*Need X Y axis revesal sensor place: P1, P3, P5, P7 */ - /* BMA2X2_FIFO_DAT_SEL_X: 1, Y:2, Z:3; - * but bst_axis_remap_tab_dft[i].src_x:0, y:1, z:2 - * so we need to +1*/ - if (BMA2X2_FIFO_DAT_SEL_X == data) - data = bst_axis_remap_tab_dft[place].src_x + 1; - else if (BMA2X2_FIFO_DAT_SEL_Y == data) - data = bst_axis_remap_tab_dft[place].src_y + 1; - } + place = bma2x2->pdata->place; + /* sensor with place 0 needs not to be remapped */ + if ((place > 0) && (place < MAX_AXIS_REMAP_TAB_SZ)) { + /*Need X Y axis revesal sensor place: P1, P3, P5, P7 */ + /* BMA2X2_FIFO_DAT_SEL_X: 1, Y:2, Z:3; + * but bst_axis_remap_tab_dft[i].src_x:0, y:1, z:2 + * so we need to +1*/ + if (BMA2X2_FIFO_DAT_SEL_X == data) + data = bst_axis_remap_tab_dft[place].src_x + 1; + else if (BMA2X2_FIFO_DAT_SEL_Y == data) + data = bst_axis_remap_tab_dft[place].src_y + 1; } #ifdef CONFIG_SENSORS_BMI058 /*Update BMI058 fifo_data_sel to the BMA2x2 common definition*/ - if (BMA2X2_FIFO_DAT_SEL_X == data) - data = BMI058_FIFO_DAT_SEL_X; - else if (BMA2X2_FIFO_DAT_SEL_Y == data) - data = BMI058_FIFO_DAT_SEL_Y; + if (BMA2X2_FIFO_DAT_SEL_X == data) + data = BMI058_FIFO_DAT_SEL_X; + else if (BMA2X2_FIFO_DAT_SEL_Y == data) + data = BMI058_FIFO_DAT_SEL_Y; #endif if (bma2x2_set_fifo_data_sel(bma2x2->bma2x2_client, @@ -5567,47 +5560,41 @@ static ssize_t bma2x2_fifo_data_sel_store(struct device *dev, static void bma2x2_single_axis_remaping(unsigned char fifo_datasel, unsigned char *remap_dir, struct bma2x2_data *client_data) { - if ((NULL == client_data->bst_pd) || - (BOSCH_SENSOR_PLACE_UNKNOWN - == client_data->bst_pd->place)) + signed char place = client_data->pdata->place; + /* sensor with place 0 needs not to be remapped */ + if ((place <= 0) || (place >= MAX_AXIS_REMAP_TAB_SZ)) return; - else { - signed char place = client_data->bst_pd->place; - /* sensor with place 0 needs not to be remapped */ - if ((place <= 0) || (place >= MAX_AXIS_REMAP_TAB_SZ)) - return; - - if (fifo_datasel < 1 || fifo_datasel > 3) - return; - else { - switch (fifo_datasel) { - /*P2, P3, P4, P5 X axis(andorid) need to reverse*/ - case BMA2X2_FIFO_DAT_SEL_X: - if (-1 == bst_axis_remap_tab_dft[place].sign_x) - *remap_dir = 1; - else - *remap_dir = 0; - break; - /*P1, P2, P5, P6 Y axis(andorid) need to reverse*/ - case BMA2X2_FIFO_DAT_SEL_Y: - if (-1 == bst_axis_remap_tab_dft[place].sign_y) - *remap_dir = 1; - else - *remap_dir = 0; - break; - case BMA2X2_FIFO_DAT_SEL_Z: - /*P4, P5, P6, P7 Z axis(andorid) need to reverse*/ - if (-1 == bst_axis_remap_tab_dft[place].sign_z) - *remap_dir = 1; - else - *remap_dir = 0; - break; - default: - break; - } - } + + if (fifo_datasel < 1 || fifo_datasel > 3) + return; + + switch (fifo_datasel) { + /*P2, P3, P4, P5 X axis(andorid) need to reverse*/ + case BMA2X2_FIFO_DAT_SEL_X: + if (-1 == bst_axis_remap_tab_dft[place].sign_x) + *remap_dir = 1; + else + *remap_dir = 0; + break; + /*P1, P2, P5, P6 Y axis(andorid) need to reverse*/ + case BMA2X2_FIFO_DAT_SEL_Y: + if (-1 == bst_axis_remap_tab_dft[place].sign_y) + *remap_dir = 1; + else + *remap_dir = 0; + break; + case BMA2X2_FIFO_DAT_SEL_Z: + /*P4, P5, P6, P7 Z axis(andorid) need to reverse*/ + if (-1 == bst_axis_remap_tab_dft[place].sign_z) + *remap_dir = 1; + else + *remap_dir = 0; + break; + default: + break; } + return; } @@ -6515,6 +6502,168 @@ static irqreturn_t bma2x2_irq_handler(int irq, void *handle) } #endif /* defined(BMA2X2_ENABLE_INT1)||defined(BMA2X2_ENABLE_INT2) */ +static int bma2x2_power_ctl(struct bma2x2_data *data, bool on) +{ + int ret = 0; + int err = 0; + + if (!on && data->power_enabled) { + ret = regulator_disable(data->vdd); + if (ret) { + dev_err(&data->bma2x2_client->dev, + "Regulator vdd disable failed ret=%d\n", ret); + return ret; + } + + ret = regulator_disable(data->vio); + if (ret) { + dev_err(&data->bma2x2_client->dev, + "Regulator vio disable failed ret=%d\n", ret); + err = regulator_enable(data->vdd); + return ret; + } + data->power_enabled = on; + } else if (on && !data->power_enabled) { + ret = regulator_enable(data->vdd); + if (ret) { + dev_err(&data->bma2x2_client->dev, + "Regulator vdd enable failed ret=%d\n", ret); + return ret; + } + + ret = regulator_enable(data->vio); + if (ret) { + dev_err(&data->bma2x2_client->dev, + "Regulator vio enable failed ret=%d\n", ret); + err = regulator_disable(data->vdd); + return ret; + } + data->power_enabled = on; + } else { + dev_info(&data->bma2x2_client->dev, + "Power on=%d. enabled=%d\n", + on, data->power_enabled); + } + + return ret; +} + +static int bma2x2_power_init(struct bma2x2_data *data) +{ + int ret; + + data->vdd = regulator_get(&data->bma2x2_client->dev, "vdd"); + if (IS_ERR(data->vdd)) { + ret = PTR_ERR(data->vdd); + dev_err(&data->bma2x2_client->dev, + "Regulator get failed vdd ret=%d\n", ret); + return ret; + } + + if (regulator_count_voltages(data->vdd) > 0) { + ret = regulator_set_voltage(data->vdd, + BMA2x2_VDD_MIN_UV, + BMA2x2_VDD_MAX_UV); + if (ret) { + dev_err(&data->bma2x2_client->dev, + "Regulator set failed vdd ret=%d\n", + ret); + goto reg_vdd_put; + } + } + + data->vio = regulator_get(&data->bma2x2_client->dev, "vio"); + if (IS_ERR(data->vio)) { + ret = PTR_ERR(data->vio); + dev_err(&data->bma2x2_client->dev, + "Regulator get failed vio ret=%d\n", ret); + goto reg_vdd_set; + } + + if (regulator_count_voltages(data->vio) > 0) { + ret = regulator_set_voltage(data->vio, + BMA2x2_VIO_MIN_UV, + BMA2x2_VIO_MAX_UV); + if (ret) { + dev_err(&data->bma2x2_client->dev, + "Regulator set failed vio ret=%d\n", ret); + goto reg_vio_put; + } + } + + 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, BMA2x2_VDD_MAX_UV); +reg_vdd_put: + regulator_put(data->vdd); + return ret; +} + +static int bma2x2_power_deinit(struct bma2x2_data *data) +{ + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, + 0, BMA2x2_VDD_MAX_UV); + + regulator_put(data->vdd); + + if (regulator_count_voltages(data->vio) > 0) + regulator_set_voltage(data->vio, + 0, BMA2x2_VIO_MAX_UV); + + regulator_put(data->vio); + + return 0; +} + +#ifdef CONFIG_OF +static int bma2x2_parse_dt(struct device *dev, + struct bma2x2_platform_data *pdata) +{ + struct device_node *np = dev->of_node; + u32 temp_val; + int rc; + + rc = of_property_read_u32(np, "bosch,init-interval", &temp_val); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read init-interval\n"); + return rc; + } else { + pdata->poll_interval = temp_val; + } + + rc = of_property_read_u32(np, "bosch,place", &temp_val); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read sensor place paramater\n"); + return rc; + } + if (temp_val > 7 || temp_val < 0) { + dev_err(dev, "Invalid place parameter, use default value 0\n"); + pdata->place = 0; + } else { + pdata->place = temp_val; + } + + pdata->use_int = of_property_read_bool(np, "bosch,use-interrupt"); + + pdata->gpio_int1 = of_get_named_gpio_flags(dev->of_node, + "bosch,gpio-int1", 0, NULL); + + pdata->gpio_int2 = of_get_named_gpio_flags(dev->of_node, + "bosch,gpio-int2", 0, NULL); + return 0; +} +#else +static int bma2x2_parse_dt(struct device *dev, + struct bma2x2_platform_data *pdata) +{ + return -EINVAL; +} +#endif static int bma2x2_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -6523,10 +6672,7 @@ static int bma2x2_probe(struct i2c_client *client, struct bma2x2_data *data; struct input_dev *dev; struct bst_dev *dev_acc; - -#if defined(BMA2X2_ENABLE_INT1) || defined(BMA2X2_ENABLE_INT2) - struct bosch_sensor_specific *pdata; -#endif + struct bma2x2_platform_data *pdata; struct input_dev *dev_interrupt; @@ -6540,6 +6686,46 @@ static int bma2x2_probe(struct i2c_client *client, err = -ENOMEM; goto exit; } + if (client->dev.of_node) { + pdata = devm_kzalloc(&client->dev, + sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&client->dev, "Failed to allcated memory\n"); + err = -ENOMEM; + goto kfree_exit; + } + err = bma2x2_parse_dt(&client->dev, pdata); + if (err) { + dev_err(&client->dev, "Failed to parse device tree\n"); + err = -EINVAL; + goto pdata_free_exit; + } + } else { + pdata = client->dev.platform_data; + dev_err(&client->dev, "use platform data\n"); + } + + if (!pdata) { + dev_err(&client->dev, "Cannot get device platform data\n"); + err = -EINVAL; + goto kfree_exit; + } + data->pdata = pdata; + i2c_set_clientdata(client, data); + data->bma2x2_client = client; + + err = bma2x2_power_init(data); + if (err) { + dev_err(&client->dev, "Failed to get sensor regulators\n"); + err = -EINVAL; + goto free_i2c_clientdata_exit; + } + err = bma2x2_power_ctl(data, true); + if (err) { + dev_err(&client->dev, "Failed to enable sensor power\n"); + err = -EINVAL; + goto deinit_power_exit; + } /* do soft reset */ RESET_DELAY(); @@ -6547,17 +6733,15 @@ static int bma2x2_probe(struct i2c_client *client, dev_err(&client->dev, "i2c bus write error, pls check HW connection\n"); err = -EINVAL; - goto kfree_exit; + goto disable_power_exit; } RESET_DELAY(); /* read and check chip id */ if (bma2x2_check_chip_id(client, data) < 0) { err = -EINVAL; - goto kfree_exit; + goto disable_power_exit; } - i2c_set_clientdata(client, data); - data->bma2x2_client = client; mutex_init(&data->value_mutex); mutex_init(&data->mode_mutex); mutex_init(&data->enable_mutex); @@ -6771,19 +6955,6 @@ static int bma2x2_probe(struct i2c_client *client, if (err < 0) goto bst_free_exit; - if (NULL != client->dev.platform_data) { - data->bst_pd = kzalloc(sizeof(*data->bst_pd), - GFP_KERNEL); - - if (NULL != data->bst_pd) { - memcpy(data->bst_pd, client->dev.platform_data, - sizeof(*data->bst_pd)); - dev_notice(&client->dev, - "%s sensor driver set place: p%d", - data->bst_pd->name, data->bst_pd->place); - } - } - #ifdef CONFIG_HAS_EARLYSUSPEND data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; data->early_suspend.suspend = bma2x2_early_suspend; @@ -6841,11 +7012,17 @@ err_register_input_device_interrupt: err_register_input_device: input_free_device(dev); +disable_power_exit: + bma2x2_power_ctl(data, false); +deinit_power_exit: + bma2x2_power_deinit(data); +free_i2c_clientdata_exit: + i2c_set_clientdata(client, NULL); +pdata_free_exit: + if (pdata && (client->dev.of_node)) + devm_kfree(&client->dev, pdata); + data->pdata = NULL; kfree_exit: - if ((NULL != data) && (NULL != data->bst_pd)) { - kfree(data->bst_pd); - data->bst_pd = NULL; - } kfree(data); exit: return err; @@ -6895,11 +7072,6 @@ static int bma2x2_remove(struct i2c_client *client) sysfs_remove_group(&data->input->dev.kobj, &bma2x2_attribute_group); input_unregister_device(data->input); - if ((NULL != data) && (NULL != data->bst_pd)) { - kfree(data->bst_pd); - data->bst_pd = NULL; - } - kfree(data); return 0; @@ -6962,10 +7134,16 @@ static const struct i2c_device_id bma2x2_id[] = { MODULE_DEVICE_TABLE(i2c, bma2x2_id); +static const struct of_device_id bma2x2_of_match[] = { + { .compatible = "bosch,bma2x2", }, + { }, +}; + static struct i2c_driver bma2x2_driver = { .driver = { .owner = THIS_MODULE, .name = SENSOR_NAME, + .of_match_table = bma2x2_of_match, }, .suspend = bma2x2_suspend, .resume = bma2x2_resume, |