Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9f907972 authored by Linus Walleij's avatar Linus Walleij Committed by Jonathan Cameron
Browse files

iio: accel: kxsd9: Split out transport mechanism



Split off a transport mechanism struct that will deal with the SPI
traffic in preparation for adding I2C support.

Tested-by: default avatarJonathan Cameron <jic23@kernel.org>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarJonathan Cameron <jic23@kernel.org>
parent 6841b2a0
Loading
Loading
Loading
Loading
+123 −52
Original line number Diff line number Diff line
@@ -43,18 +43,36 @@

#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
 * @buf_lock:	protect the rx and tx buffers.
 * @us:		spi device
 * @rx:		single rx buffer storage
 * @tx:		single tx buffer storage
 **/
struct kxsd9_state {
	struct kxsd9_transport *transport;
	struct mutex buf_lock;
	struct spi_device *us;
	u8 rx[KXSD9_STATE_RX_SIZE] ____cacheline_aligned;
	u8 tx[KXSD9_STATE_TX_SIZE];
};

#define KXSD9_SCALE_2G "0.011978"
@@ -80,13 +98,12 @@ static int kxsd9_write_scale(struct iio_dev *indio_dev, int micro)
		return -EINVAL;

	mutex_lock(&st->buf_lock);
	ret = spi_w8r8(st->us, KXSD9_READ(KXSD9_REG_CTRL_C));
	if (ret < 0)
	ret = st->transport->write1(st->transport, KXSD9_READ(KXSD9_REG_CTRL_C));
	if (ret)
		goto error_ret;
	st->tx[0] = KXSD9_WRITE(KXSD9_REG_CTRL_C);
	st->tx[1] = (ret & ~KXSD9_FS_MASK) | i;

	ret = spi_write(st->us, st->tx, 2);
	ret = st->transport->write2(st->transport,
				    KXSD9_WRITE(KXSD9_REG_CTRL_C),
				    (ret & ~KXSD9_FS_MASK) | i);
error_ret:
	mutex_unlock(&st->buf_lock);
	return ret;
@@ -96,24 +113,9 @@ static int kxsd9_read(struct iio_dev *indio_dev, u8 address)
{
	int ret;
	struct kxsd9_state *st = iio_priv(indio_dev);
	struct spi_transfer xfers[] = {
		{
			.bits_per_word = 8,
			.len = 1,
			.delay_usecs = 200,
			.tx_buf = st->tx,
		}, {
			.bits_per_word = 8,
			.len = 2,
			.rx_buf = st->rx,
		},
	};

	mutex_lock(&st->buf_lock);
	st->tx[0] = KXSD9_READ(address);
	ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
	if (!ret)
		ret = (((u16)(st->rx[0])) << 8) | (st->rx[1] & 0xF0);
	ret = st->transport->readval(st->transport, KXSD9_READ(address));
	mutex_unlock(&st->buf_lock);
	return ret;
}
@@ -163,8 +165,8 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev,
		ret = IIO_VAL_INT;
		break;
	case IIO_CHAN_INFO_SCALE:
		ret = spi_w8r8(st->us, KXSD9_READ(KXSD9_REG_CTRL_C));
		if (ret < 0)
		ret = st->transport->write1(st->transport, KXSD9_READ(KXSD9_REG_CTRL_C));
		if (ret)
			goto error_ret;
		*val = 0;
		*val2 = kxsd9_micro_scales[ret & KXSD9_FS_MASK];
@@ -203,15 +205,10 @@ static int kxsd9_power_up(struct kxsd9_state *st)
{
	int ret;

	st->tx[0] = 0x0d;
	st->tx[1] = 0x40;
	ret = spi_write(st->us, st->tx, 2);
	ret = st->transport->write2(st->transport, 0x0d, 0x40);
	if (ret)
		return ret;

	st->tx[0] = 0x0c;
	st->tx[1] = 0x9b;
	return spi_write(st->us, st->tx, 2);
	return st->transport->write2(st->transport, 0x0c, 0x9b);
};

static const struct iio_info kxsd9_info = {
@@ -221,56 +218,130 @@ static const struct iio_info kxsd9_info = {
	.driver_module = THIS_MODULE,
};

static int kxsd9_probe(struct spi_device *spi)
static int kxsd9_common_probe(struct device *parent,
			      struct kxsd9_transport *transport,
			      const char *name,
			      struct iio_dev **retdev)
{
	struct iio_dev *indio_dev;
	struct kxsd9_state *st;
	int ret;

	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
	indio_dev = devm_iio_device_alloc(parent, sizeof(*st));
	if (!indio_dev)
		return -ENOMEM;

	st = iio_priv(indio_dev);
	spi_set_drvdata(spi, indio_dev);
	st->transport = transport;

	st->us = spi;
	mutex_init(&st->buf_lock);
	indio_dev->channels = kxsd9_channels;
	indio_dev->num_channels = ARRAY_SIZE(kxsd9_channels);
	indio_dev->name = spi_get_device_id(spi)->name;
	indio_dev->dev.parent = &spi->dev;
	indio_dev->name = name;
	indio_dev->dev.parent = parent;
	indio_dev->info = &kxsd9_info;
	indio_dev->modes = INDIO_DIRECT_MODE;

	kxsd9_power_up(st);

	ret = iio_device_register(indio_dev);
	if (ret)
		return ret;

	*retdev = indio_dev;
	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;
	struct iio_dev *indio_dev;
	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);
	kxsd9_power_up(st);

	return iio_device_register(indio_dev);
	ret = kxsd9_common_probe(&spi->dev,
				 transport,
				 spi_get_device_id(spi)->name,
				 &indio_dev);
	if (ret)
		return ret;

	spi_set_drvdata(spi, indio_dev);
	return 0;
}

static int kxsd9_remove(struct spi_device *spi)
static int kxsd9_spi_remove(struct spi_device *spi)
{
	iio_device_unregister(spi_get_drvdata(spi));

	return 0;
}

static const struct spi_device_id kxsd9_id[] = {
static const struct spi_device_id kxsd9_spi_id[] = {
	{"kxsd9", 0},
	{ },
};
MODULE_DEVICE_TABLE(spi, kxsd9_id);
MODULE_DEVICE_TABLE(spi, kxsd9_spi_id);

static struct spi_driver kxsd9_driver = {
static struct spi_driver kxsd9_spi_driver = {
	.driver = {
		.name = "kxsd9",
	},
	.probe = kxsd9_probe,
	.remove = kxsd9_remove,
	.id_table = kxsd9_id,
	.probe = kxsd9_spi_probe,
	.remove = kxsd9_spi_remove,
	.id_table = kxsd9_spi_id,
};
module_spi_driver(kxsd9_driver);
module_spi_driver(kxsd9_spi_driver);

MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
MODULE_DESCRIPTION("Kionix KXSD9 SPI driver");