On 03/09/16 20:29, Jonathan Cameron wrote: > On 03/09/16 20:24, Jonathan Cameron wrote: >> On 01/09/16 10:44, Linus Walleij wrote: >>> This moves the KXSD9 SPI transport out to its own file and Kconfig >>> entry, so that we will be able to add another transport method. >>> We export the common probe and add a local header file for the >>> functionality shared between the main driver and the transport >>> driver. >>> >>> We make the SPI transport the default for the driver if SPI is >>> available and the KXSD9 driver was selected, so the oldconfig >>> upgrade path will be clear. >>> >>> Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx> >> Applied to the togreg branch of iio.git >> > Backed out due to later mess against the fixes. Applied again. Jonathan > > Jonathan >> Thanks >>> --- >>> ChangeLog v1->v2: >>> - Preserve MODULE_* macros as the compilation complains about >>> tainting etc. >>> - Rebased to account for the common .remove() function, make sure >>> this is also exported etc. >>> --- >>> drivers/iio/accel/Kconfig | 10 ++- >>> drivers/iio/accel/Makefile | 1 + >>> drivers/iio/accel/kxsd9-spi.c | 110 +++++++++++++++++++++++++++++++ >>> drivers/iio/accel/kxsd9.c | 147 ++++++------------------------------------ >>> drivers/iio/accel/kxsd9.h | 32 +++++++++ >>> 5 files changed, 173 insertions(+), 127 deletions(-) >>> create mode 100644 drivers/iio/accel/kxsd9-spi.c >>> create mode 100644 drivers/iio/accel/kxsd9.h >>> >>> diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig >>> index 89d78208de3f..95e3fc09f640 100644 >>> --- a/drivers/iio/accel/Kconfig >>> +++ b/drivers/iio/accel/Kconfig >>> @@ -96,7 +96,6 @@ config IIO_ST_ACCEL_SPI_3AXIS >>> >>> config KXSD9 >>> tristate "Kionix KXSD9 Accelerometer Driver" >>> - depends on SPI >>> help >>> Say yes here to build support for the Kionix KXSD9 accelerometer. >>> Currently this only supports the device via an SPI interface. >>> @@ -104,6 +103,15 @@ config KXSD9 >>> To compile this driver as a module, choose M here: the module >>> will be called kxsd9. >>> >>> +config KXSD9_SPI >>> + tristate "Kionix KXSD9 SPI transport" >>> + depends on KXSD9 >>> + depends on SPI >>> + default KXSD9 >>> + help >>> + Say yes here to enable the Kionix KXSD9 accelerometer >>> + SPI transport channel. >>> + >>> config KXCJK1013 >>> tristate "Kionix 3-Axis Accelerometer Driver" >>> depends on I2C >>> diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile >>> index 6cedbecca2ee..22a5770f62a9 100644 >>> --- a/drivers/iio/accel/Makefile >>> +++ b/drivers/iio/accel/Makefile >>> @@ -11,6 +11,7 @@ obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o >>> obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o >>> obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o >>> obj-$(CONFIG_KXSD9) += kxsd9.o >>> +obj-$(CONFIG_KXSD9_SPI) += kxsd9-spi.o >>> >>> obj-$(CONFIG_MMA7455) += mma7455_core.o >>> obj-$(CONFIG_MMA7455_I2C) += mma7455_i2c.o >>> diff --git a/drivers/iio/accel/kxsd9-spi.c b/drivers/iio/accel/kxsd9-spi.c >>> new file mode 100644 >>> index 000000000000..ec9d00d5340f >>> --- /dev/null >>> +++ b/drivers/iio/accel/kxsd9-spi.c >>> @@ -0,0 +1,110 @@ >>> +#include <linux/device.h> >>> +#include <linux/kernel.h> >>> +#include <linux/spi/spi.h> >>> +#include <linux/module.h> >>> +#include <linux/slab.h> >>> + >>> +#include "kxsd9.h" >>> + >>> +#define KXSD9_READ(a) (0x80 | (a)) >>> +#define KXSD9_WRITE(a) (a) >>> + >>> +static int kxsd9_spi_readreg(struct kxsd9_transport *tr, u8 address) >>> +{ >>> + struct spi_device *spi = tr->trdev; >>> + >>> + return spi_w8r8(spi, KXSD9_READ(address)); >>> +} >>> + >>> +static int kxsd9_spi_writereg(struct kxsd9_transport *tr, u8 address, u8 val) >>> +{ >>> + struct spi_device *spi = tr->trdev; >>> + >>> + tr->tx[0] = KXSD9_WRITE(address), >>> + tr->tx[1] = val; >>> + return spi_write(spi, tr->tx, 2); >>> +} >>> + >>> +static int kxsd9_spi_write2(struct kxsd9_transport *tr, u8 b1, u8 b2) >>> +{ >>> + struct spi_device *spi = tr->trdev; >>> + >>> + tr->tx[0] = b1; >>> + tr->tx[1] = b2; >>> + return spi_write(spi, tr->tx, 2); >>> +} >>> + >>> +static int kxsd9_spi_readval(struct kxsd9_transport *tr, u8 address) >>> +{ >>> + struct spi_device *spi = tr->trdev; >>> + struct spi_transfer xfers[] = { >>> + { >>> + .bits_per_word = 8, >>> + .len = 1, >>> + .delay_usecs = 200, >>> + .tx_buf = tr->tx, >>> + }, { >>> + .bits_per_word = 8, >>> + .len = 2, >>> + .rx_buf = tr->rx, >>> + }, >>> + }; >>> + int ret; >>> + >>> + tr->tx[0] = KXSD9_READ(address); >>> + ret = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers)); >>> + if (!ret) >>> + ret = (((u16)(tr->rx[0])) << 8) | (tr->rx[1]); >>> + return ret; >>> +} >>> + >>> +static int kxsd9_spi_probe(struct spi_device *spi) >>> +{ >>> + struct kxsd9_transport *transport; >>> + int ret; >>> + >>> + transport = devm_kzalloc(&spi->dev, sizeof(*transport), GFP_KERNEL); >>> + if (!transport) >>> + return -ENOMEM; >>> + >>> + transport->trdev = spi; >>> + transport->readreg = kxsd9_spi_readreg; >>> + transport->writereg = kxsd9_spi_writereg; >>> + transport->write2 = kxsd9_spi_write2; >>> + transport->readval = kxsd9_spi_readval; >>> + spi->mode = SPI_MODE_0; >>> + spi_setup(spi); >>> + >>> + ret = kxsd9_common_probe(&spi->dev, >>> + transport, >>> + spi_get_device_id(spi)->name); >>> + if (ret) >>> + return ret; >>> + >>> + return 0; >>> +} >>> + >>> +static int kxsd9_spi_remove(struct spi_device *spi) >>> +{ >>> + return kxsd9_common_remove(&spi->dev); >>> +} >>> + >>> +static const struct spi_device_id kxsd9_spi_id[] = { >>> + {"kxsd9", 0}, >>> + { }, >>> +}; >>> +MODULE_DEVICE_TABLE(spi, kxsd9_spi_id); >>> + >>> +static struct spi_driver kxsd9_spi_driver = { >>> + .driver = { >>> + .name = "kxsd9", >>> + }, >>> + .probe = kxsd9_spi_probe, >>> + .remove = kxsd9_spi_remove, >>> + .id_table = kxsd9_spi_id, >>> +}; >>> +module_spi_driver(kxsd9_spi_driver); >>> + >>> +MODULE_AUTHOR("Jonathan Cameron <jic23@xxxxxxxxxx>"); >>> +MODULE_DESCRIPTION("Kionix KXSD9 SPI driver"); >>> +MODULE_LICENSE("GPL v2"); >>> diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c >>> index 1f9e9a867f34..e2033374bfef 100644 >>> --- a/drivers/iio/accel/kxsd9.c >>> +++ b/drivers/iio/accel/kxsd9.c >>> @@ -18,7 +18,6 @@ >>> >>> #include <linux/device.h> >>> #include <linux/kernel.h> >>> -#include <linux/spi/spi.h> >>> #include <linux/sysfs.h> >>> #include <linux/slab.h> >>> #include <linux/module.h> >>> @@ -26,6 +25,8 @@ >>> #include <linux/iio/iio.h> >>> #include <linux/iio/sysfs.h> >>> >>> +#include "kxsd9.h" >>> + >>> #define KXSD9_REG_X 0x00 >>> #define KXSD9_REG_Y 0x02 >>> #define KXSD9_REG_Z 0x04 >>> @@ -38,32 +39,6 @@ >>> #define KXSD9_REG_CTRL_B 0x0d >>> #define KXSD9_REG_CTRL_A 0x0e >>> >>> -#define KXSD9_READ(a) (0x80 | (a)) >>> -#define KXSD9_WRITE(a) (a) >>> - >>> -#define KXSD9_STATE_RX_SIZE 2 >>> -#define KXSD9_STATE_TX_SIZE 2 >>> - >>> -struct kxsd9_transport; >>> - >>> -/** >>> - * struct kxsd9_transport - transport adapter for SPI or I2C >>> - * @trdev: transport device such as SPI or I2C >>> - * @write1(): function to write a byte to the device >>> - * @write2(): function to write two consecutive bytes to the device >>> - * @readval(): function to read a 16bit value from the device >>> - * @rx: cache aligned read buffer >>> - * @tx: cache aligned write buffer >>> - */ >>> -struct kxsd9_transport { >>> - void *trdev; >>> - int (*write1) (struct kxsd9_transport *tr, u8 byte); >>> - int (*write2) (struct kxsd9_transport *tr, u8 b1, u8 b2); >>> - int (*readval) (struct kxsd9_transport *tr, u8 address); >>> - u8 rx[KXSD9_STATE_RX_SIZE] ____cacheline_aligned; >>> - u8 tx[KXSD9_STATE_TX_SIZE]; >>> -}; >>> - >>> /** >>> * struct kxsd9_state - device related storage >>> * @transport: transport for the KXSD9 >>> @@ -98,12 +73,13 @@ static int kxsd9_write_scale(struct iio_dev *indio_dev, int micro) >>> return -EINVAL; >>> >>> mutex_lock(&st->buf_lock); >>> - ret = st->transport->write1(st->transport, KXSD9_READ(KXSD9_REG_CTRL_C)); >>> - if (ret) >>> + ret = st->transport->readreg(st->transport, >>> + KXSD9_REG_CTRL_C); >>> + if (ret < 0) >>> goto error_ret; >>> - ret = st->transport->write2(st->transport, >>> - KXSD9_WRITE(KXSD9_REG_CTRL_C), >>> - (ret & ~KXSD9_FS_MASK) | i); >>> + ret = st->transport->writereg(st->transport, >>> + KXSD9_REG_CTRL_C, >>> + (ret & ~KXSD9_FS_MASK) | i); >>> error_ret: >>> mutex_unlock(&st->buf_lock); >>> return ret; >>> @@ -115,7 +91,9 @@ static int kxsd9_read(struct iio_dev *indio_dev, u8 address) >>> struct kxsd9_state *st = iio_priv(indio_dev); >>> >>> mutex_lock(&st->buf_lock); >>> - ret = st->transport->readval(st->transport, KXSD9_READ(address)); >>> + ret = st->transport->readval(st->transport, address); >>> + /* Only 12 bits are valid */ >>> + ret &= 0xfff0; >>> mutex_unlock(&st->buf_lock); >>> return ret; >>> } >>> @@ -165,8 +143,9 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev, >>> ret = IIO_VAL_INT; >>> break; >>> case IIO_CHAN_INFO_SCALE: >>> - ret = st->transport->write1(st->transport, KXSD9_READ(KXSD9_REG_CTRL_C)); >>> - if (ret) >>> + ret = st->transport->readreg(st->transport, >>> + KXSD9_REG_CTRL_C); >>> + if (ret < 0) >>> goto error_ret; >>> *val = 0; >>> *val2 = kxsd9_micro_scales[ret & KXSD9_FS_MASK]; >>> @@ -218,9 +197,9 @@ static const struct iio_info kxsd9_info = { >>> .driver_module = THIS_MODULE, >>> }; >>> >>> -static int kxsd9_common_probe(struct device *parent, >>> - struct kxsd9_transport *transport, >>> - const char *name) >>> +int kxsd9_common_probe(struct device *parent, >>> + struct kxsd9_transport *transport, >>> + const char *name) >>> { >>> struct iio_dev *indio_dev; >>> struct kxsd9_state *st; >>> @@ -251,8 +230,9 @@ static int kxsd9_common_probe(struct device *parent, >>> >>> return 0; >>> } >>> +EXPORT_SYMBOL(kxsd9_common_probe); >>> >>> -static int kxsd9_common_remove(struct device *parent) >>> +int kxsd9_common_remove(struct device *parent) >>> { >>> struct iio_dev *indio_dev = dev_get_drvdata(parent); >>> >>> @@ -260,93 +240,8 @@ static int kxsd9_common_remove(struct device *parent) >>> >>> return 0; >>> } >>> - >>> -static int kxsd9_spi_write1(struct kxsd9_transport *tr, u8 byte) >>> -{ >>> - struct spi_device *spi = tr->trdev; >>> - >>> - return spi_w8r8(spi, byte); >>> -} >>> - >>> -static int kxsd9_spi_write2(struct kxsd9_transport *tr, u8 b1, u8 b2) >>> -{ >>> - struct spi_device *spi = tr->trdev; >>> - >>> - tr->tx[0] = b1; >>> - tr->tx[1] = b2; >>> - return spi_write(spi, tr->tx, 2); >>> -} >>> - >>> -static int kxsd9_spi_readval(struct kxsd9_transport *tr, u8 address) >>> -{ >>> - struct spi_device *spi = tr->trdev; >>> - struct spi_transfer xfers[] = { >>> - { >>> - .bits_per_word = 8, >>> - .len = 1, >>> - .delay_usecs = 200, >>> - .tx_buf = tr->tx, >>> - }, { >>> - .bits_per_word = 8, >>> - .len = 2, >>> - .rx_buf = tr->rx, >>> - }, >>> - }; >>> - int ret; >>> - >>> - tr->tx[0] = address; >>> - ret = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers)); >>> - if (!ret) >>> - ret = (((u16)(tr->rx[0])) << 8) | (tr->rx[1] & 0xF0); >>> - return ret; >>> -} >>> - >>> -static int kxsd9_spi_probe(struct spi_device *spi) >>> -{ >>> - struct kxsd9_transport *transport; >>> - int ret; >>> - >>> - transport = devm_kzalloc(&spi->dev, sizeof(*transport), GFP_KERNEL); >>> - if (!transport) >>> - return -ENOMEM; >>> - >>> - transport->trdev = spi; >>> - transport->write1 = kxsd9_spi_write1; >>> - transport->write2 = kxsd9_spi_write2; >>> - transport->readval = kxsd9_spi_readval; >>> - spi->mode = SPI_MODE_0; >>> - spi_setup(spi); >>> - >>> - ret = kxsd9_common_probe(&spi->dev, >>> - transport, >>> - spi_get_device_id(spi)->name); >>> - if (ret) >>> - return ret; >>> - >>> - return 0; >>> -} >>> - >>> -static int kxsd9_spi_remove(struct spi_device *spi) >>> -{ >>> - return kxsd9_common_remove(&spi->dev); >>> -} >>> - >>> -static const struct spi_device_id kxsd9_spi_id[] = { >>> - {"kxsd9", 0}, >>> - { }, >>> -}; >>> -MODULE_DEVICE_TABLE(spi, kxsd9_spi_id); >>> - >>> -static struct spi_driver kxsd9_spi_driver = { >>> - .driver = { >>> - .name = "kxsd9", >>> - }, >>> - .probe = kxsd9_spi_probe, >>> - .remove = kxsd9_spi_remove, >>> - .id_table = kxsd9_spi_id, >>> -}; >>> -module_spi_driver(kxsd9_spi_driver); >>> +EXPORT_SYMBOL(kxsd9_common_remove); >>> >>> MODULE_AUTHOR("Jonathan Cameron <jic23@xxxxxxxxxx>"); >>> -MODULE_DESCRIPTION("Kionix KXSD9 SPI driver"); >>> +MODULE_DESCRIPTION("Kionix KXSD9 driver"); >>> MODULE_LICENSE("GPL v2"); >>> diff --git a/drivers/iio/accel/kxsd9.h b/drivers/iio/accel/kxsd9.h >>> new file mode 100644 >>> index 000000000000..28845c3440e9 >>> --- /dev/null >>> +++ b/drivers/iio/accel/kxsd9.h >>> @@ -0,0 +1,32 @@ >>> +#include <linux/device.h> >>> +#include <linux/kernel.h> >>> + >>> +#define KXSD9_STATE_RX_SIZE 2 >>> +#define KXSD9_STATE_TX_SIZE 2 >>> + >>> +struct kxsd9_transport; >>> + >>> +/** >>> + * struct kxsd9_transport - transport adapter for SPI or I2C >>> + * @trdev: transport device such as SPI or I2C >>> + * @readreg(): function to read a byte from an address in the device >>> + * @writereg(): function to write a byte to an address in the device >>> + * @write2(): function to write two consecutive bytes to the device >>> + * @readval(): function to read a 16bit value from the device >>> + * @rx: cache aligned read buffer >>> + * @tx: cache aligned write buffer >>> + */ >>> +struct kxsd9_transport { >>> + void *trdev; >>> + int (*readreg) (struct kxsd9_transport *tr, u8 address); >>> + int (*writereg) (struct kxsd9_transport *tr, u8 address, u8 val); >>> + int (*write2) (struct kxsd9_transport *tr, u8 b1, u8 b2); >>> + int (*readval) (struct kxsd9_transport *tr, u8 address); >>> + u8 rx[KXSD9_STATE_RX_SIZE] ____cacheline_aligned; >>> + u8 tx[KXSD9_STATE_TX_SIZE]; >>> +}; >>> + >>> +int kxsd9_common_probe(struct device *parent, >>> + struct kxsd9_transport *transport, >>> + const char *name); >>> +int kxsd9_common_remove(struct device *parent); >>> >> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-iio" in >> the body of a message to majordomo@xxxxxxxxxxxxxxx >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> > > -- > To unsubscribe from this list: send the line "unsubscribe linux-iio" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html