iio: accel: kionix-kx022a: Refactor driver and add chip_info structure
authorMehdi Djait <mehdi.djait.k@gmail.com>
Sat, 16 Sep 2023 12:38:51 +0000 (14:38 +0200)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Sun, 17 Sep 2023 09:44:31 +0000 (10:44 +0100)
Add the chip_info structure to the driver's private data to hold all
the device specific infos.
Refactor the kx022a driver implementation to make it more generic and
extensible.

Acked-by: Matti Vaittinen <mazziesaccount@gmail.com>
Signed-off-by: Mehdi Djait <mehdi.djait.k@gmail.com>
Link: https://lore.kernel.org/r/7a31d0cdefba15d7c791252ec8bc5db553b3996b.1694867379.git.mehdi.djait.k@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/accel/kionix-kx022a-i2c.c
drivers/iio/accel/kionix-kx022a-spi.c
drivers/iio/accel/kionix-kx022a.c
drivers/iio/accel/kionix-kx022a.h

index c0d0b69680f961032ed5b365e5d488679a07a6d5..2fdc4c1ab93f7cbbd26940bb3b25418a62751174 100644 (file)
@@ -15,6 +15,7 @@
 static int kx022a_i2c_probe(struct i2c_client *i2c)
 {
        struct device *dev = &i2c->dev;
+       const struct kx022a_chip_info *chip_info;
        struct regmap *regmap;
 
        if (!i2c->irq) {
@@ -22,22 +23,26 @@ static int kx022a_i2c_probe(struct i2c_client *i2c)
                return -EINVAL;
        }
 
-       regmap = devm_regmap_init_i2c(i2c, &kx022a_regmap);
+       chip_info = i2c_get_match_data(i2c);
+       if (!chip_info)
+               return -EINVAL;
+
+       regmap = devm_regmap_init_i2c(i2c, chip_info->regmap_config);
        if (IS_ERR(regmap))
                return dev_err_probe(dev, PTR_ERR(regmap),
                                     "Failed to initialize Regmap\n");
 
-       return kx022a_probe_internal(dev);
+       return kx022a_probe_internal(dev, chip_info);
 }
 
 static const struct i2c_device_id kx022a_i2c_id[] = {
-       { .name = "kx022a" },
+       { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, kx022a_i2c_id);
 
 static const struct of_device_id kx022a_of_match[] = {
-       { .compatible = "kionix,kx022a", },
+       { .compatible = "kionix,kx022a", .data = &kx022a_chip_info },
        { }
 };
 MODULE_DEVICE_TABLE(of, kx022a_of_match);
index f45a46899a5f63d4d6a9021190d7a2b6091db3ec..c21494ade1573672b311a645502a9dbf15256c16 100644 (file)
@@ -15,6 +15,7 @@
 static int kx022a_spi_probe(struct spi_device *spi)
 {
        struct device *dev = &spi->dev;
+       const struct kx022a_chip_info *chip_info;
        struct regmap *regmap;
 
        if (!spi->irq) {
@@ -22,22 +23,26 @@ static int kx022a_spi_probe(struct spi_device *spi)
                return -EINVAL;
        }
 
-       regmap = devm_regmap_init_spi(spi, &kx022a_regmap);
+       chip_info = spi_get_device_match_data(spi);
+       if (!chip_info)
+               return -EINVAL;
+
+       regmap = devm_regmap_init_spi(spi, chip_info->regmap_config);
        if (IS_ERR(regmap))
                return dev_err_probe(dev, PTR_ERR(regmap),
                                     "Failed to initialize Regmap\n");
 
-       return kx022a_probe_internal(dev);
+       return kx022a_probe_internal(dev, chip_info);
 }
 
 static const struct spi_device_id kx022a_id[] = {
-       { "kx022a" },
+       { .name = "kx022a", .driver_data = (kernel_ulong_t)&kx022a_chip_info },
        { }
 };
 MODULE_DEVICE_TABLE(spi, kx022a_id);
 
 static const struct of_device_id kx022a_of_match[] = {
-       { .compatible = "kionix,kx022a", },
+       { .compatible = "kionix,kx022a", .data = &kx022a_chip_info },
        { }
 };
 MODULE_DEVICE_TABLE(of, kx022a_of_match);
index 5a144f86c6342bfd799339f0ab44387cd3abce76..448f1019e5bf5374a7689bf0643a8381226cc5a7 100644 (file)
@@ -48,7 +48,7 @@ enum {
        KX022A_STATE_FIFO,
 };
 
-/* Regmap configs */
+/* kx022a Regmap configs */
 static const struct regmap_range kx022a_volatile_ranges[] = {
        {
                .range_min = KX022A_REG_XHP_L,
@@ -138,7 +138,7 @@ static const struct regmap_access_table kx022a_nir_regs = {
        .n_yes_ranges = ARRAY_SIZE(kx022a_noinc_read_ranges),
 };
 
-const struct regmap_config kx022a_regmap = {
+static const struct regmap_config kx022a_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
        .volatile_table = &kx022a_volatile_regs,
@@ -149,10 +149,10 @@ const struct regmap_config kx022a_regmap = {
        .max_register = KX022A_MAX_REGISTER,
        .cache_type = REGCACHE_RBTREE,
 };
-EXPORT_SYMBOL_NS_GPL(kx022a_regmap, IIO_KX022A);
 
 struct kx022a_data {
        struct regmap *regmap;
+       const struct kx022a_chip_info *chip_info;
        struct iio_trigger *trig;
        struct device *dev;
        struct iio_mount_matrix orientation;
@@ -175,6 +175,8 @@ struct kx022a_data {
        struct mutex mutex;
        u8 watermark;
 
+       __le16 *fifo_buffer;
+
        /* 3 x 16bit accel data + timestamp */
        __le16 buffer[8] __aligned(IIO_DMA_MINALIGN);
        struct {
@@ -208,7 +210,7 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = {
        { }
 };
 
-#define KX022A_ACCEL_CHAN(axis, index)                         \
+#define KX022A_ACCEL_CHAN(axis, reg, index)                    \
 {                                                              \
        .type = IIO_ACCEL,                                      \
        .modified = 1,                                          \
@@ -220,7 +222,7 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = {
                                BIT(IIO_CHAN_INFO_SCALE) |      \
                                BIT(IIO_CHAN_INFO_SAMP_FREQ),   \
        .ext_info = kx022a_ext_info,                            \
-       .address = KX022A_REG_##axis##OUT_L,                    \
+       .address = reg,                                         \
        .scan_index = index,                                    \
        .scan_type = {                                          \
                .sign = 's',                                    \
@@ -231,9 +233,9 @@ static const struct iio_chan_spec_ext_info kx022a_ext_info[] = {
 }
 
 static const struct iio_chan_spec kx022a_channels[] = {
-       KX022A_ACCEL_CHAN(X, 0),
-       KX022A_ACCEL_CHAN(Y, 1),
-       KX022A_ACCEL_CHAN(Z, 2),
+       KX022A_ACCEL_CHAN(X, KX022A_REG_XOUT_L, 0),
+       KX022A_ACCEL_CHAN(Y, KX022A_REG_YOUT_L, 1),
+       KX022A_ACCEL_CHAN(Z, KX022A_REG_ZOUT_L, 2),
        IIO_CHAN_SOFT_TIMESTAMP(3),
 };
 
@@ -332,10 +334,10 @@ static int kx022a_turn_on_off_unlocked(struct kx022a_data *data, bool on)
        int ret;
 
        if (on)
-               ret = regmap_set_bits(data->regmap, KX022A_REG_CNTL,
+               ret = regmap_set_bits(data->regmap, data->chip_info->cntl,
                                      KX022A_MASK_PC1);
        else
-               ret = regmap_clear_bits(data->regmap, KX022A_REG_CNTL,
+               ret = regmap_clear_bits(data->regmap, data->chip_info->cntl,
                                        KX022A_MASK_PC1);
        if (ret)
                dev_err(data->dev, "Turn %s fail %d\n", str_on_off(on), ret);
@@ -402,7 +404,7 @@ static int kx022a_write_raw(struct iio_dev *idev,
                        break;
 
                ret = regmap_update_bits(data->regmap,
-                                        KX022A_REG_ODCNTL,
+                                        data->chip_info->odcntl,
                                         KX022A_MASK_ODR, n);
                data->odr_ns = kx022a_odrs[n];
                kx022a_turn_on_unlock(data);
@@ -423,7 +425,7 @@ static int kx022a_write_raw(struct iio_dev *idev,
                if (ret)
                        break;
 
-               ret = regmap_update_bits(data->regmap, KX022A_REG_CNTL,
+               ret = regmap_update_bits(data->regmap, data->chip_info->cntl,
                                         KX022A_MASK_GSEL,
                                         n << KX022A_GSEL_SHIFT);
                kx022a_turn_on_unlock(data);
@@ -445,7 +447,7 @@ static int kx022a_fifo_set_wmi(struct kx022a_data *data)
 
        threshold = data->watermark;
 
-       return regmap_update_bits(data->regmap, KX022A_REG_BUF_CNTL1,
+       return regmap_update_bits(data->regmap, data->chip_info->buf_cntl1,
                                  KX022A_MASK_WM_TH, threshold);
 }
 
@@ -488,7 +490,7 @@ static int kx022a_read_raw(struct iio_dev *idev,
                return ret;
 
        case IIO_CHAN_INFO_SAMP_FREQ:
-               ret = regmap_read(data->regmap, KX022A_REG_ODCNTL, &regval);
+               ret = regmap_read(data->regmap, data->chip_info->odcntl, &regval);
                if (ret)
                        return ret;
 
@@ -503,7 +505,7 @@ static int kx022a_read_raw(struct iio_dev *idev,
                return IIO_VAL_INT_PLUS_MICRO;
 
        case IIO_CHAN_INFO_SCALE:
-               ret = regmap_read(data->regmap, KX022A_REG_CNTL, &regval);
+               ret = regmap_read(data->regmap, data->chip_info->cntl, &regval);
                if (ret < 0)
                        return ret;
 
@@ -519,8 +521,7 @@ static int kx022a_set_watermark(struct iio_dev *idev, unsigned int val)
 {
        struct kx022a_data *data = iio_priv(idev);
 
-       if (val > KX022A_FIFO_LENGTH)
-               val = KX022A_FIFO_LENGTH;
+       val = min(data->chip_info->fifo_length, val);
 
        mutex_lock(&data->mutex);
        data->watermark = val;
@@ -581,7 +582,7 @@ static int kx022a_drop_fifo_contents(struct kx022a_data *data)
         */
        data->timestamp = 0;
 
-       return regmap_write(data->regmap, KX022A_REG_BUF_CLEAR, 0x0);
+       return regmap_write(data->regmap, data->chip_info->buf_clear, 0x0);
 }
 
 static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
@@ -589,7 +590,6 @@ static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
 {
        struct kx022a_data *data = iio_priv(idev);
        struct device *dev = regmap_get_device(data->regmap);
-       __le16 buffer[KX022A_FIFO_LENGTH * 3];
        uint64_t sample_period;
        int count, fifo_bytes;
        bool renable = false;
@@ -668,13 +668,13 @@ static int __kx022a_fifo_flush(struct iio_dev *idev, unsigned int samples,
        }
 
        fifo_bytes = count * KX022A_FIFO_SAMPLES_SIZE_BYTES;
-       ret = regmap_noinc_read(data->regmap, KX022A_REG_BUF_READ,
-                               &buffer[0], fifo_bytes);
+       ret = regmap_noinc_read(data->regmap, data->chip_info->buf_read,
+                               data->fifo_buffer, fifo_bytes);
        if (ret)
                goto renable_out;
 
        for (i = 0; i < count; i++) {
-               __le16 *sam = &buffer[i * 3];
+               __le16 *sam = &data->fifo_buffer[i * 3];
                __le16 *chs;
                int bit;
 
@@ -721,10 +721,10 @@ static const struct iio_info kx022a_info = {
 static int kx022a_set_drdy_irq(struct kx022a_data *data, bool en)
 {
        if (en)
-               return regmap_set_bits(data->regmap, KX022A_REG_CNTL,
+               return regmap_set_bits(data->regmap, data->chip_info->cntl,
                                       KX022A_MASK_DRDY);
 
-       return regmap_clear_bits(data->regmap, KX022A_REG_CNTL,
+       return regmap_clear_bits(data->regmap, data->chip_info->cntl,
                                 KX022A_MASK_DRDY);
 }
 
@@ -759,7 +759,7 @@ static int kx022a_fifo_disable(struct kx022a_data *data)
        if (ret)
                goto unlock_out;
 
-       ret = regmap_clear_bits(data->regmap, KX022A_REG_BUF_CNTL2,
+       ret = regmap_clear_bits(data->regmap, data->chip_info->buf_cntl2,
                                KX022A_MASK_BUF_EN);
        if (ret)
                goto unlock_out;
@@ -768,6 +768,8 @@ static int kx022a_fifo_disable(struct kx022a_data *data)
 
        kx022a_drop_fifo_contents(data);
 
+       kfree(data->fifo_buffer);
+
        return kx022a_turn_on_unlock(data);
 
 unlock_out:
@@ -790,6 +792,12 @@ static int kx022a_fifo_enable(struct kx022a_data *data)
 {
        int ret;
 
+       data->fifo_buffer = kmalloc_array(data->chip_info->fifo_length,
+                                         KX022A_FIFO_SAMPLES_SIZE_BYTES,
+                                         GFP_KERNEL);
+       if (!data->fifo_buffer)
+               return -ENOMEM;
+
        ret = kx022a_turn_off_lock(data);
        if (ret)
                return ret;
@@ -800,7 +808,7 @@ static int kx022a_fifo_enable(struct kx022a_data *data)
                goto unlock_out;
 
        /* Enable buffer */
-       ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2,
+       ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2,
                              KX022A_MASK_BUF_EN);
        if (ret)
                goto unlock_out;
@@ -846,7 +854,7 @@ static irqreturn_t kx022a_trigger_handler(int irq, void *p)
        struct kx022a_data *data = iio_priv(idev);
        int ret;
 
-       ret = regmap_bulk_read(data->regmap, KX022A_REG_XOUT_L, data->buffer,
+       ret = regmap_bulk_read(data->regmap, data->chip_info->xout_l, data->buffer,
                               KX022A_FIFO_SAMPLES_SIZE_BYTES);
        if (ret < 0)
                goto err_read;
@@ -894,7 +902,7 @@ static irqreturn_t kx022a_irq_thread_handler(int irq, void *private)
        if (data->state & KX022A_STATE_FIFO) {
                int ok;
 
-               ok = __kx022a_fifo_flush(idev, KX022A_FIFO_LENGTH, true);
+               ok = __kx022a_fifo_flush(idev, data->chip_info->fifo_length, true);
                if (ok > 0)
                        ret = IRQ_HANDLED;
        }
@@ -947,7 +955,7 @@ static int kx022a_chip_init(struct kx022a_data *data)
        int ret, val;
 
        /* Reset the senor */
-       ret = regmap_write(data->regmap, KX022A_REG_CNTL2, KX022A_MASK_SRST);
+       ret = regmap_write(data->regmap, data->chip_info->cntl2, KX022A_MASK_SRST);
        if (ret)
                return ret;
 
@@ -957,7 +965,7 @@ static int kx022a_chip_init(struct kx022a_data *data)
         */
        msleep(1);
 
-       ret = regmap_read_poll_timeout(data->regmap, KX022A_REG_CNTL2, val,
+       ret = regmap_read_poll_timeout(data->regmap, data->chip_info->cntl2, val,
                                       !(val & KX022A_MASK_SRST),
                                       KX022A_SOFT_RESET_WAIT_TIME_US,
                                       KX022A_SOFT_RESET_TOTAL_WAIT_TIME_US);
@@ -967,14 +975,14 @@ static int kx022a_chip_init(struct kx022a_data *data)
                return ret;
        }
 
-       ret = regmap_reinit_cache(data->regmap, &kx022a_regmap);
+       ret = regmap_reinit_cache(data->regmap, data->chip_info->regmap_config);
        if (ret) {
                dev_err(data->dev, "Failed to reinit reg cache\n");
                return ret;
        }
 
        /* set data res 16bit */
-       ret = regmap_set_bits(data->regmap, KX022A_REG_BUF_CNTL2,
+       ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2,
                              KX022A_MASK_BRES16);
        if (ret) {
                dev_err(data->dev, "Failed to set data resolution\n");
@@ -984,7 +992,31 @@ static int kx022a_chip_init(struct kx022a_data *data)
        return kx022a_prepare_irq_pin(data);
 }
 
-int kx022a_probe_internal(struct device *dev)
+const struct kx022a_chip_info kx022a_chip_info = {
+       .name                           = "kx022-accel",
+       .regmap_config                  = &kx022a_regmap_config,
+       .channels                       = kx022a_channels,
+       .num_channels                   = ARRAY_SIZE(kx022a_channels),
+       .fifo_length                    = KX022A_FIFO_LENGTH,
+       .who                            = KX022A_REG_WHO,
+       .id                             = KX022A_ID,
+       .cntl                           = KX022A_REG_CNTL,
+       .cntl2                          = KX022A_REG_CNTL2,
+       .odcntl                         = KX022A_REG_ODCNTL,
+       .buf_cntl1                      = KX022A_REG_BUF_CNTL1,
+       .buf_cntl2                      = KX022A_REG_BUF_CNTL2,
+       .buf_clear                      = KX022A_REG_BUF_CLEAR,
+       .buf_status1                    = KX022A_REG_BUF_STATUS_1,
+       .buf_read                       = KX022A_REG_BUF_READ,
+       .inc1                           = KX022A_REG_INC1,
+       .inc4                           = KX022A_REG_INC4,
+       .inc5                           = KX022A_REG_INC5,
+       .inc6                           = KX022A_REG_INC6,
+       .xout_l                         = KX022A_REG_XOUT_L,
+};
+EXPORT_SYMBOL_NS_GPL(kx022a_chip_info, IIO_KX022A);
+
+int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info)
 {
        static const char * const regulator_names[] = {"io-vdd", "vdd"};
        struct iio_trigger *indio_trig;
@@ -1011,6 +1043,7 @@ int kx022a_probe_internal(struct device *dev)
                return -ENOMEM;
 
        data = iio_priv(idev);
+       data->chip_info = chip_info;
 
        /*
         * VDD is the analog and digital domain voltage supply and
@@ -1021,24 +1054,24 @@ int kx022a_probe_internal(struct device *dev)
        if (ret && ret != -ENODEV)
                return dev_err_probe(dev, ret, "failed to enable regulator\n");
 
-       ret = regmap_read(regmap, KX022A_REG_WHO, &chip_id);
+       ret = regmap_read(regmap, chip_info->who, &chip_id);
        if (ret)
                return dev_err_probe(dev, ret, "Failed to access sensor\n");
 
-       if (chip_id != KX022A_ID)
+       if (chip_id != chip_info->id)
                dev_warn(dev, "unknown device 0x%x\n", chip_id);
 
        irq = fwnode_irq_get_byname(fwnode, "INT1");
        if (irq > 0) {
-               data->inc_reg = KX022A_REG_INC1;
-               data->ien_reg = KX022A_REG_INC4;
+               data->inc_reg = chip_info->inc1;
+               data->ien_reg = chip_info->inc4;
        } else {
                irq = fwnode_irq_get_byname(fwnode, "INT2");
                if (irq < 0)
                        return dev_err_probe(dev, irq, "No suitable IRQ\n");
 
-               data->inc_reg = KX022A_REG_INC5;
-               data->ien_reg = KX022A_REG_INC6;
+               data->inc_reg = chip_info->inc5;
+               data->ien_reg = chip_info->inc6;
        }
 
        data->regmap = regmap;
@@ -1047,9 +1080,9 @@ int kx022a_probe_internal(struct device *dev)
        data->odr_ns = KX022A_DEFAULT_PERIOD_NS;
        mutex_init(&data->mutex);
 
-       idev->channels = kx022a_channels;
-       idev->num_channels = ARRAY_SIZE(kx022a_channels);
-       idev->name = "kx022-accel";
+       idev->channels = chip_info->channels;
+       idev->num_channels = chip_info->num_channels;
+       idev->name = chip_info->name;
        idev->info = &kx022a_info;
        idev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
        idev->available_scan_masks = kx022a_scan_masks;
index 12424649d438b29b0fc7ef7a3c7120e029bcc33b..92f69c33a53b5a51cc8595b8d131866ba87bf0f6 100644 (file)
 
 struct device;
 
-int kx022a_probe_internal(struct device *dev);
-extern const struct regmap_config kx022a_regmap;
+/**
+ * struct kx022a_chip_info - Kionix accelerometer chip specific information
+ *
+ * @name:                      name of the device
+ * @regmap_config:             pointer to register map configuration
+ * @channels:                  pointer to iio_chan_spec array
+ * @num_channels:              number of iio_chan_spec channels
+ * @fifo_length:               number of 16-bit samples in a full buffer
+ * @who:                       WHO_AM_I register
+ * @id:                                WHO_AM_I register value
+ * @cntl:                      control register 1
+ * @cntl2:                     control register 2
+ * @odcntl:                    output data control register
+ * @buf_cntl1:                 buffer control register 1
+ * @buf_cntl2:                 buffer control register 2
+ * @buf_clear:                 buffer clear register
+ * @buf_status1:               buffer status register 1
+ * @buf_read:                  buffer read register
+ * @inc1:                      interrupt control register 1
+ * @inc4:                      interrupt control register 4
+ * @inc5:                      interrupt control register 5
+ * @inc6:                      interrupt control register 6
+ * @xout_l:                    x-axis output least significant byte
+ */
+struct kx022a_chip_info {
+       const char *name;
+       const struct regmap_config *regmap_config;
+       const struct iio_chan_spec *channels;
+       unsigned int num_channels;
+       unsigned int fifo_length;
+       u8 who;
+       u8 id;
+       u8 cntl;
+       u8 cntl2;
+       u8 odcntl;
+       u8 buf_cntl1;
+       u8 buf_cntl2;
+       u8 buf_clear;
+       u8 buf_status1;
+       u8 buf_read;
+       u8 inc1;
+       u8 inc4;
+       u8 inc5;
+       u8 inc6;
+       u8 xout_l;
+};
+
+int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info);
+
+extern const struct kx022a_chip_info kx022a_chip_info;
 
 #endif