aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/imu
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2012-11-20 08:36:00 -0500
committerJonathan Cameron <jic23@kernel.org>2012-11-20 16:26:37 -0500
commit484a0bf091c93c379e6524a17bb037c33c898e01 (patch)
treeb84cf4f38c21825bcfdcba02a23f5216680c69fb /drivers/iio/imu
parent9caed0d9d6db12cb6d81ba68d5bc98432d6b4711 (diff)
iio:imu:adis: Add paging support
Some of the newer generation devices from the ADIS16XXX series have more registers than what can be supported with the current register addressing scheme. These devices implement register paging to support a larger register range. Each page is 128 registers large and the currently active page can be selected via register 0x00 in each page. This patch implements transparent paging inside the common adis library. The register read/write interface stays the same and when a register is accessed the library automatically switches to the correct page if it is not already selected. The page number is encoded in the upper bits of the register number, e.g. register 0x5 of page 1 is 0x85. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio/imu')
-rw-r--r--drivers/iio/imu/adis.c70
-rw-r--r--drivers/iio/imu/adis_buffer.c15
2 files changed, 69 insertions, 16 deletions
diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
index 280a49584adf..c4ea04ffa60e 100644
--- a/drivers/iio/imu/adis.c
+++ b/drivers/iio/imu/adis.c
@@ -30,6 +30,7 @@
30int adis_write_reg(struct adis *adis, unsigned int reg, 30int adis_write_reg(struct adis *adis, unsigned int reg,
31 unsigned int value, unsigned int size) 31 unsigned int value, unsigned int size)
32{ 32{
33 unsigned int page = reg / ADIS_PAGE_SIZE;
33 int ret, i; 34 int ret, i;
34 struct spi_message msg; 35 struct spi_message msg;
35 struct spi_transfer xfers[] = { 36 struct spi_transfer xfers[] = {
@@ -56,39 +57,53 @@ int adis_write_reg(struct adis *adis, unsigned int reg,
56 .bits_per_word = 8, 57 .bits_per_word = 8,
57 .len = 2, 58 .len = 2,
58 .delay_usecs = adis->data->write_delay, 59 .delay_usecs = adis->data->write_delay,
60 }, {
61 .tx_buf = adis->tx + 8,
62 .bits_per_word = 8,
63 .len = 2,
64 .delay_usecs = adis->data->write_delay,
59 }, 65 },
60 }; 66 };
61 67
62 mutex_lock(&adis->txrx_lock); 68 mutex_lock(&adis->txrx_lock);
63 69
64 spi_message_init(&msg); 70 spi_message_init(&msg);
71
72 if (adis->current_page != page) {
73 adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
74 adis->tx[1] = page;
75 spi_message_add_tail(&xfers[0], &msg);
76 }
77
65 switch (size) { 78 switch (size) {
66 case 4: 79 case 4:
67 adis->tx[6] = ADIS_WRITE_REG(reg + 3); 80 adis->tx[8] = ADIS_WRITE_REG(reg + 3);
68 adis->tx[7] = (value >> 24) & 0xff; 81 adis->tx[9] = (value >> 24) & 0xff;
69 adis->tx[4] = ADIS_WRITE_REG(reg + 2); 82 adis->tx[6] = ADIS_WRITE_REG(reg + 2);
70 adis->tx[5] = (value >> 16) & 0xff; 83 adis->tx[7] = (value >> 16) & 0xff;
71 case 2: 84 case 2:
72 adis->tx[2] = ADIS_WRITE_REG(reg + 1); 85 adis->tx[4] = ADIS_WRITE_REG(reg + 1);
73 adis->tx[3] = (value >> 8) & 0xff; 86 adis->tx[5] = (value >> 8) & 0xff;
74 case 1: 87 case 1:
75 adis->tx[0] = ADIS_WRITE_REG(reg); 88 adis->tx[2] = ADIS_WRITE_REG(reg);
76 adis->tx[1] = value & 0xff; 89 adis->tx[3] = value & 0xff;
77 break; 90 break;
78 default: 91 default:
79 ret = -EINVAL; 92 ret = -EINVAL;
80 goto out_unlock; 93 goto out_unlock;
81 } 94 }
82 95
83 xfers[size - 1].cs_change = 0; 96 xfers[size].cs_change = 0;
84 97
85 for (i = 0; i < size; i++) 98 for (i = 1; i <= size; i++)
86 spi_message_add_tail(&xfers[i], &msg); 99 spi_message_add_tail(&xfers[i], &msg);
87 100
88 ret = spi_sync(adis->spi, &msg); 101 ret = spi_sync(adis->spi, &msg);
89 if (ret) { 102 if (ret) {
90 dev_err(&adis->spi->dev, "Failed to write register 0x%02X: %d\n", 103 dev_err(&adis->spi->dev, "Failed to write register 0x%02X: %d\n",
91 reg, ret); 104 reg, ret);
105 } else {
106 adis->current_page = page;
92 } 107 }
93 108
94out_unlock: 109out_unlock:
@@ -107,6 +122,7 @@ EXPORT_SYMBOL_GPL(adis_write_reg);
107int adis_read_reg(struct adis *adis, unsigned int reg, 122int adis_read_reg(struct adis *adis, unsigned int reg,
108 unsigned int *val, unsigned int size) 123 unsigned int *val, unsigned int size)
109{ 124{
125 unsigned int page = reg / ADIS_PAGE_SIZE;
110 struct spi_message msg; 126 struct spi_message msg;
111 int ret; 127 int ret;
112 struct spi_transfer xfers[] = { 128 struct spi_transfer xfers[] = {
@@ -115,9 +131,15 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
115 .bits_per_word = 8, 131 .bits_per_word = 8,
116 .len = 2, 132 .len = 2,
117 .cs_change = 1, 133 .cs_change = 1,
118 .delay_usecs = adis->data->read_delay, 134 .delay_usecs = adis->data->write_delay,
119 }, { 135 }, {
120 .tx_buf = adis->tx + 2, 136 .tx_buf = adis->tx + 2,
137 .bits_per_word = 8,
138 .len = 2,
139 .cs_change = 1,
140 .delay_usecs = adis->data->read_delay,
141 }, {
142 .tx_buf = adis->tx + 4,
121 .rx_buf = adis->rx, 143 .rx_buf = adis->rx,
122 .bits_per_word = 8, 144 .bits_per_word = 8,
123 .len = 2, 145 .len = 2,
@@ -134,16 +156,22 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
134 mutex_lock(&adis->txrx_lock); 156 mutex_lock(&adis->txrx_lock);
135 spi_message_init(&msg); 157 spi_message_init(&msg);
136 158
159 if (adis->current_page != page) {
160 adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
161 adis->tx[1] = page;
162 spi_message_add_tail(&xfers[0], &msg);
163 }
164
137 switch (size) { 165 switch (size) {
138 case 4: 166 case 4:
139 adis->tx[0] = ADIS_READ_REG(reg + 2); 167 adis->tx[2] = ADIS_READ_REG(reg + 2);
140 adis->tx[1] = 0;
141 spi_message_add_tail(&xfers[0], &msg);
142 case 2:
143 adis->tx[2] = ADIS_READ_REG(reg);
144 adis->tx[3] = 0; 168 adis->tx[3] = 0;
145 spi_message_add_tail(&xfers[1], &msg); 169 spi_message_add_tail(&xfers[1], &msg);
170 case 2:
171 adis->tx[4] = ADIS_READ_REG(reg);
172 adis->tx[5] = 0;
146 spi_message_add_tail(&xfers[2], &msg); 173 spi_message_add_tail(&xfers[2], &msg);
174 spi_message_add_tail(&xfers[3], &msg);
147 break; 175 break;
148 default: 176 default:
149 ret = -EINVAL; 177 ret = -EINVAL;
@@ -155,6 +183,8 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
155 dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n", 183 dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n",
156 reg, ret); 184 reg, ret);
157 goto out_unlock; 185 goto out_unlock;
186 } else {
187 adis->current_page = page;
158 } 188 }
159 189
160 switch (size) { 190 switch (size) {
@@ -390,6 +420,14 @@ int adis_init(struct adis *adis, struct iio_dev *indio_dev,
390 adis->data = data; 420 adis->data = data;
391 iio_device_set_drvdata(indio_dev, adis); 421 iio_device_set_drvdata(indio_dev, adis);
392 422
423 if (data->has_paging) {
424 /* Need to set the page before first read/write */
425 adis->current_page = -1;
426 } else {
427 /* Page will always be 0 */
428 adis->current_page = 0;
429 }
430
393 return adis_enable_irq(adis, false); 431 return adis_enable_irq(adis, false);
394} 432}
395EXPORT_SYMBOL_GPL(adis_init); 433EXPORT_SYMBOL_GPL(adis_init);
diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c
index 785713349e9f..99d8e0b0dd34 100644
--- a/drivers/iio/imu/adis_buffer.c
+++ b/drivers/iio/imu/adis_buffer.c
@@ -83,10 +83,25 @@ static irqreturn_t adis_trigger_handler(int irq, void *p)
83 if (!adis->buffer) 83 if (!adis->buffer)
84 return -ENOMEM; 84 return -ENOMEM;
85 85
86 if (adis->data->has_paging) {
87 mutex_lock(&adis->txrx_lock);
88 if (adis->current_page != 0) {
89 adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
90 adis->tx[1] = 0;
91 spi_write(adis->spi, adis->tx, 2);
92 }
93 }
94
86 ret = spi_sync(adis->spi, &adis->msg); 95 ret = spi_sync(adis->spi, &adis->msg);
87 if (ret) 96 if (ret)
88 dev_err(&adis->spi->dev, "Failed to read data: %d", ret); 97 dev_err(&adis->spi->dev, "Failed to read data: %d", ret);
89 98
99
100 if (adis->data->has_paging) {
101 adis->current_page = 0;
102 mutex_unlock(&adis->txrx_lock);
103 }
104
90 /* Guaranteed to be aligned with 8 byte boundary */ 105 /* Guaranteed to be aligned with 8 byte boundary */
91 if (indio_dev->scan_timestamp) { 106 if (indio_dev->scan_timestamp) {
92 void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64); 107 void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64);