Commit bf96f6e8 authored by Linus Walleij's avatar Linus Walleij Committed by Jonathan Cameron

iio: accel: kxsd9: Split out SPI transport

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: default avatarLinus Walleij <linus.walleij@linaro.org>
Tested-by: default avatarJonathan Cameron <jic23@kernel.org>
Signed-off-by: default avatarJonathan Cameron <jic23@kernel.org>
parent 154021a3
...@@ -119,7 +119,6 @@ config IIO_ST_ACCEL_SPI_3AXIS ...@@ -119,7 +119,6 @@ config IIO_ST_ACCEL_SPI_3AXIS
config KXSD9 config KXSD9
tristate "Kionix KXSD9 Accelerometer Driver" tristate "Kionix KXSD9 Accelerometer Driver"
depends on SPI
help help
Say yes here to build support for the Kionix KXSD9 accelerometer. Say yes here to build support for the Kionix KXSD9 accelerometer.
Currently this only supports the device via an SPI interface. Currently this only supports the device via an SPI interface.
...@@ -127,6 +126,15 @@ config KXSD9 ...@@ -127,6 +126,15 @@ config KXSD9
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called kxsd9. 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 config KXCJK1013
tristate "Kionix 3-Axis Accelerometer Driver" tristate "Kionix 3-Axis Accelerometer Driver"
depends on I2C depends on I2C
......
...@@ -13,6 +13,7 @@ obj-$(CONFIG_DMARD09) += dmard09.o ...@@ -13,6 +13,7 @@ obj-$(CONFIG_DMARD09) += dmard09.o
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
obj-$(CONFIG_KXSD9) += kxsd9.o obj-$(CONFIG_KXSD9) += kxsd9.o
obj-$(CONFIG_KXSD9_SPI) += kxsd9-spi.o
obj-$(CONFIG_MMA7455) += mma7455_core.o obj-$(CONFIG_MMA7455) += mma7455_core.o
obj-$(CONFIG_MMA7455_I2C) += mma7455_i2c.o obj-$(CONFIG_MMA7455_I2C) += mma7455_i2c.o
......
#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@kernel.org>");
MODULE_DESCRIPTION("Kionix KXSD9 SPI driver");
MODULE_LICENSE("GPL v2");
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -26,6 +25,8 @@ ...@@ -26,6 +25,8 @@
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include "kxsd9.h"
#define KXSD9_REG_X 0x00 #define KXSD9_REG_X 0x00
#define KXSD9_REG_Y 0x02 #define KXSD9_REG_Y 0x02
#define KXSD9_REG_Z 0x04 #define KXSD9_REG_Z 0x04
...@@ -38,32 +39,6 @@ ...@@ -38,32 +39,6 @@
#define KXSD9_REG_CTRL_B 0x0d #define KXSD9_REG_CTRL_B 0x0d
#define KXSD9_REG_CTRL_A 0x0e #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 * struct kxsd9_state - device related storage
* @transport: transport for the KXSD9 * @transport: transport for the KXSD9
...@@ -98,11 +73,12 @@ static int kxsd9_write_scale(struct iio_dev *indio_dev, int micro) ...@@ -98,11 +73,12 @@ static int kxsd9_write_scale(struct iio_dev *indio_dev, int micro)
return -EINVAL; return -EINVAL;
mutex_lock(&st->buf_lock); mutex_lock(&st->buf_lock);
ret = st->transport->write1(st->transport, KXSD9_READ(KXSD9_REG_CTRL_C)); ret = st->transport->readreg(st->transport,
if (ret) KXSD9_REG_CTRL_C);
if (ret < 0)
goto error_ret; goto error_ret;
ret = st->transport->write2(st->transport, ret = st->transport->writereg(st->transport,
KXSD9_WRITE(KXSD9_REG_CTRL_C), KXSD9_REG_CTRL_C,
(ret & ~KXSD9_FS_MASK) | i); (ret & ~KXSD9_FS_MASK) | i);
error_ret: error_ret:
mutex_unlock(&st->buf_lock); mutex_unlock(&st->buf_lock);
...@@ -115,7 +91,9 @@ static int kxsd9_read(struct iio_dev *indio_dev, u8 address) ...@@ -115,7 +91,9 @@ static int kxsd9_read(struct iio_dev *indio_dev, u8 address)
struct kxsd9_state *st = iio_priv(indio_dev); struct kxsd9_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock); 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); mutex_unlock(&st->buf_lock);
return ret; return ret;
} }
...@@ -165,8 +143,9 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev, ...@@ -165,8 +143,9 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev,
ret = IIO_VAL_INT; ret = IIO_VAL_INT;
break; break;
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
ret = st->transport->write1(st->transport, KXSD9_READ(KXSD9_REG_CTRL_C)); ret = st->transport->readreg(st->transport,
if (ret) KXSD9_REG_CTRL_C);
if (ret < 0)
goto error_ret; goto error_ret;
*val = 0; *val = 0;
*val2 = kxsd9_micro_scales[ret & KXSD9_FS_MASK]; *val2 = kxsd9_micro_scales[ret & KXSD9_FS_MASK];
...@@ -218,7 +197,7 @@ static const struct iio_info kxsd9_info = { ...@@ -218,7 +197,7 @@ static const struct iio_info kxsd9_info = {
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
}; };
static int kxsd9_common_probe(struct device *parent, int kxsd9_common_probe(struct device *parent,
struct kxsd9_transport *transport, struct kxsd9_transport *transport,
const char *name) const char *name)
{ {
...@@ -251,8 +230,9 @@ static int kxsd9_common_probe(struct device *parent, ...@@ -251,8 +230,9 @@ static int kxsd9_common_probe(struct device *parent,
return 0; 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); struct iio_dev *indio_dev = dev_get_drvdata(parent);
...@@ -260,93 +240,8 @@ static int kxsd9_common_remove(struct device *parent) ...@@ -260,93 +240,8 @@ static int kxsd9_common_remove(struct device *parent)
return 0; return 0;
} }
EXPORT_SYMBOL(kxsd9_common_remove);
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);
MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
MODULE_DESCRIPTION("Kionix KXSD9 SPI driver"); MODULE_DESCRIPTION("Kionix KXSD9 driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
#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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment