diff options
Diffstat (limited to 'drivers/iio/accel/mma8452.c')
| -rw-r--r-- | drivers/iio/accel/mma8452.c | 194 |
1 files changed, 109 insertions, 85 deletions
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 64b82b4503ad..15172ba2972c 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -19,6 +19,8 @@ */ #include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/property.h> #include <linux/i2c.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -28,10 +30,9 @@ #include <linux/iio/triggered_buffer.h> #include <linux/iio/events.h> #include <linux/delay.h> -#include <linux/of_device.h> -#include <linux/of_irq.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/types.h> #define MMA8452_STATUS 0x00 #define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) @@ -104,6 +105,7 @@ struct mma8452_data { struct i2c_client *client; struct mutex lock; + struct iio_mount_matrix orientation; u8 ctrl_reg1; u8 data_cfg; const struct mma_chip_info *chip_info; @@ -114,7 +116,7 @@ struct mma8452_data { /* Ensure correct alignment of time stamp when present */ struct { __be16 channels[3]; - s64 ts __aligned(8); + aligned_s64 ts; } buffer; }; @@ -165,6 +167,7 @@ static const struct mma8452_event_regs trans_ev_regs = { /** * struct mma_chip_info - chip specific data + * @name: part number of device reported via 'name' attr * @chip_id: WHO_AM_I register's value * @channels: struct iio_chan_spec matching the device's * capabilities @@ -176,6 +179,7 @@ static const struct mma8452_event_regs trans_ev_regs = { * @enabled_events: event flags enabled and handled by this driver */ struct mma_chip_info { + const char *name; u8 chip_id; const struct iio_chan_spec *channels; int num_channels; @@ -220,13 +224,10 @@ static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on) #ifdef CONFIG_PM int ret; - if (on) { + if (on) ret = pm_runtime_resume_and_get(&client->dev); - } else { - pm_runtime_mark_last_busy(&client->dev); + else ret = pm_runtime_put_autosuspend(&client->dev); - } - if (ret < 0) { dev_err(&client->dev, "failed to change power state to %d\n", on); @@ -379,8 +380,8 @@ static ssize_t mma8452_show_scale_avail(struct device *dev, struct device_attribute *attr, char *buf) { - struct mma8452_data *data = iio_priv(i2c_get_clientdata( - to_i2c_client(dev))); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct mma8452_data *data = iio_priv(indio_dev); return mma8452_show_int_plus_micros(buf, data->chip_info->mma_scales, ARRAY_SIZE(data->chip_info->mma_scales)); @@ -493,14 +494,13 @@ static int mma8452_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; mutex_lock(&data->lock); ret = mma8452_read(data, buffer); mutex_unlock(&data->lock); - iio_device_release_direct_mode(indio_dev); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; @@ -703,55 +703,45 @@ static int mma8452_set_hp_filter_frequency(struct mma8452_data *data, return mma8452_change_config(data, MMA8452_HP_FILTER_CUTOFF, reg); } -static int mma8452_write_raw(struct iio_dev *indio_dev, +static int __mma8452_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { struct mma8452_data *data = iio_priv(indio_dev); - int i, ret; - - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + int i, j, ret; switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: i = mma8452_get_samp_freq_index(data, val, val2); - if (i < 0) { - ret = i; - break; - } + if (i < 0) + return i; + data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK; data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT; data->sleep_val = mma8452_calculate_sleep(data); - ret = mma8452_change_config(data, MMA8452_CTRL_REG1, - data->ctrl_reg1); - break; + return mma8452_change_config(data, MMA8452_CTRL_REG1, + data->ctrl_reg1); + case IIO_CHAN_INFO_SCALE: i = mma8452_get_scale_index(data, val, val2); - if (i < 0) { - ret = i; - break; - } + if (i < 0) + return i; data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK; data->data_cfg |= i; - ret = mma8452_change_config(data, MMA8452_DATA_CFG, - data->data_cfg); - break; + return mma8452_change_config(data, MMA8452_DATA_CFG, + data->data_cfg); + case IIO_CHAN_INFO_CALIBBIAS: - if (val < -128 || val > 127) { - ret = -EINVAL; - break; - } + if (val < -128 || val > 127) + return -EINVAL; - ret = mma8452_change_config(data, - MMA8452_OFF_X + chan->scan_index, - val); - break; + return mma8452_change_config(data, + MMA8452_OFF_X + chan->scan_index, + val); case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: if (val == 0 && val2 == 0) { @@ -760,29 +750,38 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, data->data_cfg |= MMA8452_DATA_CFG_HPF_MASK; ret = mma8452_set_hp_filter_frequency(data, val, val2); if (ret < 0) - break; + return ret; } - ret = mma8452_change_config(data, MMA8452_DATA_CFG, + return mma8452_change_config(data, MMA8452_DATA_CFG, data->data_cfg); - break; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - ret = mma8452_get_odr_index(data); + j = mma8452_get_odr_index(data); for (i = 0; i < ARRAY_SIZE(mma8452_os_ratio); i++) { - if (mma8452_os_ratio[i][ret] == val) { - ret = mma8452_set_power_mode(data, i); - break; - } + if (mma8452_os_ratio[i][j] == val) + return mma8452_set_power_mode(data, i); } - break; + + return -EINVAL; + default: - ret = -EINVAL; - break; + return -EINVAL; } +} + +static int mma8452_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + int ret; + + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; - iio_device_release_direct_mode(indio_dev); + ret = __mma8452_write_raw(indio_dev, chan, val, val2, mask); + iio_device_release_direct(indio_dev); return ret; } @@ -970,7 +969,7 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, - int state) + bool state) { struct mma8452_data *data = iio_priv(indio_dev); int val, ret; @@ -1064,7 +1063,7 @@ static irqreturn_t mma8452_interrupt(int irq, void *p) return IRQ_NONE; if (src & MMA8452_INT_DRDY) { - iio_trigger_poll_chained(indio_dev->trig); + iio_trigger_poll_nested(indio_dev->trig); ret = IRQ_HANDLED; } @@ -1101,8 +1100,9 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p) if (ret < 0) goto done; - iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, - iio_get_time_ns(indio_dev)); + iio_push_to_buffers_with_ts(indio_dev, &data->buffer, + sizeof(data->buffer), + iio_get_time_ns(indio_dev)); done: iio_trigger_notify_done(indio_dev->trig); @@ -1189,6 +1189,20 @@ static const struct attribute_group mma8452_event_attribute_group = { .attrs = mma8452_event_attributes, }; +static const struct iio_mount_matrix * +mma8452_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct mma8452_data *data = iio_priv(indio_dev); + + return &data->orientation; +} + +static const struct iio_chan_spec_ext_info mma8452_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, mma8452_get_mount_matrix), + { } +}; + #define MMA8452_FREEFALL_CHANNEL(modifier) { \ .type = IIO_ACCEL, \ .modified = 1, \ @@ -1227,6 +1241,7 @@ static const struct attribute_group mma8452_event_attribute_group = { }, \ .event_spec = mma8452_transient_event, \ .num_event_specs = ARRAY_SIZE(mma8452_transient_event), \ + .ext_info = mma8452_ext_info, \ } #define MMA8652_CHANNEL(axis, idx, bits) { \ @@ -1248,6 +1263,7 @@ static const struct attribute_group mma8452_event_attribute_group = { }, \ .event_spec = mma8452_motion_event, \ .num_event_specs = ARRAY_SIZE(mma8452_motion_event), \ + .ext_info = mma8452_ext_info, \ } static const struct iio_chan_spec mma8451_channels[] = { @@ -1301,6 +1317,7 @@ enum { static const struct mma_chip_info mma_chip_info_table[] = { [mma8451] = { + .name = "mma8451", .chip_id = MMA8451_DEVICE_ID, .channels = mma8451_channels, .num_channels = ARRAY_SIZE(mma8451_channels), @@ -1325,6 +1342,7 @@ static const struct mma_chip_info mma_chip_info_table[] = { MMA8452_INT_FF_MT, }, [mma8452] = { + .name = "mma8452", .chip_id = MMA8452_DEVICE_ID, .channels = mma8452_channels, .num_channels = ARRAY_SIZE(mma8452_channels), @@ -1341,6 +1359,7 @@ static const struct mma_chip_info mma_chip_info_table[] = { MMA8452_INT_FF_MT, }, [mma8453] = { + .name = "mma8453", .chip_id = MMA8453_DEVICE_ID, .channels = mma8453_channels, .num_channels = ARRAY_SIZE(mma8453_channels), @@ -1357,6 +1376,7 @@ static const struct mma_chip_info mma_chip_info_table[] = { MMA8452_INT_FF_MT, }, [mma8652] = { + .name = "mma8652", .chip_id = MMA8652_DEVICE_ID, .channels = mma8652_channels, .num_channels = ARRAY_SIZE(mma8652_channels), @@ -1366,6 +1386,7 @@ static const struct mma_chip_info mma_chip_info_table[] = { .enabled_events = MMA8452_INT_FF_MT, }, [mma8653] = { + .name = "mma8653", .chip_id = MMA8653_DEVICE_ID, .channels = mma8653_channels, .num_channels = ARRAY_SIZE(mma8653_channels), @@ -1380,6 +1401,7 @@ static const struct mma_chip_info mma_chip_info_table[] = { .enabled_events = MMA8452_INT_FF_MT, }, [fxls8471] = { + .name = "fxls8471", .chip_id = FXLS8471_DEVICE_ID, .channels = mma8451_channels, .num_channels = ARRAY_SIZE(mma8451_channels), @@ -1486,10 +1508,14 @@ static int mma8452_reset(struct i2c_client *client) int i; int ret; - ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG2, + /* + * Find on fxls8471, after config reset bit, it reset immediately, + * and will not give ACK, so here do not check the return value. + * The following code will read the reset register, and check whether + * this reset works. + */ + i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG2, MMA8452_CTRL_REG2_RST); - if (ret < 0) - return ret; for (i = 0; i < 10; i++) { usleep_range(100, 200); @@ -1506,29 +1532,21 @@ static int mma8452_reset(struct i2c_client *client) } static const struct of_device_id mma8452_dt_ids[] = { + { .compatible = "fsl,fxls8471", .data = &mma_chip_info_table[fxls8471] }, { .compatible = "fsl,mma8451", .data = &mma_chip_info_table[mma8451] }, { .compatible = "fsl,mma8452", .data = &mma_chip_info_table[mma8452] }, { .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] }, { .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] }, { .compatible = "fsl,mma8653", .data = &mma_chip_info_table[mma8653] }, - { .compatible = "fsl,fxls8471", .data = &mma_chip_info_table[fxls8471] }, { } }; MODULE_DEVICE_TABLE(of, mma8452_dt_ids); -static int mma8452_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int mma8452_probe(struct i2c_client *client) { struct mma8452_data *data; struct iio_dev *indio_dev; int ret; - const struct of_device_id *match; - - match = of_match_device(mma8452_dt_ids, &client->dev); - if (!match) { - dev_err(&client->dev, "unknown device model\n"); - return -ENODEV; - } indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -1537,7 +1555,15 @@ static int mma8452_probe(struct i2c_client *client, data = iio_priv(indio_dev); data->client = client; mutex_init(&data->lock); - data->chip_info = match->data; + + data->chip_info = i2c_get_match_data(client); + if (!data->chip_info) + return dev_err_probe(&client->dev, -ENODEV, + "unknown device model\n"); + + ret = iio_read_mount_matrix(&client->dev, &data->orientation); + if (ret) + return ret; data->vdd_reg = devm_regulator_get(&client->dev, "vdd"); if (IS_ERR(data->vdd_reg)) @@ -1581,11 +1607,11 @@ static int mma8452_probe(struct i2c_client *client, } dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n", - match->compatible, data->chip_info->chip_id); + data->chip_info->name, data->chip_info->chip_id); i2c_set_clientdata(client, indio_dev); indio_dev->info = &mma8452_info; - indio_dev->name = id->name; + indio_dev->name = data->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = data->chip_info->channels; indio_dev->num_channels = data->chip_info->num_channels; @@ -1613,7 +1639,7 @@ static int mma8452_probe(struct i2c_client *client, if (client->irq) { int irq2; - irq2 = of_irq_get_byname(client->dev.of_node, "INT2"); + irq2 = fwnode_irq_get_byname(dev_fwnode(&client->dev), "INT2"); if (irq2 == client->irq) { dev_dbg(&client->dev, "using interrupt line INT2\n"); @@ -1700,7 +1726,7 @@ disable_regulator_vdd: return ret; } -static int mma8452_remove(struct i2c_client *client) +static void mma8452_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct mma8452_data *data = iio_priv(indio_dev); @@ -1716,8 +1742,6 @@ static int mma8452_remove(struct i2c_client *client) regulator_disable(data->vddio_reg); regulator_disable(data->vdd_reg); - - return 0; } #ifdef CONFIG_PM @@ -1797,12 +1821,12 @@ static const struct dev_pm_ops mma8452_pm_ops = { }; static const struct i2c_device_id mma8452_id[] = { - { "mma8451", mma8451 }, - { "mma8452", mma8452 }, - { "mma8453", mma8453 }, - { "mma8652", mma8652 }, - { "mma8653", mma8653 }, - { "fxls8471", fxls8471 }, + { "fxls8471", (kernel_ulong_t)&mma_chip_info_table[fxls8471] }, + { "mma8451", (kernel_ulong_t)&mma_chip_info_table[mma8451] }, + { "mma8452", (kernel_ulong_t)&mma_chip_info_table[mma8452] }, + { "mma8453", (kernel_ulong_t)&mma_chip_info_table[mma8453] }, + { "mma8652", (kernel_ulong_t)&mma_chip_info_table[mma8652] }, + { "mma8653", (kernel_ulong_t)&mma_chip_info_table[mma8653] }, { } }; MODULE_DEVICE_TABLE(i2c, mma8452_id); @@ -1810,7 +1834,7 @@ MODULE_DEVICE_TABLE(i2c, mma8452_id); static struct i2c_driver mma8452_driver = { .driver = { .name = "mma8452", - .of_match_table = of_match_ptr(mma8452_dt_ids), + .of_match_table = mma8452_dt_ids, .pm = &mma8452_pm_ops, }, .probe = mma8452_probe, |
