Commit b9a063a1654653348161de8d3d411d8ce2f56856
1 parent
d5b52b5992
Exists in
v3.2_SMARCT335xPSP_04.06.00.11
and in
3 other branches
IIO: ti_adc: Enabling of IRQ for continuous mode
Since IRQ is a part of continuous mode feature, Enabling should also take place when continuous data is asked for. In default mode ADC is configured as one shot, IRQ need not be enabled if one wants to use one shot mode only. Signed-off-by: Patil, Rachna <rachna@ti.com>
Showing 1 changed file with 6 additions and 8 deletions Inline Diff
drivers/staging/iio/adc/ti_adc.c
1 | /* | 1 | /* |
2 | * TI ADC MFD driver | 2 | * TI ADC MFD driver |
3 | * | 3 | * |
4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ | 4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License as | 7 | * modify it under the terms of the GNU General Public License as |
8 | * published by the Free Software Foundation version 2. | 8 | * published by the Free Software Foundation version 2. |
9 | * | 9 | * |
10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | 10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any |
11 | * kind, whether express or implied; without even the implied warranty | 11 | * kind, whether express or implied; without even the implied warranty |
12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/sched.h> | 24 | #include <linux/sched.h> |
25 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
26 | 26 | ||
27 | #include "../iio.h" | 27 | #include "../iio.h" |
28 | #include "../sysfs.h" | 28 | #include "../sysfs.h" |
29 | #include "../buffer_generic.h" | 29 | #include "../buffer_generic.h" |
30 | #include "../ring_sw.h" | 30 | #include "../ring_sw.h" |
31 | 31 | ||
32 | #include <linux/mfd/ti_tscadc.h> | 32 | #include <linux/mfd/ti_tscadc.h> |
33 | #include <linux/platform_data/ti_adc.h> | 33 | #include <linux/platform_data/ti_adc.h> |
34 | 34 | ||
35 | struct adc_device { | 35 | struct adc_device { |
36 | struct ti_tscadc_dev *mfd_tscadc; | 36 | struct ti_tscadc_dev *mfd_tscadc; |
37 | struct iio_dev *idev; | 37 | struct iio_dev *idev; |
38 | struct work_struct poll_work; | 38 | struct work_struct poll_work; |
39 | wait_queue_head_t wq_data_avail; | 39 | wait_queue_head_t wq_data_avail; |
40 | int channels; | 40 | int channels; |
41 | int irq; | 41 | int irq; |
42 | bool is_continuous_mode; | 42 | bool is_continuous_mode; |
43 | u16 *buffer; | 43 | u16 *buffer; |
44 | }; | 44 | }; |
45 | 45 | ||
46 | static unsigned int adc_readl(struct adc_device *adc, unsigned int reg) | 46 | static unsigned int adc_readl(struct adc_device *adc, unsigned int reg) |
47 | { | 47 | { |
48 | return readl(adc->mfd_tscadc->tscadc_base + reg); | 48 | return readl(adc->mfd_tscadc->tscadc_base + reg); |
49 | } | 49 | } |
50 | 50 | ||
51 | static void adc_writel(struct adc_device *adc, unsigned int reg, | 51 | static void adc_writel(struct adc_device *adc, unsigned int reg, |
52 | unsigned int val) | 52 | unsigned int val) |
53 | { | 53 | { |
54 | writel(val, adc->mfd_tscadc->tscadc_base + reg); | 54 | writel(val, adc->mfd_tscadc->tscadc_base + reg); |
55 | } | 55 | } |
56 | 56 | ||
57 | static void adc_step_config(struct adc_device *adc_dev) | 57 | static void adc_step_config(struct adc_device *adc_dev) |
58 | { | 58 | { |
59 | unsigned int stepconfig; | 59 | unsigned int stepconfig; |
60 | int i, channels = 0, steps; | 60 | int i, channels = 0, steps; |
61 | 61 | ||
62 | /* | 62 | /* |
63 | * There are 16 configurable steps and 8 analog input | 63 | * There are 16 configurable steps and 8 analog input |
64 | * lines available which are shared between Touchscreen and ADC. | 64 | * lines available which are shared between Touchscreen and ADC. |
65 | * | 65 | * |
66 | * Steps backwards i.e. from 16 towards 0 are used by ADC | 66 | * Steps backwards i.e. from 16 towards 0 are used by ADC |
67 | * depending on number of input lines needed. | 67 | * depending on number of input lines needed. |
68 | * Channel would represent which analog input | 68 | * Channel would represent which analog input |
69 | * needs to be given to ADC to digitalize data. | 69 | * needs to be given to ADC to digitalize data. |
70 | */ | 70 | */ |
71 | 71 | ||
72 | steps = TOTAL_STEPS - adc_dev->channels; | 72 | steps = TOTAL_STEPS - adc_dev->channels; |
73 | channels = TOTAL_CHANNELS - adc_dev->channels; | 73 | channels = TOTAL_CHANNELS - adc_dev->channels; |
74 | 74 | ||
75 | stepconfig = TSCADC_STEPCONFIG_AVG_16 | TSCADC_STEPCONFIG_FIFO1; | 75 | stepconfig = TSCADC_STEPCONFIG_AVG_16 | TSCADC_STEPCONFIG_FIFO1; |
76 | 76 | ||
77 | for (i = (steps + 1); i <= TOTAL_STEPS; i++) { | 77 | for (i = (steps + 1); i <= TOTAL_STEPS; i++) { |
78 | adc_writel(adc_dev, TSCADC_REG_STEPCONFIG(i), | 78 | adc_writel(adc_dev, TSCADC_REG_STEPCONFIG(i), |
79 | stepconfig | TSCADC_STEPCONFIG_INP(channels)); | 79 | stepconfig | TSCADC_STEPCONFIG_INP(channels)); |
80 | adc_writel(adc_dev, TSCADC_REG_STEPDELAY(i), | 80 | adc_writel(adc_dev, TSCADC_REG_STEPDELAY(i), |
81 | TSCADC_STEPCONFIG_OPENDLY); | 81 | TSCADC_STEPCONFIG_OPENDLY); |
82 | channels++; | 82 | channels++; |
83 | } | 83 | } |
84 | } | 84 | } |
85 | 85 | ||
86 | static ssize_t tiadc_show_mode(struct device *dev, | 86 | static ssize_t tiadc_show_mode(struct device *dev, |
87 | struct device_attribute *attr, char *buf) | 87 | struct device_attribute *attr, char *buf) |
88 | { | 88 | { |
89 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | 89 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
90 | struct adc_device *adc_dev = iio_priv(indio_dev); | 90 | struct adc_device *adc_dev = iio_priv(indio_dev); |
91 | unsigned int tmp; | 91 | unsigned int tmp; |
92 | 92 | ||
93 | tmp = adc_readl(adc_dev, TSCADC_REG_STEPCONFIG(TOTAL_STEPS)); | 93 | tmp = adc_readl(adc_dev, TSCADC_REG_STEPCONFIG(TOTAL_STEPS)); |
94 | tmp &= TSCADC_STEPCONFIG_MODE(1); | 94 | tmp &= TSCADC_STEPCONFIG_MODE(1); |
95 | 95 | ||
96 | if (tmp == 0x00) | 96 | if (tmp == 0x00) |
97 | return sprintf(buf, "oneshot\n"); | 97 | return sprintf(buf, "oneshot\n"); |
98 | else if (tmp == 0x01) | 98 | else if (tmp == 0x01) |
99 | return sprintf(buf, "continuous\n"); | 99 | return sprintf(buf, "continuous\n"); |
100 | else | 100 | else |
101 | return sprintf(buf, "Operation mode unknown\n"); | 101 | return sprintf(buf, "Operation mode unknown\n"); |
102 | } | 102 | } |
103 | 103 | ||
104 | static ssize_t tiadc_set_mode(struct device *dev, | 104 | static ssize_t tiadc_set_mode(struct device *dev, |
105 | struct device_attribute *attr, const char *buf, size_t count) | 105 | struct device_attribute *attr, const char *buf, size_t count) |
106 | { | 106 | { |
107 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | 107 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
108 | struct adc_device *adc_dev = iio_priv(indio_dev); | 108 | struct adc_device *adc_dev = iio_priv(indio_dev); |
109 | int i, channels = 0, steps; | 109 | int i, channels = 0, steps; |
110 | unsigned int stepconfig, config; | 110 | unsigned int stepconfig, config; |
111 | 111 | ||
112 | steps = (TOTAL_STEPS - adc_dev->channels) + 1; | 112 | steps = (TOTAL_STEPS - adc_dev->channels) + 1; |
113 | channels = TOTAL_CHANNELS - adc_dev->channels; | 113 | channels = TOTAL_CHANNELS - adc_dev->channels; |
114 | 114 | ||
115 | config = adc_readl(adc_dev, TSCADC_REG_CTRL); | 115 | config = adc_readl(adc_dev, TSCADC_REG_CTRL); |
116 | config &= ~(TSCADC_CNTRLREG_TSCSSENB); | 116 | config &= ~(TSCADC_CNTRLREG_TSCSSENB); |
117 | adc_writel(adc_dev, TSCADC_REG_CTRL, config); | 117 | adc_writel(adc_dev, TSCADC_REG_CTRL, config); |
118 | 118 | ||
119 | stepconfig = adc_readl(adc_dev, TSCADC_REG_STEPCONFIG(steps)); | 119 | stepconfig = adc_readl(adc_dev, TSCADC_REG_STEPCONFIG(steps)); |
120 | 120 | ||
121 | for (i = steps; i <= TOTAL_STEPS; i++) { | 121 | for (i = steps; i <= TOTAL_STEPS; i++) { |
122 | if (!strncmp(buf, "oneshot", 7)) { | 122 | if (!strncmp(buf, "oneshot", 7)) { |
123 | stepconfig &= ~(TSCADC_STEPCONFIG_MODE_SWCNT); | 123 | stepconfig &= ~(TSCADC_STEPCONFIG_MODE_SWCNT); |
124 | adc_writel(adc_dev, TSCADC_REG_STEPCONFIG(i), | 124 | adc_writel(adc_dev, TSCADC_REG_STEPCONFIG(i), |
125 | stepconfig); | 125 | stepconfig); |
126 | adc_dev->is_continuous_mode = false; | 126 | adc_dev->is_continuous_mode = false; |
127 | } else if (!strncmp(buf, "continuous", 10)) { | 127 | } else if (!strncmp(buf, "continuous", 10)) { |
128 | adc_writel(adc_dev, TSCADC_REG_STEPCONFIG(i), | 128 | adc_writel(adc_dev, TSCADC_REG_STEPCONFIG(i), |
129 | stepconfig | TSCADC_STEPCONFIG_MODE_SWCNT); | 129 | stepconfig | TSCADC_STEPCONFIG_MODE_SWCNT); |
130 | adc_dev->is_continuous_mode = true; | 130 | adc_dev->is_continuous_mode = true; |
131 | } | 131 | } |
132 | } | 132 | } |
133 | 133 | ||
134 | config = adc_readl(adc_dev, TSCADC_REG_CTRL); | 134 | config = adc_readl(adc_dev, TSCADC_REG_CTRL); |
135 | adc_writel(adc_dev, TSCADC_REG_CTRL, | 135 | adc_writel(adc_dev, TSCADC_REG_CTRL, |
136 | (config | TSCADC_CNTRLREG_TSCSSENB)); | 136 | (config | TSCADC_CNTRLREG_TSCSSENB)); |
137 | return count; | 137 | return count; |
138 | } | 138 | } |
139 | 139 | ||
140 | static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, tiadc_show_mode, | 140 | static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, tiadc_show_mode, |
141 | tiadc_set_mode, 0); | 141 | tiadc_set_mode, 0); |
142 | 142 | ||
143 | static struct attribute *tiadc_attributes[] = { | 143 | static struct attribute *tiadc_attributes[] = { |
144 | &iio_dev_attr_mode.dev_attr.attr, | 144 | &iio_dev_attr_mode.dev_attr.attr, |
145 | NULL, | 145 | NULL, |
146 | }; | 146 | }; |
147 | 147 | ||
148 | static const struct attribute_group tiadc_attribute_group = { | 148 | static const struct attribute_group tiadc_attribute_group = { |
149 | .attrs = tiadc_attributes, | 149 | .attrs = tiadc_attributes, |
150 | }; | 150 | }; |
151 | 151 | ||
152 | static irqreturn_t tiadc_irq(int irq, void *private) | 152 | static irqreturn_t tiadc_irq(int irq, void *private) |
153 | { | 153 | { |
154 | struct iio_dev *idev = private; | 154 | struct iio_dev *idev = private; |
155 | struct adc_device *adc_dev = iio_priv(idev); | 155 | struct adc_device *adc_dev = iio_priv(idev); |
156 | unsigned int status, fifo1count, config; | 156 | unsigned int status, fifo1count, config; |
157 | 157 | ||
158 | status = adc_readl(adc_dev, TSCADC_REG_IRQSTATUS); | 158 | status = adc_readl(adc_dev, TSCADC_REG_IRQSTATUS); |
159 | if (status & TSCADC_IRQENB_FIFO1THRES) { | 159 | if (status & TSCADC_IRQENB_FIFO1THRES) { |
160 | fifo1count = adc_readl(adc_dev, TSCADC_REG_FIFO1CNT); | 160 | fifo1count = adc_readl(adc_dev, TSCADC_REG_FIFO1CNT); |
161 | adc_writel(adc_dev, TSCADC_REG_IRQCLR, | 161 | adc_writel(adc_dev, TSCADC_REG_IRQCLR, |
162 | TSCADC_IRQENB_FIFO1THRES); | 162 | TSCADC_IRQENB_FIFO1THRES); |
163 | 163 | ||
164 | if (iio_buffer_enabled(idev)) { | 164 | if (iio_buffer_enabled(idev)) { |
165 | if (!work_pending(&adc_dev->poll_work)) | 165 | if (!work_pending(&adc_dev->poll_work)) |
166 | schedule_work(&adc_dev->poll_work); | 166 | schedule_work(&adc_dev->poll_work); |
167 | } else { | 167 | } else { |
168 | wake_up_interruptible(&adc_dev->wq_data_avail); | 168 | wake_up_interruptible(&adc_dev->wq_data_avail); |
169 | } | 169 | } |
170 | adc_writel(adc_dev, TSCADC_REG_IRQSTATUS, | 170 | adc_writel(adc_dev, TSCADC_REG_IRQSTATUS, |
171 | (status | TSCADC_IRQENB_FIFO1THRES)); | 171 | (status | TSCADC_IRQENB_FIFO1THRES)); |
172 | return IRQ_HANDLED; | 172 | return IRQ_HANDLED; |
173 | } else if ((status & TSCADC_IRQENB_FIFO1OVRRUN) || | 173 | } else if ((status & TSCADC_IRQENB_FIFO1OVRRUN) || |
174 | (status & TSCADC_IRQENB_FIFO1UNDRFLW)) { | 174 | (status & TSCADC_IRQENB_FIFO1UNDRFLW)) { |
175 | config = adc_readl(adc_dev, TSCADC_REG_CTRL); | 175 | config = adc_readl(adc_dev, TSCADC_REG_CTRL); |
176 | config &= ~(TSCADC_CNTRLREG_TSCSSENB); | 176 | config &= ~(TSCADC_CNTRLREG_TSCSSENB); |
177 | adc_writel(adc_dev, TSCADC_REG_CTRL, config); | 177 | adc_writel(adc_dev, TSCADC_REG_CTRL, config); |
178 | 178 | ||
179 | if (status & TSCADC_IRQENB_FIFO1UNDRFLW) | 179 | if (status & TSCADC_IRQENB_FIFO1UNDRFLW) |
180 | adc_writel(adc_dev, TSCADC_REG_IRQSTATUS, | 180 | adc_writel(adc_dev, TSCADC_REG_IRQSTATUS, |
181 | (status | TSCADC_IRQENB_FIFO1UNDRFLW)); | 181 | (status | TSCADC_IRQENB_FIFO1UNDRFLW)); |
182 | else | 182 | else |
183 | adc_writel(adc_dev, TSCADC_REG_IRQSTATUS, | 183 | adc_writel(adc_dev, TSCADC_REG_IRQSTATUS, |
184 | (status | TSCADC_IRQENB_FIFO1OVRRUN)); | 184 | (status | TSCADC_IRQENB_FIFO1OVRRUN)); |
185 | 185 | ||
186 | adc_writel(adc_dev, TSCADC_REG_CTRL, | 186 | adc_writel(adc_dev, TSCADC_REG_CTRL, |
187 | (config | TSCADC_CNTRLREG_TSCSSENB)); | 187 | (config | TSCADC_CNTRLREG_TSCSSENB)); |
188 | return IRQ_HANDLED; | 188 | return IRQ_HANDLED; |
189 | } else { | 189 | } else { |
190 | return IRQ_NONE; | 190 | return IRQ_NONE; |
191 | } | 191 | } |
192 | } | 192 | } |
193 | 193 | ||
194 | static void tiadc_poll_handler(struct work_struct *work_s) | 194 | static void tiadc_poll_handler(struct work_struct *work_s) |
195 | { | 195 | { |
196 | struct adc_device *adc_dev = | 196 | struct adc_device *adc_dev = |
197 | container_of(work_s, struct adc_device, poll_work); | 197 | container_of(work_s, struct adc_device, poll_work); |
198 | struct iio_dev *idev = iio_priv_to_dev(adc_dev); | 198 | struct iio_dev *idev = iio_priv_to_dev(adc_dev); |
199 | struct iio_buffer *buffer = idev->buffer; | 199 | struct iio_buffer *buffer = idev->buffer; |
200 | unsigned int fifo1count, readx1, status; | 200 | unsigned int fifo1count, readx1, status; |
201 | int i; | 201 | int i; |
202 | u32 *iBuf; | 202 | u32 *iBuf; |
203 | 203 | ||
204 | fifo1count = adc_readl(adc_dev, TSCADC_REG_FIFO1CNT); | 204 | fifo1count = adc_readl(adc_dev, TSCADC_REG_FIFO1CNT); |
205 | iBuf = kmalloc((fifo1count + 1) * sizeof(u32), GFP_KERNEL); | 205 | iBuf = kmalloc((fifo1count + 1) * sizeof(u32), GFP_KERNEL); |
206 | if (iBuf == NULL) | 206 | if (iBuf == NULL) |
207 | return; | 207 | return; |
208 | 208 | ||
209 | /* | 209 | /* |
210 | * Wait for ADC sequencer to settle down. | 210 | * Wait for ADC sequencer to settle down. |
211 | * There could be a scenario where in we | 211 | * There could be a scenario where in we |
212 | * try to read data from ADC before | 212 | * try to read data from ADC before |
213 | * it is available. | 213 | * it is available. |
214 | */ | 214 | */ |
215 | udelay(500); | 215 | udelay(500); |
216 | 216 | ||
217 | for (i = 0; i < fifo1count; i++) { | 217 | for (i = 0; i < fifo1count; i++) { |
218 | readx1 = adc_readl(adc_dev, TSCADC_REG_FIFO1); | 218 | readx1 = adc_readl(adc_dev, TSCADC_REG_FIFO1); |
219 | readx1 &= TSCADC_FIFOREAD_DATA_MASK; | 219 | readx1 &= TSCADC_FIFOREAD_DATA_MASK; |
220 | iBuf[i] = readx1; | 220 | iBuf[i] = readx1; |
221 | } | 221 | } |
222 | 222 | ||
223 | buffer->access->store_to(buffer, (u8 *) iBuf, iio_get_time_ns()); | 223 | buffer->access->store_to(buffer, (u8 *) iBuf, iio_get_time_ns()); |
224 | status = adc_readl(adc_dev, TSCADC_REG_IRQENABLE); | 224 | status = adc_readl(adc_dev, TSCADC_REG_IRQENABLE); |
225 | adc_writel(adc_dev, TSCADC_REG_IRQENABLE, | 225 | adc_writel(adc_dev, TSCADC_REG_IRQENABLE, |
226 | (status | TSCADC_IRQENB_FIFO1THRES)); | 226 | (status | TSCADC_IRQENB_FIFO1THRES)); |
227 | 227 | ||
228 | kfree(iBuf); | 228 | kfree(iBuf); |
229 | } | 229 | } |
230 | 230 | ||
231 | static int tiadc_buffer_preenable(struct iio_dev *idev) | 231 | static int tiadc_buffer_preenable(struct iio_dev *idev) |
232 | { | 232 | { |
233 | struct iio_buffer *buffer = idev->buffer; | 233 | struct iio_buffer *buffer = idev->buffer; |
234 | 234 | ||
235 | buffer->access->set_bytes_per_datum(buffer, 16); | 235 | buffer->access->set_bytes_per_datum(buffer, 16); |
236 | return 0; | 236 | return 0; |
237 | } | 237 | } |
238 | 238 | ||
239 | static int tiadc_buffer_postenable(struct iio_dev *idev) | 239 | static int tiadc_buffer_postenable(struct iio_dev *idev) |
240 | { | 240 | { |
241 | struct adc_device *adc_dev = iio_priv(idev); | 241 | struct adc_device *adc_dev = iio_priv(idev); |
242 | struct iio_buffer *buffer = idev->buffer; | 242 | struct iio_buffer *buffer = idev->buffer; |
243 | unsigned int enb, status, fifo1count; | 243 | unsigned int enb, status, fifo1count; |
244 | int stepnum, i; | 244 | int stepnum, i; |
245 | u8 bit; | 245 | u8 bit; |
246 | 246 | ||
247 | if (!adc_dev->is_continuous_mode) { | 247 | if (!adc_dev->is_continuous_mode) { |
248 | pr_info("Data cannot be read continuously in one shot mode\n"); | 248 | pr_info("Data cannot be read continuously in one shot mode\n"); |
249 | return -EINVAL; | 249 | return -EINVAL; |
250 | } else { | 250 | } else { |
251 | status = adc_readl(adc_dev, TSCADC_REG_IRQENABLE); | 251 | status = adc_readl(adc_dev, TSCADC_REG_IRQENABLE); |
252 | adc_writel(adc_dev, TSCADC_REG_IRQENABLE, | 252 | adc_writel(adc_dev, TSCADC_REG_IRQENABLE, |
253 | (status | TSCADC_IRQENB_FIFO1THRES)); | 253 | (status | TSCADC_IRQENB_FIFO1THRES | |
254 | TSCADC_IRQENB_FIFO1OVRRUN | | ||
255 | TSCADC_IRQENB_FIFO1UNDRFLW)); | ||
254 | 256 | ||
255 | fifo1count = adc_readl(adc_dev, TSCADC_REG_FIFO1CNT); | 257 | fifo1count = adc_readl(adc_dev, TSCADC_REG_FIFO1CNT); |
256 | for (i = 0; i < fifo1count; i++) | 258 | for (i = 0; i < fifo1count; i++) |
257 | adc_readl(adc_dev, TSCADC_REG_FIFO1); | 259 | adc_readl(adc_dev, TSCADC_REG_FIFO1); |
258 | 260 | ||
259 | adc_writel(adc_dev, TSCADC_REG_SE, 0x00); | 261 | adc_writel(adc_dev, TSCADC_REG_SE, 0x00); |
260 | for_each_set_bit(bit, buffer->scan_mask, | 262 | for_each_set_bit(bit, buffer->scan_mask, |
261 | adc_dev->channels) { | 263 | adc_dev->channels) { |
262 | struct iio_chan_spec const *chan = idev->channels + bit; | 264 | struct iio_chan_spec const *chan = idev->channels + bit; |
263 | /* | 265 | /* |
264 | * There are a total of 16 steps available | 266 | * There are a total of 16 steps available |
265 | * that are shared between ADC and touchscreen. | 267 | * that are shared between ADC and touchscreen. |
266 | * We start configuring from step 16 to 0 incase of | 268 | * We start configuring from step 16 to 0 incase of |
267 | * ADC. Hence the relation between input channel | 269 | * ADC. Hence the relation between input channel |
268 | * and step for ADC would be as below. | 270 | * and step for ADC would be as below. |
269 | */ | 271 | */ |
270 | stepnum = chan->channel + 9; | 272 | stepnum = chan->channel + 9; |
271 | enb = adc_readl(adc_dev, TSCADC_REG_SE); | 273 | enb = adc_readl(adc_dev, TSCADC_REG_SE); |
272 | enb |= stepnum; | 274 | enb |= stepnum; |
273 | adc_writel(adc_dev, TSCADC_REG_SE, TSCADC_ENB(enb)); | 275 | adc_writel(adc_dev, TSCADC_REG_SE, TSCADC_ENB(enb)); |
274 | } | 276 | } |
275 | return 0; | 277 | return 0; |
276 | } | 278 | } |
277 | } | 279 | } |
278 | 280 | ||
279 | static int tiadc_buffer_postdisable(struct iio_dev *idev) | 281 | static int tiadc_buffer_postdisable(struct iio_dev *idev) |
280 | { | 282 | { |
281 | struct adc_device *adc_dev = iio_priv(idev); | 283 | struct adc_device *adc_dev = iio_priv(idev); |
282 | 284 | ||
283 | adc_writel(adc_dev, TSCADC_REG_IRQCLR, TSCADC_IRQENB_FIFO1THRES); | 285 | adc_writel(adc_dev, TSCADC_REG_IRQCLR, (TSCADC_IRQENB_FIFO1THRES | |
286 | TSCADC_IRQENB_FIFO1OVRRUN | | ||
287 | TSCADC_IRQENB_FIFO1UNDRFLW)); | ||
284 | adc_writel(adc_dev, TSCADC_REG_SE, TSCADC_STPENB_STEPENB_TC); | 288 | adc_writel(adc_dev, TSCADC_REG_SE, TSCADC_STPENB_STEPENB_TC); |
285 | return 0; | 289 | return 0; |
286 | } | 290 | } |
287 | 291 | ||
288 | static const struct iio_buffer_setup_ops tiadc_swring_setup_ops = { | 292 | static const struct iio_buffer_setup_ops tiadc_swring_setup_ops = { |
289 | .preenable = &tiadc_buffer_preenable, | 293 | .preenable = &tiadc_buffer_preenable, |
290 | .postenable = &tiadc_buffer_postenable, | 294 | .postenable = &tiadc_buffer_postenable, |
291 | .postdisable = &tiadc_buffer_postdisable, | 295 | .postdisable = &tiadc_buffer_postdisable, |
292 | }; | 296 | }; |
293 | 297 | ||
294 | static int tiadc_config_sw_ring(struct iio_dev *idev) | 298 | static int tiadc_config_sw_ring(struct iio_dev *idev) |
295 | { | 299 | { |
296 | struct adc_device *adc_dev = iio_priv(idev); | 300 | struct adc_device *adc_dev = iio_priv(idev); |
297 | int ret; | 301 | int ret; |
298 | 302 | ||
299 | idev->buffer = iio_sw_rb_allocate(idev); | 303 | idev->buffer = iio_sw_rb_allocate(idev); |
300 | if (!idev->buffer) | 304 | if (!idev->buffer) |
301 | ret = -ENOMEM; | 305 | ret = -ENOMEM; |
302 | 306 | ||
303 | idev->buffer->access = &ring_sw_access_funcs; | 307 | idev->buffer->access = &ring_sw_access_funcs; |
304 | idev->buffer->setup_ops = &tiadc_swring_setup_ops; | 308 | idev->buffer->setup_ops = &tiadc_swring_setup_ops; |
305 | 309 | ||
306 | INIT_WORK(&adc_dev->poll_work, &tiadc_poll_handler); | 310 | INIT_WORK(&adc_dev->poll_work, &tiadc_poll_handler); |
307 | 311 | ||
308 | idev->modes |= INDIO_BUFFER_HARDWARE; | 312 | idev->modes |= INDIO_BUFFER_HARDWARE; |
309 | return 0; | 313 | return 0; |
310 | } | 314 | } |
311 | 315 | ||
312 | static int tiadc_channel_init(struct iio_dev *idev, struct adc_device *adc_dev) | 316 | static int tiadc_channel_init(struct iio_dev *idev, struct adc_device *adc_dev) |
313 | { | 317 | { |
314 | struct iio_chan_spec *chan_array; | 318 | struct iio_chan_spec *chan_array; |
315 | int i, channels; | 319 | int i, channels; |
316 | 320 | ||
317 | idev->num_channels = adc_dev->channels; | 321 | idev->num_channels = adc_dev->channels; |
318 | chan_array = kcalloc(idev->num_channels, sizeof(struct iio_chan_spec), | 322 | chan_array = kcalloc(idev->num_channels, sizeof(struct iio_chan_spec), |
319 | GFP_KERNEL); | 323 | GFP_KERNEL); |
320 | 324 | ||
321 | if (chan_array == NULL) | 325 | if (chan_array == NULL) |
322 | return -ENOMEM; | 326 | return -ENOMEM; |
323 | 327 | ||
324 | channels = TOTAL_CHANNELS - adc_dev->channels; | 328 | channels = TOTAL_CHANNELS - adc_dev->channels; |
325 | for (i = 0; i < (idev->num_channels); i++) { | 329 | for (i = 0; i < (idev->num_channels); i++) { |
326 | struct iio_chan_spec *chan = chan_array + i; | 330 | struct iio_chan_spec *chan = chan_array + i; |
327 | chan->type = IIO_VOLTAGE; | 331 | chan->type = IIO_VOLTAGE; |
328 | chan->indexed = 1; | 332 | chan->indexed = 1; |
329 | chan->channel = channels; | 333 | chan->channel = channels; |
330 | chan->scan_index = i; | 334 | chan->scan_index = i; |
331 | chan->scan_type.sign = 'u'; | 335 | chan->scan_type.sign = 'u'; |
332 | chan->scan_type.realbits = 12; | 336 | chan->scan_type.realbits = 12; |
333 | chan->scan_type.storagebits = 32; | 337 | chan->scan_type.storagebits = 32; |
334 | chan->scan_type.shift = 0; | 338 | chan->scan_type.shift = 0; |
335 | channels++; | 339 | channels++; |
336 | } | 340 | } |
337 | 341 | ||
338 | idev->channels = chan_array; | 342 | idev->channels = chan_array; |
339 | return idev->num_channels; | 343 | return idev->num_channels; |
340 | } | 344 | } |
341 | 345 | ||
342 | static void tiadc_channel_remove(struct iio_dev *idev) | 346 | static void tiadc_channel_remove(struct iio_dev *idev) |
343 | { | 347 | { |
344 | kfree(idev->channels); | 348 | kfree(idev->channels); |
345 | } | 349 | } |
346 | 350 | ||
347 | static int tiadc_read_raw(struct iio_dev *idev, | 351 | static int tiadc_read_raw(struct iio_dev *idev, |
348 | struct iio_chan_spec const *chan, | 352 | struct iio_chan_spec const *chan, |
349 | int *val, int *val2, long mask) | 353 | int *val, int *val2, long mask) |
350 | { | 354 | { |
351 | struct adc_device *adc_dev = iio_priv(idev); | 355 | struct adc_device *adc_dev = iio_priv(idev); |
352 | int i, map_val; | 356 | int i, map_val; |
353 | unsigned int fifo1count, readx1, stepid; | 357 | unsigned int fifo1count, readx1, stepid; |
354 | unsigned long timeout = jiffies + usecs_to_jiffies | 358 | unsigned long timeout = jiffies + usecs_to_jiffies |
355 | (IDLE_TIMEOUT * adc_dev->channels); | 359 | (IDLE_TIMEOUT * adc_dev->channels); |
356 | 360 | ||
357 | if (adc_dev->is_continuous_mode) { | 361 | if (adc_dev->is_continuous_mode) { |
358 | pr_info("One shot mode not enabled\n"); | 362 | pr_info("One shot mode not enabled\n"); |
359 | return -EINVAL; | 363 | return -EINVAL; |
360 | } else { | 364 | } else { |
361 | adc_writel(adc_dev, TSCADC_REG_SE, TSCADC_STPENB_STEPENB); | 365 | adc_writel(adc_dev, TSCADC_REG_SE, TSCADC_STPENB_STEPENB); |
362 | 366 | ||
363 | /* Wait for ADC sequencer to complete sampling */ | 367 | /* Wait for ADC sequencer to complete sampling */ |
364 | while (adc_readl(adc_dev, TSCADC_REG_ADCFSM) & | 368 | while (adc_readl(adc_dev, TSCADC_REG_ADCFSM) & |
365 | TSCADC_SEQ_STATUS) { | 369 | TSCADC_SEQ_STATUS) { |
366 | if (time_after(jiffies, timeout)) | 370 | if (time_after(jiffies, timeout)) |
367 | return -EAGAIN; | 371 | return -EAGAIN; |
368 | } | 372 | } |
369 | 373 | ||
370 | map_val = chan->channel + TOTAL_CHANNELS; | 374 | map_val = chan->channel + TOTAL_CHANNELS; |
371 | fifo1count = adc_readl(adc_dev, TSCADC_REG_FIFO1CNT); | 375 | fifo1count = adc_readl(adc_dev, TSCADC_REG_FIFO1CNT); |
372 | for (i = 0; i < fifo1count; i++) { | 376 | for (i = 0; i < fifo1count; i++) { |
373 | readx1 = adc_readl(adc_dev, TSCADC_REG_FIFO1); | 377 | readx1 = adc_readl(adc_dev, TSCADC_REG_FIFO1); |
374 | stepid = readx1 & TSCADC_FIFOREAD_CHNLID_MASK; | 378 | stepid = readx1 & TSCADC_FIFOREAD_CHNLID_MASK; |
375 | stepid = stepid >> 0x10; | 379 | stepid = stepid >> 0x10; |
376 | 380 | ||
377 | if (stepid == map_val) { | 381 | if (stepid == map_val) { |
378 | readx1 = readx1 & TSCADC_FIFOREAD_DATA_MASK; | 382 | readx1 = readx1 & TSCADC_FIFOREAD_DATA_MASK; |
379 | *val = readx1; | 383 | *val = readx1; |
380 | } | 384 | } |
381 | } | 385 | } |
382 | return IIO_VAL_INT; | 386 | return IIO_VAL_INT; |
383 | } | 387 | } |
384 | } | 388 | } |
385 | 389 | ||
386 | static const struct iio_info tiadc_info = { | 390 | static const struct iio_info tiadc_info = { |
387 | .read_raw = &tiadc_read_raw, | 391 | .read_raw = &tiadc_read_raw, |
388 | .attrs = &tiadc_attribute_group, | 392 | .attrs = &tiadc_attribute_group, |
389 | }; | 393 | }; |
390 | 394 | ||
391 | static int __devinit tiadc_probe(struct platform_device *pdev) | 395 | static int __devinit tiadc_probe(struct platform_device *pdev) |
392 | { | 396 | { |
393 | struct iio_dev *idev; | 397 | struct iio_dev *idev; |
394 | struct adc_device *adc_dev = NULL; | 398 | struct adc_device *adc_dev = NULL; |
395 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; | 399 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; |
396 | struct mfd_tscadc_board *pdata; | 400 | struct mfd_tscadc_board *pdata; |
397 | unsigned int irqenb; | ||
398 | int err; | 401 | int err; |
399 | 402 | ||
400 | pdata = (struct mfd_tscadc_board *)tscadc_dev->dev->platform_data; | 403 | pdata = (struct mfd_tscadc_board *)tscadc_dev->dev->platform_data; |
401 | if (!pdata || !pdata->adc_init) { | 404 | if (!pdata || !pdata->adc_init) { |
402 | dev_err(tscadc_dev->dev, "Could not find platform data\n"); | 405 | dev_err(tscadc_dev->dev, "Could not find platform data\n"); |
403 | return -EINVAL; | 406 | return -EINVAL; |
404 | } | 407 | } |
405 | 408 | ||
406 | idev = iio_allocate_device(sizeof(struct adc_device)); | 409 | idev = iio_allocate_device(sizeof(struct adc_device)); |
407 | if (idev == NULL) { | 410 | if (idev == NULL) { |
408 | dev_err(&pdev->dev, "failed to allocate iio device.\n"); | 411 | dev_err(&pdev->dev, "failed to allocate iio device.\n"); |
409 | err = -ENOMEM; | 412 | err = -ENOMEM; |
410 | goto err_allocate; | 413 | goto err_allocate; |
411 | } | 414 | } |
412 | adc_dev = iio_priv(idev); | 415 | adc_dev = iio_priv(idev); |
413 | 416 | ||
414 | tscadc_dev->adc = adc_dev; | 417 | tscadc_dev->adc = adc_dev; |
415 | adc_dev->mfd_tscadc = tscadc_dev; | 418 | adc_dev->mfd_tscadc = tscadc_dev; |
416 | adc_dev->idev = idev; | 419 | adc_dev->idev = idev; |
417 | adc_dev->channels = pdata->adc_init->adc_channels; | 420 | adc_dev->channels = pdata->adc_init->adc_channels; |
418 | adc_dev->irq = tscadc_dev->irq; | 421 | adc_dev->irq = tscadc_dev->irq; |
419 | 422 | ||
420 | idev->dev.parent = &pdev->dev; | 423 | idev->dev.parent = &pdev->dev; |
421 | idev->name = dev_name(&pdev->dev); | 424 | idev->name = dev_name(&pdev->dev); |
422 | idev->modes = INDIO_DIRECT_MODE; | 425 | idev->modes = INDIO_DIRECT_MODE; |
423 | idev->info = &tiadc_info; | 426 | idev->info = &tiadc_info; |
424 | |||
425 | irqenb = adc_readl(adc_dev, TSCADC_REG_IRQENABLE); | ||
426 | adc_writel(adc_dev, TSCADC_REG_IRQENABLE, | ||
427 | (irqenb | TSCADC_IRQENB_FIFO1OVRRUN | ||
428 | | TSCADC_IRQENB_FIFO1UNDRFLW)); | ||
429 | 427 | ||
430 | adc_step_config(adc_dev); | 428 | adc_step_config(adc_dev); |
431 | 429 | ||
432 | /* program FIFO threshold to value minus 1 */ | 430 | /* program FIFO threshold to value minus 1 */ |
433 | adc_writel(adc_dev, TSCADC_REG_FIFO1THR, FIFO1_THRESHOLD); | 431 | adc_writel(adc_dev, TSCADC_REG_FIFO1THR, FIFO1_THRESHOLD); |
434 | 432 | ||
435 | err = tiadc_channel_init(idev, adc_dev); | 433 | err = tiadc_channel_init(idev, adc_dev); |
436 | if (err < 0) | 434 | if (err < 0) |
437 | goto err_cleanup_channels; | 435 | goto err_cleanup_channels; |
438 | 436 | ||
439 | init_waitqueue_head(&adc_dev->wq_data_avail); | 437 | init_waitqueue_head(&adc_dev->wq_data_avail); |
440 | 438 | ||
441 | err = request_irq(adc_dev->irq, tiadc_irq, IRQF_SHARED, | 439 | err = request_irq(adc_dev->irq, tiadc_irq, IRQF_SHARED, |
442 | idev->name, idev); | 440 | idev->name, idev); |
443 | if (err) | 441 | if (err) |
444 | goto err_unregister; | 442 | goto err_unregister; |
445 | 443 | ||
446 | err = tiadc_config_sw_ring(idev); | 444 | err = tiadc_config_sw_ring(idev); |
447 | if (err) | 445 | if (err) |
448 | goto err_unregister; | 446 | goto err_unregister; |
449 | 447 | ||
450 | err = iio_buffer_register(idev, | 448 | err = iio_buffer_register(idev, |
451 | idev->channels, idev->num_channels); | 449 | idev->channels, idev->num_channels); |
452 | if (err < 0) | 450 | if (err < 0) |
453 | goto err_unregister; | 451 | goto err_unregister; |
454 | 452 | ||
455 | err = iio_device_register(idev); | 453 | err = iio_device_register(idev); |
456 | if (err) | 454 | if (err) |
457 | goto err_unregister; | 455 | goto err_unregister; |
458 | 456 | ||
459 | dev_info(&pdev->dev, "attached adc driver\n"); | 457 | dev_info(&pdev->dev, "attached adc driver\n"); |
460 | platform_set_drvdata(pdev, idev); | 458 | platform_set_drvdata(pdev, idev); |
461 | 459 | ||
462 | return 0; | 460 | return 0; |
463 | 461 | ||
464 | err_unregister: | 462 | err_unregister: |
465 | tiadc_channel_remove(idev); | 463 | tiadc_channel_remove(idev); |
466 | err_cleanup_channels: | 464 | err_cleanup_channels: |
467 | iio_device_unregister(idev); | 465 | iio_device_unregister(idev); |
468 | iio_free_device(idev); | 466 | iio_free_device(idev); |
469 | err_allocate: | 467 | err_allocate: |
470 | return err; | 468 | return err; |
471 | } | 469 | } |
472 | 470 | ||
473 | static int __devexit tiadc_remove(struct platform_device *pdev) | 471 | static int __devexit tiadc_remove(struct platform_device *pdev) |
474 | { | 472 | { |
475 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; | 473 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; |
476 | struct adc_device *adc_dev = tscadc_dev->adc; | 474 | struct adc_device *adc_dev = tscadc_dev->adc; |
477 | struct iio_dev *idev = adc_dev->idev; | 475 | struct iio_dev *idev = adc_dev->idev; |
478 | 476 | ||
479 | iio_device_unregister(idev); | 477 | iio_device_unregister(idev); |
480 | tiadc_channel_remove(idev); | 478 | tiadc_channel_remove(idev); |
481 | 479 | ||
482 | tscadc_dev->adc = NULL; | 480 | tscadc_dev->adc = NULL; |
483 | iio_free_device(idev); | 481 | iio_free_device(idev); |
484 | 482 | ||
485 | platform_set_drvdata(pdev, NULL); | 483 | platform_set_drvdata(pdev, NULL); |
486 | return 0; | 484 | return 0; |
487 | } | 485 | } |
488 | 486 | ||
489 | static int adc_suspend(struct platform_device *pdev, pm_message_t state) | 487 | static int adc_suspend(struct platform_device *pdev, pm_message_t state) |
490 | { | 488 | { |
491 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; | 489 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; |
492 | struct adc_device *adc_dev = tscadc_dev->adc; | 490 | struct adc_device *adc_dev = tscadc_dev->adc; |
493 | unsigned int idle; | 491 | unsigned int idle; |
494 | 492 | ||
495 | if (!device_may_wakeup(tscadc_dev->dev)) { | 493 | if (!device_may_wakeup(tscadc_dev->dev)) { |
496 | idle = adc_readl(adc_dev, TSCADC_REG_CTRL); | 494 | idle = adc_readl(adc_dev, TSCADC_REG_CTRL); |
497 | idle &= ~(TSCADC_CNTRLREG_TSCSSENB); | 495 | idle &= ~(TSCADC_CNTRLREG_TSCSSENB); |
498 | adc_writel(adc_dev, TSCADC_REG_CTRL, (idle | | 496 | adc_writel(adc_dev, TSCADC_REG_CTRL, (idle | |
499 | TSCADC_CNTRLREG_POWERDOWN)); | 497 | TSCADC_CNTRLREG_POWERDOWN)); |
500 | } | 498 | } |
501 | return 0; | 499 | return 0; |
502 | } | 500 | } |
503 | 501 | ||
504 | static int adc_resume(struct platform_device *pdev) | 502 | static int adc_resume(struct platform_device *pdev) |
505 | { | 503 | { |
506 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; | 504 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; |
507 | struct adc_device *adc_dev = tscadc_dev->adc; | 505 | struct adc_device *adc_dev = tscadc_dev->adc; |
508 | unsigned int restore; | 506 | unsigned int restore; |
509 | 507 | ||
510 | /* Make sure ADC is powered up */ | 508 | /* Make sure ADC is powered up */ |
511 | restore = adc_readl(adc_dev, TSCADC_REG_CTRL); | 509 | restore = adc_readl(adc_dev, TSCADC_REG_CTRL); |
512 | restore &= ~(TSCADC_CNTRLREG_POWERDOWN); | 510 | restore &= ~(TSCADC_CNTRLREG_POWERDOWN); |
513 | adc_writel(adc_dev, TSCADC_REG_CTRL, restore); | 511 | adc_writel(adc_dev, TSCADC_REG_CTRL, restore); |
514 | 512 | ||
515 | adc_step_config(adc_dev); | 513 | adc_step_config(adc_dev); |
516 | return 0; | 514 | return 0; |
517 | } | 515 | } |
518 | 516 | ||
519 | static struct platform_driver tiadc_driver = { | 517 | static struct platform_driver tiadc_driver = { |
520 | .driver = { | 518 | .driver = { |
521 | .name = "tiadc", | 519 | .name = "tiadc", |
522 | .owner = THIS_MODULE, | 520 | .owner = THIS_MODULE, |
523 | }, | 521 | }, |
524 | .probe = tiadc_probe, | 522 | .probe = tiadc_probe, |
525 | .remove = __devexit_p(tiadc_remove), | 523 | .remove = __devexit_p(tiadc_remove), |
526 | .suspend = adc_suspend, | 524 | .suspend = adc_suspend, |
527 | .resume = adc_resume, | 525 | .resume = adc_resume, |
528 | }; | 526 | }; |
529 | 527 | ||
530 | module_platform_driver(tiadc_driver); | 528 | module_platform_driver(tiadc_driver); |
531 | 529 |