Commit | Line | Data |
---|---|---|
10f5b148 NKC |
1 | /* |
2 | * exynos_adc.c - Support for ADC in EXYNOS SoCs | |
3 | * | |
4 | * 8 ~ 10 channel, 10/12-bit ADC | |
5 | * | |
6 | * Copyright (C) 2013 Naveen Krishna Chatradhi <ch.naveen@samsung.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
21 | */ | |
22 | ||
23 | #include <linux/module.h> | |
24 | #include <linux/platform_device.h> | |
25 | #include <linux/interrupt.h> | |
26 | #include <linux/delay.h> | |
adb4e3f4 | 27 | #include <linux/errno.h> |
10f5b148 NKC |
28 | #include <linux/kernel.h> |
29 | #include <linux/slab.h> | |
30 | #include <linux/io.h> | |
31 | #include <linux/clk.h> | |
32 | #include <linux/completion.h> | |
33 | #include <linux/of.h> | |
34 | #include <linux/of_irq.h> | |
35 | #include <linux/regulator/consumer.h> | |
36 | #include <linux/of_platform.h> | |
ebeb021a | 37 | #include <linux/err.h> |
2bb8ad9b | 38 | #include <linux/input.h> |
10f5b148 NKC |
39 | |
40 | #include <linux/iio/iio.h> | |
41 | #include <linux/iio/machine.h> | |
42 | #include <linux/iio/driver.h> | |
fafb37cf NKC |
43 | #include <linux/mfd/syscon.h> |
44 | #include <linux/regmap.h> | |
10f5b148 | 45 | |
2bb8ad9b AB |
46 | #include <linux/platform_data/touchscreen-s3c2410.h> |
47 | ||
249535d8 | 48 | /* S3C/EXYNOS4412/5250 ADC_V1 registers definitions */ |
10f5b148 | 49 | #define ADC_V1_CON(x) ((x) + 0x00) |
2bb8ad9b | 50 | #define ADC_V1_TSC(x) ((x) + 0x04) |
10f5b148 NKC |
51 | #define ADC_V1_DLY(x) ((x) + 0x08) |
52 | #define ADC_V1_DATX(x) ((x) + 0x0C) | |
2bb8ad9b AB |
53 | #define ADC_V1_DATY(x) ((x) + 0x10) |
54 | #define ADC_V1_UPDN(x) ((x) + 0x14) | |
10f5b148 NKC |
55 | #define ADC_V1_INTCLR(x) ((x) + 0x18) |
56 | #define ADC_V1_MUX(x) ((x) + 0x1c) | |
2bb8ad9b | 57 | #define ADC_V1_CLRINTPNDNUP(x) ((x) + 0x20) |
10f5b148 | 58 | |
145b0a5d CC |
59 | /* S3C2410 ADC registers definitions */ |
60 | #define ADC_S3C2410_MUX(x) ((x) + 0x18) | |
61 | ||
10f5b148 NKC |
62 | /* Future ADC_V2 registers definitions */ |
63 | #define ADC_V2_CON1(x) ((x) + 0x00) | |
64 | #define ADC_V2_CON2(x) ((x) + 0x04) | |
65 | #define ADC_V2_STAT(x) ((x) + 0x08) | |
66 | #define ADC_V2_INT_EN(x) ((x) + 0x10) | |
67 | #define ADC_V2_INT_ST(x) ((x) + 0x14) | |
68 | #define ADC_V2_VER(x) ((x) + 0x20) | |
69 | ||
70 | /* Bit definitions for ADC_V1 */ | |
71 | #define ADC_V1_CON_RES (1u << 16) | |
72 | #define ADC_V1_CON_PRSCEN (1u << 14) | |
73 | #define ADC_V1_CON_PRSCLV(x) (((x) & 0xFF) << 6) | |
74 | #define ADC_V1_CON_STANDBY (1u << 2) | |
75 | ||
249535d8 AB |
76 | /* Bit definitions for S3C2410 ADC */ |
77 | #define ADC_S3C2410_CON_SELMUX(x) (((x) & 7) << 3) | |
145b0a5d CC |
78 | #define ADC_S3C2410_DATX_MASK 0x3FF |
79 | #define ADC_S3C2416_CON_RES_SEL (1u << 3) | |
249535d8 | 80 | |
2bb8ad9b AB |
81 | /* touch screen always uses channel 0 */ |
82 | #define ADC_S3C2410_MUX_TS 0 | |
83 | ||
84 | /* ADCTSC Register Bits */ | |
85 | #define ADC_S3C2443_TSC_UD_SEN (1u << 8) | |
86 | #define ADC_S3C2410_TSC_YM_SEN (1u << 7) | |
87 | #define ADC_S3C2410_TSC_YP_SEN (1u << 6) | |
88 | #define ADC_S3C2410_TSC_XM_SEN (1u << 5) | |
89 | #define ADC_S3C2410_TSC_XP_SEN (1u << 4) | |
90 | #define ADC_S3C2410_TSC_PULL_UP_DISABLE (1u << 3) | |
91 | #define ADC_S3C2410_TSC_AUTO_PST (1u << 2) | |
92 | #define ADC_S3C2410_TSC_XY_PST(x) (((x) & 0x3) << 0) | |
93 | ||
94 | #define ADC_TSC_WAIT4INT (ADC_S3C2410_TSC_YM_SEN | \ | |
95 | ADC_S3C2410_TSC_YP_SEN | \ | |
96 | ADC_S3C2410_TSC_XP_SEN | \ | |
97 | ADC_S3C2410_TSC_XY_PST(3)) | |
98 | ||
99 | #define ADC_TSC_AUTOPST (ADC_S3C2410_TSC_YM_SEN | \ | |
100 | ADC_S3C2410_TSC_YP_SEN | \ | |
101 | ADC_S3C2410_TSC_XP_SEN | \ | |
102 | ADC_S3C2410_TSC_AUTO_PST | \ | |
103 | ADC_S3C2410_TSC_XY_PST(0)) | |
104 | ||
10f5b148 NKC |
105 | /* Bit definitions for ADC_V2 */ |
106 | #define ADC_V2_CON1_SOFT_RESET (1u << 2) | |
107 | ||
108 | #define ADC_V2_CON2_OSEL (1u << 10) | |
109 | #define ADC_V2_CON2_ESEL (1u << 9) | |
110 | #define ADC_V2_CON2_HIGHF (1u << 8) | |
111 | #define ADC_V2_CON2_C_TIME(x) (((x) & 7) << 4) | |
112 | #define ADC_V2_CON2_ACH_SEL(x) (((x) & 0xF) << 0) | |
113 | #define ADC_V2_CON2_ACH_MASK 0xF | |
114 | ||
adb4e3f4 CC |
115 | #define MAX_ADC_V2_CHANNELS 10 |
116 | #define MAX_ADC_V1_CHANNELS 8 | |
117 | #define MAX_EXYNOS3250_ADC_CHANNELS 2 | |
10f5b148 NKC |
118 | |
119 | /* Bit definitions common for ADC_V1 and ADC_V2 */ | |
120 | #define ADC_CON_EN_START (1u << 0) | |
145b0a5d | 121 | #define ADC_CON_EN_START_MASK (0x3 << 0) |
2bb8ad9b | 122 | #define ADC_DATX_PRESSED (1u << 15) |
10f5b148 | 123 | #define ADC_DATX_MASK 0xFFF |
2bb8ad9b | 124 | #define ADC_DATY_MASK 0xFFF |
10f5b148 | 125 | |
c780a8c2 | 126 | #define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100)) |
10f5b148 | 127 | |
fafb37cf NKC |
128 | #define EXYNOS_ADCV1_PHY_OFFSET 0x0718 |
129 | #define EXYNOS_ADCV2_PHY_OFFSET 0x0720 | |
130 | ||
10f5b148 | 131 | struct exynos_adc { |
e49d99e0 | 132 | struct exynos_adc_data *data; |
adb4e3f4 | 133 | struct device *dev; |
2bb8ad9b | 134 | struct input_dev *input; |
10f5b148 | 135 | void __iomem *regs; |
fafb37cf | 136 | struct regmap *pmu_map; |
10f5b148 | 137 | struct clk *clk; |
adb4e3f4 | 138 | struct clk *sclk; |
10f5b148 | 139 | unsigned int irq; |
2bb8ad9b AB |
140 | unsigned int tsirq; |
141 | unsigned int delay; | |
10f5b148 NKC |
142 | struct regulator *vdd; |
143 | ||
144 | struct completion completion; | |
145 | ||
146 | u32 value; | |
147 | unsigned int version; | |
2bb8ad9b AB |
148 | |
149 | bool read_ts; | |
150 | u32 ts_x; | |
151 | u32 ts_y; | |
10f5b148 NKC |
152 | }; |
153 | ||
e49d99e0 CC |
154 | struct exynos_adc_data { |
155 | int num_channels; | |
adb4e3f4 | 156 | bool needs_sclk; |
145b0a5d | 157 | bool needs_adc_phy; |
fafb37cf | 158 | int phy_offset; |
145b0a5d | 159 | u32 mask; |
e49d99e0 CC |
160 | |
161 | void (*init_hw)(struct exynos_adc *info); | |
162 | void (*exit_hw)(struct exynos_adc *info); | |
163 | void (*clear_irq)(struct exynos_adc *info); | |
164 | void (*start_conv)(struct exynos_adc *info, unsigned long addr); | |
10f5b148 | 165 | }; |
10f5b148 | 166 | |
adb4e3f4 CC |
167 | static void exynos_adc_unprepare_clk(struct exynos_adc *info) |
168 | { | |
169 | if (info->data->needs_sclk) | |
170 | clk_unprepare(info->sclk); | |
171 | clk_unprepare(info->clk); | |
172 | } | |
173 | ||
174 | static int exynos_adc_prepare_clk(struct exynos_adc *info) | |
175 | { | |
176 | int ret; | |
177 | ||
178 | ret = clk_prepare(info->clk); | |
179 | if (ret) { | |
180 | dev_err(info->dev, "failed preparing adc clock: %d\n", ret); | |
181 | return ret; | |
182 | } | |
183 | ||
184 | if (info->data->needs_sclk) { | |
185 | ret = clk_prepare(info->sclk); | |
186 | if (ret) { | |
187 | clk_unprepare(info->clk); | |
188 | dev_err(info->dev, | |
189 | "failed preparing sclk_adc clock: %d\n", ret); | |
190 | return ret; | |
191 | } | |
192 | } | |
193 | ||
194 | return 0; | |
195 | } | |
196 | ||
197 | static void exynos_adc_disable_clk(struct exynos_adc *info) | |
198 | { | |
199 | if (info->data->needs_sclk) | |
200 | clk_disable(info->sclk); | |
201 | clk_disable(info->clk); | |
202 | } | |
203 | ||
204 | static int exynos_adc_enable_clk(struct exynos_adc *info) | |
205 | { | |
206 | int ret; | |
207 | ||
208 | ret = clk_enable(info->clk); | |
209 | if (ret) { | |
210 | dev_err(info->dev, "failed enabling adc clock: %d\n", ret); | |
211 | return ret; | |
212 | } | |
213 | ||
214 | if (info->data->needs_sclk) { | |
215 | ret = clk_enable(info->sclk); | |
216 | if (ret) { | |
217 | clk_disable(info->clk); | |
218 | dev_err(info->dev, | |
219 | "failed enabling sclk_adc clock: %d\n", ret); | |
220 | return ret; | |
221 | } | |
222 | } | |
223 | ||
224 | return 0; | |
225 | } | |
226 | ||
e49d99e0 | 227 | static void exynos_adc_v1_init_hw(struct exynos_adc *info) |
10f5b148 | 228 | { |
e49d99e0 | 229 | u32 con1; |
10f5b148 | 230 | |
145b0a5d | 231 | if (info->data->needs_adc_phy) |
fafb37cf | 232 | regmap_write(info->pmu_map, info->data->phy_offset, 1); |
e49d99e0 CC |
233 | |
234 | /* set default prescaler values and Enable prescaler */ | |
235 | con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN; | |
236 | ||
237 | /* Enable 12-bit ADC resolution */ | |
238 | con1 |= ADC_V1_CON_RES; | |
239 | writel(con1, ADC_V1_CON(info->regs)); | |
2bb8ad9b AB |
240 | |
241 | /* set touchscreen delay */ | |
242 | writel(info->delay, ADC_V1_DLY(info->regs)); | |
e49d99e0 CC |
243 | } |
244 | ||
245 | static void exynos_adc_v1_exit_hw(struct exynos_adc *info) | |
246 | { | |
247 | u32 con; | |
248 | ||
145b0a5d | 249 | if (info->data->needs_adc_phy) |
fafb37cf | 250 | regmap_write(info->pmu_map, info->data->phy_offset, 0); |
e49d99e0 CC |
251 | |
252 | con = readl(ADC_V1_CON(info->regs)); | |
253 | con |= ADC_V1_CON_STANDBY; | |
254 | writel(con, ADC_V1_CON(info->regs)); | |
255 | } | |
256 | ||
257 | static void exynos_adc_v1_clear_irq(struct exynos_adc *info) | |
258 | { | |
259 | writel(1, ADC_V1_INTCLR(info->regs)); | |
10f5b148 NKC |
260 | } |
261 | ||
e49d99e0 CC |
262 | static void exynos_adc_v1_start_conv(struct exynos_adc *info, |
263 | unsigned long addr) | |
264 | { | |
265 | u32 con1; | |
266 | ||
267 | writel(addr, ADC_V1_MUX(info->regs)); | |
268 | ||
269 | con1 = readl(ADC_V1_CON(info->regs)); | |
270 | writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); | |
271 | } | |
272 | ||
273 | static const struct exynos_adc_data exynos_adc_v1_data = { | |
274 | .num_channels = MAX_ADC_V1_CHANNELS, | |
145b0a5d CC |
275 | .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ |
276 | .needs_adc_phy = true, | |
fafb37cf | 277 | .phy_offset = EXYNOS_ADCV1_PHY_OFFSET, |
e49d99e0 CC |
278 | |
279 | .init_hw = exynos_adc_v1_init_hw, | |
280 | .exit_hw = exynos_adc_v1_exit_hw, | |
281 | .clear_irq = exynos_adc_v1_clear_irq, | |
282 | .start_conv = exynos_adc_v1_start_conv, | |
283 | }; | |
284 | ||
145b0a5d CC |
285 | static void exynos_adc_s3c2416_start_conv(struct exynos_adc *info, |
286 | unsigned long addr) | |
287 | { | |
288 | u32 con1; | |
289 | ||
290 | /* Enable 12 bit ADC resolution */ | |
291 | con1 = readl(ADC_V1_CON(info->regs)); | |
292 | con1 |= ADC_S3C2416_CON_RES_SEL; | |
293 | writel(con1, ADC_V1_CON(info->regs)); | |
294 | ||
295 | /* Select channel for S3C2416 */ | |
296 | writel(addr, ADC_S3C2410_MUX(info->regs)); | |
297 | ||
298 | con1 = readl(ADC_V1_CON(info->regs)); | |
299 | writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); | |
300 | } | |
301 | ||
302 | static struct exynos_adc_data const exynos_adc_s3c2416_data = { | |
303 | .num_channels = MAX_ADC_V1_CHANNELS, | |
304 | .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ | |
305 | ||
306 | .init_hw = exynos_adc_v1_init_hw, | |
307 | .exit_hw = exynos_adc_v1_exit_hw, | |
308 | .start_conv = exynos_adc_s3c2416_start_conv, | |
309 | }; | |
310 | ||
311 | static void exynos_adc_s3c2443_start_conv(struct exynos_adc *info, | |
312 | unsigned long addr) | |
313 | { | |
314 | u32 con1; | |
315 | ||
316 | /* Select channel for S3C2433 */ | |
317 | writel(addr, ADC_S3C2410_MUX(info->regs)); | |
318 | ||
319 | con1 = readl(ADC_V1_CON(info->regs)); | |
320 | writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); | |
321 | } | |
322 | ||
323 | static struct exynos_adc_data const exynos_adc_s3c2443_data = { | |
324 | .num_channels = MAX_ADC_V1_CHANNELS, | |
325 | .mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */ | |
326 | ||
327 | .init_hw = exynos_adc_v1_init_hw, | |
328 | .exit_hw = exynos_adc_v1_exit_hw, | |
329 | .start_conv = exynos_adc_s3c2443_start_conv, | |
330 | }; | |
331 | ||
249535d8 AB |
332 | static void exynos_adc_s3c64xx_start_conv(struct exynos_adc *info, |
333 | unsigned long addr) | |
334 | { | |
335 | u32 con1; | |
336 | ||
337 | con1 = readl(ADC_V1_CON(info->regs)); | |
338 | con1 &= ~ADC_S3C2410_CON_SELMUX(0x7); | |
339 | con1 |= ADC_S3C2410_CON_SELMUX(addr); | |
340 | writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); | |
341 | } | |
342 | ||
145b0a5d CC |
343 | static struct exynos_adc_data const exynos_adc_s3c24xx_data = { |
344 | .num_channels = MAX_ADC_V1_CHANNELS, | |
345 | .mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */ | |
346 | ||
347 | .init_hw = exynos_adc_v1_init_hw, | |
348 | .exit_hw = exynos_adc_v1_exit_hw, | |
349 | .start_conv = exynos_adc_s3c64xx_start_conv, | |
350 | }; | |
351 | ||
249535d8 AB |
352 | static struct exynos_adc_data const exynos_adc_s3c64xx_data = { |
353 | .num_channels = MAX_ADC_V1_CHANNELS, | |
145b0a5d | 354 | .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ |
249535d8 AB |
355 | |
356 | .init_hw = exynos_adc_v1_init_hw, | |
357 | .exit_hw = exynos_adc_v1_exit_hw, | |
358 | .clear_irq = exynos_adc_v1_clear_irq, | |
359 | .start_conv = exynos_adc_s3c64xx_start_conv, | |
360 | }; | |
361 | ||
e49d99e0 | 362 | static void exynos_adc_v2_init_hw(struct exynos_adc *info) |
dd2723f5 NKC |
363 | { |
364 | u32 con1, con2; | |
365 | ||
145b0a5d | 366 | if (info->data->needs_adc_phy) |
fafb37cf | 367 | regmap_write(info->pmu_map, info->data->phy_offset, 1); |
dd2723f5 | 368 | |
e49d99e0 CC |
369 | con1 = ADC_V2_CON1_SOFT_RESET; |
370 | writel(con1, ADC_V2_CON1(info->regs)); | |
dd2723f5 | 371 | |
e49d99e0 CC |
372 | con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL | |
373 | ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0); | |
374 | writel(con2, ADC_V2_CON2(info->regs)); | |
dd2723f5 | 375 | |
e49d99e0 CC |
376 | /* Enable interrupts */ |
377 | writel(1, ADC_V2_INT_EN(info->regs)); | |
378 | } | |
379 | ||
380 | static void exynos_adc_v2_exit_hw(struct exynos_adc *info) | |
381 | { | |
382 | u32 con; | |
383 | ||
145b0a5d | 384 | if (info->data->needs_adc_phy) |
fafb37cf | 385 | regmap_write(info->pmu_map, info->data->phy_offset, 0); |
e49d99e0 CC |
386 | |
387 | con = readl(ADC_V2_CON1(info->regs)); | |
388 | con &= ~ADC_CON_EN_START; | |
389 | writel(con, ADC_V2_CON1(info->regs)); | |
390 | } | |
391 | ||
392 | static void exynos_adc_v2_clear_irq(struct exynos_adc *info) | |
393 | { | |
394 | writel(1, ADC_V2_INT_ST(info->regs)); | |
395 | } | |
396 | ||
397 | static void exynos_adc_v2_start_conv(struct exynos_adc *info, | |
398 | unsigned long addr) | |
399 | { | |
400 | u32 con1, con2; | |
401 | ||
402 | con2 = readl(ADC_V2_CON2(info->regs)); | |
403 | con2 &= ~ADC_V2_CON2_ACH_MASK; | |
404 | con2 |= ADC_V2_CON2_ACH_SEL(addr); | |
405 | writel(con2, ADC_V2_CON2(info->regs)); | |
406 | ||
407 | con1 = readl(ADC_V2_CON1(info->regs)); | |
408 | writel(con1 | ADC_CON_EN_START, ADC_V2_CON1(info->regs)); | |
409 | } | |
410 | ||
411 | static const struct exynos_adc_data exynos_adc_v2_data = { | |
412 | .num_channels = MAX_ADC_V2_CHANNELS, | |
145b0a5d CC |
413 | .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ |
414 | .needs_adc_phy = true, | |
fafb37cf | 415 | .phy_offset = EXYNOS_ADCV2_PHY_OFFSET, |
e49d99e0 CC |
416 | |
417 | .init_hw = exynos_adc_v2_init_hw, | |
418 | .exit_hw = exynos_adc_v2_exit_hw, | |
419 | .clear_irq = exynos_adc_v2_clear_irq, | |
420 | .start_conv = exynos_adc_v2_start_conv, | |
421 | }; | |
422 | ||
adb4e3f4 CC |
423 | static const struct exynos_adc_data exynos3250_adc_data = { |
424 | .num_channels = MAX_EXYNOS3250_ADC_CHANNELS, | |
145b0a5d | 425 | .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ |
adb4e3f4 | 426 | .needs_sclk = true, |
145b0a5d | 427 | .needs_adc_phy = true, |
fafb37cf | 428 | .phy_offset = EXYNOS_ADCV1_PHY_OFFSET, |
adb4e3f4 CC |
429 | |
430 | .init_hw = exynos_adc_v2_init_hw, | |
431 | .exit_hw = exynos_adc_v2_exit_hw, | |
432 | .clear_irq = exynos_adc_v2_clear_irq, | |
433 | .start_conv = exynos_adc_v2_start_conv, | |
434 | }; | |
435 | ||
c1b50156 AK |
436 | static void exynos_adc_exynos7_init_hw(struct exynos_adc *info) |
437 | { | |
438 | u32 con1, con2; | |
439 | ||
440 | if (info->data->needs_adc_phy) | |
441 | regmap_write(info->pmu_map, info->data->phy_offset, 1); | |
442 | ||
443 | con1 = ADC_V2_CON1_SOFT_RESET; | |
444 | writel(con1, ADC_V2_CON1(info->regs)); | |
445 | ||
446 | con2 = readl(ADC_V2_CON2(info->regs)); | |
447 | con2 &= ~ADC_V2_CON2_C_TIME(7); | |
448 | con2 |= ADC_V2_CON2_C_TIME(0); | |
449 | writel(con2, ADC_V2_CON2(info->regs)); | |
450 | ||
451 | /* Enable interrupts */ | |
452 | writel(1, ADC_V2_INT_EN(info->regs)); | |
453 | } | |
454 | ||
455 | static const struct exynos_adc_data exynos7_adc_data = { | |
456 | .num_channels = MAX_ADC_V1_CHANNELS, | |
457 | .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ | |
458 | ||
459 | .init_hw = exynos_adc_exynos7_init_hw, | |
460 | .exit_hw = exynos_adc_v2_exit_hw, | |
461 | .clear_irq = exynos_adc_v2_clear_irq, | |
462 | .start_conv = exynos_adc_v2_start_conv, | |
463 | }; | |
464 | ||
e49d99e0 CC |
465 | static const struct of_device_id exynos_adc_match[] = { |
466 | { | |
145b0a5d CC |
467 | .compatible = "samsung,s3c2410-adc", |
468 | .data = &exynos_adc_s3c24xx_data, | |
469 | }, { | |
470 | .compatible = "samsung,s3c2416-adc", | |
471 | .data = &exynos_adc_s3c2416_data, | |
472 | }, { | |
473 | .compatible = "samsung,s3c2440-adc", | |
474 | .data = &exynos_adc_s3c24xx_data, | |
475 | }, { | |
476 | .compatible = "samsung,s3c2443-adc", | |
477 | .data = &exynos_adc_s3c2443_data, | |
478 | }, { | |
249535d8 AB |
479 | .compatible = "samsung,s3c6410-adc", |
480 | .data = &exynos_adc_s3c64xx_data, | |
481 | }, { | |
e49d99e0 CC |
482 | .compatible = "samsung,exynos-adc-v1", |
483 | .data = &exynos_adc_v1_data, | |
484 | }, { | |
485 | .compatible = "samsung,exynos-adc-v2", | |
486 | .data = &exynos_adc_v2_data, | |
adb4e3f4 CC |
487 | }, { |
488 | .compatible = "samsung,exynos3250-adc", | |
489 | .data = &exynos3250_adc_data, | |
c1b50156 AK |
490 | }, { |
491 | .compatible = "samsung,exynos7-adc", | |
492 | .data = &exynos7_adc_data, | |
e49d99e0 CC |
493 | }, |
494 | {}, | |
495 | }; | |
496 | MODULE_DEVICE_TABLE(of, exynos_adc_match); | |
497 | ||
498 | static struct exynos_adc_data *exynos_adc_get_data(struct platform_device *pdev) | |
499 | { | |
500 | const struct of_device_id *match; | |
501 | ||
502 | match = of_match_node(exynos_adc_match, pdev->dev.of_node); | |
503 | return (struct exynos_adc_data *)match->data; | |
dd2723f5 NKC |
504 | } |
505 | ||
10f5b148 NKC |
506 | static int exynos_read_raw(struct iio_dev *indio_dev, |
507 | struct iio_chan_spec const *chan, | |
508 | int *val, | |
509 | int *val2, | |
510 | long mask) | |
511 | { | |
512 | struct exynos_adc *info = iio_priv(indio_dev); | |
513 | unsigned long timeout; | |
c780a8c2 | 514 | int ret; |
10f5b148 NKC |
515 | |
516 | if (mask != IIO_CHAN_INFO_RAW) | |
517 | return -EINVAL; | |
518 | ||
519 | mutex_lock(&indio_dev->mlock); | |
6442d94b | 520 | reinit_completion(&info->completion); |
10f5b148 NKC |
521 | |
522 | /* Select the channel to be used and Trigger conversion */ | |
e49d99e0 CC |
523 | if (info->data->start_conv) |
524 | info->data->start_conv(info, chan->address); | |
10f5b148 | 525 | |
2bb8ad9b AB |
526 | timeout = wait_for_completion_timeout(&info->completion, |
527 | EXYNOS_ADC_TIMEOUT); | |
c780a8c2 | 528 | if (timeout == 0) { |
dd2723f5 | 529 | dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n"); |
e49d99e0 CC |
530 | if (info->data->init_hw) |
531 | info->data->init_hw(info); | |
c780a8c2 NKC |
532 | ret = -ETIMEDOUT; |
533 | } else { | |
534 | *val = info->value; | |
535 | *val2 = 0; | |
536 | ret = IIO_VAL_INT; | |
537 | } | |
10f5b148 NKC |
538 | |
539 | mutex_unlock(&indio_dev->mlock); | |
540 | ||
c780a8c2 | 541 | return ret; |
10f5b148 NKC |
542 | } |
543 | ||
2bb8ad9b AB |
544 | static int exynos_read_s3c64xx_ts(struct iio_dev *indio_dev, int *x, int *y) |
545 | { | |
546 | struct exynos_adc *info = iio_priv(indio_dev); | |
547 | unsigned long timeout; | |
548 | int ret; | |
549 | ||
550 | mutex_lock(&indio_dev->mlock); | |
551 | info->read_ts = true; | |
552 | ||
553 | reinit_completion(&info->completion); | |
554 | ||
555 | writel(ADC_S3C2410_TSC_PULL_UP_DISABLE | ADC_TSC_AUTOPST, | |
556 | ADC_V1_TSC(info->regs)); | |
557 | ||
558 | /* Select the ts channel to be used and Trigger conversion */ | |
559 | info->data->start_conv(info, ADC_S3C2410_MUX_TS); | |
560 | ||
561 | timeout = wait_for_completion_timeout(&info->completion, | |
562 | EXYNOS_ADC_TIMEOUT); | |
563 | if (timeout == 0) { | |
564 | dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n"); | |
565 | if (info->data->init_hw) | |
566 | info->data->init_hw(info); | |
567 | ret = -ETIMEDOUT; | |
568 | } else { | |
569 | *x = info->ts_x; | |
570 | *y = info->ts_y; | |
571 | ret = 0; | |
572 | } | |
573 | ||
574 | info->read_ts = false; | |
575 | mutex_unlock(&indio_dev->mlock); | |
576 | ||
577 | return ret; | |
578 | } | |
579 | ||
10f5b148 NKC |
580 | static irqreturn_t exynos_adc_isr(int irq, void *dev_id) |
581 | { | |
582 | struct exynos_adc *info = (struct exynos_adc *)dev_id; | |
145b0a5d | 583 | u32 mask = info->data->mask; |
10f5b148 NKC |
584 | |
585 | /* Read value */ | |
2bb8ad9b AB |
586 | if (info->read_ts) { |
587 | info->ts_x = readl(ADC_V1_DATX(info->regs)); | |
588 | info->ts_y = readl(ADC_V1_DATY(info->regs)); | |
589 | writel(ADC_TSC_WAIT4INT | ADC_S3C2443_TSC_UD_SEN, ADC_V1_TSC(info->regs)); | |
590 | } else { | |
591 | info->value = readl(ADC_V1_DATX(info->regs)) & mask; | |
592 | } | |
e49d99e0 | 593 | |
10f5b148 | 594 | /* clear irq */ |
e49d99e0 CC |
595 | if (info->data->clear_irq) |
596 | info->data->clear_irq(info); | |
10f5b148 NKC |
597 | |
598 | complete(&info->completion); | |
599 | ||
600 | return IRQ_HANDLED; | |
601 | } | |
602 | ||
2bb8ad9b AB |
603 | /* |
604 | * Here we (ab)use a threaded interrupt handler to stay running | |
605 | * for as long as the touchscreen remains pressed, we report | |
606 | * a new event with the latest data and then sleep until the | |
607 | * next timer tick. This mirrors the behavior of the old | |
608 | * driver, with much less code. | |
609 | */ | |
610 | static irqreturn_t exynos_ts_isr(int irq, void *dev_id) | |
611 | { | |
612 | struct exynos_adc *info = dev_id; | |
613 | struct iio_dev *dev = dev_get_drvdata(info->dev); | |
614 | u32 x, y; | |
615 | bool pressed; | |
616 | int ret; | |
617 | ||
618 | while (info->input->users) { | |
619 | ret = exynos_read_s3c64xx_ts(dev, &x, &y); | |
620 | if (ret == -ETIMEDOUT) | |
621 | break; | |
622 | ||
623 | pressed = x & y & ADC_DATX_PRESSED; | |
624 | if (!pressed) { | |
625 | input_report_key(info->input, BTN_TOUCH, 0); | |
626 | input_sync(info->input); | |
627 | break; | |
628 | } | |
629 | ||
630 | input_report_abs(info->input, ABS_X, x & ADC_DATX_MASK); | |
631 | input_report_abs(info->input, ABS_Y, y & ADC_DATY_MASK); | |
632 | input_report_key(info->input, BTN_TOUCH, 1); | |
633 | input_sync(info->input); | |
634 | ||
635 | msleep(1); | |
636 | }; | |
637 | ||
638 | writel(0, ADC_V1_CLRINTPNDNUP(info->regs)); | |
639 | ||
640 | return IRQ_HANDLED; | |
641 | } | |
642 | ||
10f5b148 NKC |
643 | static int exynos_adc_reg_access(struct iio_dev *indio_dev, |
644 | unsigned reg, unsigned writeval, | |
645 | unsigned *readval) | |
646 | { | |
647 | struct exynos_adc *info = iio_priv(indio_dev); | |
648 | ||
649 | if (readval == NULL) | |
650 | return -EINVAL; | |
651 | ||
652 | *readval = readl(info->regs + reg); | |
653 | ||
654 | return 0; | |
655 | } | |
656 | ||
657 | static const struct iio_info exynos_adc_iio_info = { | |
658 | .read_raw = &exynos_read_raw, | |
659 | .debugfs_reg_access = &exynos_adc_reg_access, | |
660 | .driver_module = THIS_MODULE, | |
661 | }; | |
662 | ||
663 | #define ADC_CHANNEL(_index, _id) { \ | |
664 | .type = IIO_VOLTAGE, \ | |
665 | .indexed = 1, \ | |
666 | .channel = _index, \ | |
667 | .address = _index, \ | |
0d23d328 | 668 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
10f5b148 NKC |
669 | .datasheet_name = _id, \ |
670 | } | |
671 | ||
672 | static const struct iio_chan_spec exynos_adc_iio_channels[] = { | |
673 | ADC_CHANNEL(0, "adc0"), | |
674 | ADC_CHANNEL(1, "adc1"), | |
675 | ADC_CHANNEL(2, "adc2"), | |
676 | ADC_CHANNEL(3, "adc3"), | |
677 | ADC_CHANNEL(4, "adc4"), | |
678 | ADC_CHANNEL(5, "adc5"), | |
679 | ADC_CHANNEL(6, "adc6"), | |
680 | ADC_CHANNEL(7, "adc7"), | |
681 | ADC_CHANNEL(8, "adc8"), | |
682 | ADC_CHANNEL(9, "adc9"), | |
683 | }; | |
684 | ||
685 | static int exynos_adc_remove_devices(struct device *dev, void *c) | |
686 | { | |
687 | struct platform_device *pdev = to_platform_device(dev); | |
688 | ||
689 | platform_device_unregister(pdev); | |
690 | ||
691 | return 0; | |
692 | } | |
693 | ||
2bb8ad9b AB |
694 | static int exynos_adc_ts_open(struct input_dev *dev) |
695 | { | |
696 | struct exynos_adc *info = input_get_drvdata(dev); | |
697 | ||
698 | enable_irq(info->tsirq); | |
699 | ||
700 | return 0; | |
701 | } | |
702 | ||
703 | static void exynos_adc_ts_close(struct input_dev *dev) | |
704 | { | |
705 | struct exynos_adc *info = input_get_drvdata(dev); | |
706 | ||
707 | disable_irq(info->tsirq); | |
708 | } | |
709 | ||
710 | static int exynos_adc_ts_init(struct exynos_adc *info) | |
711 | { | |
712 | int ret; | |
713 | ||
714 | if (info->tsirq <= 0) | |
715 | return -ENODEV; | |
716 | ||
717 | info->input = input_allocate_device(); | |
718 | if (!info->input) | |
719 | return -ENOMEM; | |
720 | ||
721 | info->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | |
722 | info->input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | |
723 | ||
724 | input_set_abs_params(info->input, ABS_X, 0, 0x3FF, 0, 0); | |
725 | input_set_abs_params(info->input, ABS_Y, 0, 0x3FF, 0, 0); | |
726 | ||
727 | info->input->name = "S3C24xx TouchScreen"; | |
728 | info->input->id.bustype = BUS_HOST; | |
729 | info->input->open = exynos_adc_ts_open; | |
730 | info->input->close = exynos_adc_ts_close; | |
731 | ||
732 | input_set_drvdata(info->input, info); | |
733 | ||
734 | ret = input_register_device(info->input); | |
735 | if (ret) { | |
736 | input_free_device(info->input); | |
737 | return ret; | |
738 | } | |
739 | ||
740 | disable_irq(info->tsirq); | |
741 | ret = request_threaded_irq(info->tsirq, NULL, exynos_ts_isr, | |
86af4741 | 742 | IRQF_ONESHOT, "touchscreen", info); |
2bb8ad9b AB |
743 | if (ret) |
744 | input_unregister_device(info->input); | |
745 | ||
746 | return ret; | |
747 | } | |
748 | ||
10f5b148 NKC |
749 | static int exynos_adc_probe(struct platform_device *pdev) |
750 | { | |
751 | struct exynos_adc *info = NULL; | |
752 | struct device_node *np = pdev->dev.of_node; | |
2bb8ad9b | 753 | struct s3c2410_ts_mach_info *pdata = dev_get_platdata(&pdev->dev); |
10f5b148 NKC |
754 | struct iio_dev *indio_dev = NULL; |
755 | struct resource *mem; | |
2bb8ad9b | 756 | bool has_ts = false; |
10f5b148 NKC |
757 | int ret = -ENODEV; |
758 | int irq; | |
759 | ||
ebeb021a | 760 | indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc)); |
10f5b148 NKC |
761 | if (!indio_dev) { |
762 | dev_err(&pdev->dev, "failed allocating iio device\n"); | |
763 | return -ENOMEM; | |
764 | } | |
765 | ||
766 | info = iio_priv(indio_dev); | |
767 | ||
e49d99e0 CC |
768 | info->data = exynos_adc_get_data(pdev); |
769 | if (!info->data) { | |
770 | dev_err(&pdev->dev, "failed getting exynos_adc_data\n"); | |
771 | return -EINVAL; | |
772 | } | |
773 | ||
10f5b148 | 774 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
c619653d | 775 | info->regs = devm_ioremap_resource(&pdev->dev, mem); |
ebeb021a SK |
776 | if (IS_ERR(info->regs)) |
777 | return PTR_ERR(info->regs); | |
10f5b148 | 778 | |
145b0a5d CC |
779 | |
780 | if (info->data->needs_adc_phy) { | |
fafb37cf NKC |
781 | info->pmu_map = syscon_regmap_lookup_by_phandle( |
782 | pdev->dev.of_node, | |
783 | "samsung,syscon-phandle"); | |
784 | if (IS_ERR(info->pmu_map)) { | |
785 | dev_err(&pdev->dev, "syscon regmap lookup failed.\n"); | |
786 | return PTR_ERR(info->pmu_map); | |
787 | } | |
145b0a5d | 788 | } |
bb916ebb | 789 | |
10f5b148 NKC |
790 | irq = platform_get_irq(pdev, 0); |
791 | if (irq < 0) { | |
792 | dev_err(&pdev->dev, "no irq resource?\n"); | |
ebeb021a | 793 | return irq; |
10f5b148 | 794 | } |
10f5b148 | 795 | info->irq = irq; |
2bb8ad9b AB |
796 | |
797 | irq = platform_get_irq(pdev, 1); | |
798 | if (irq == -EPROBE_DEFER) | |
799 | return irq; | |
800 | ||
801 | info->tsirq = irq; | |
802 | ||
adb4e3f4 | 803 | info->dev = &pdev->dev; |
10f5b148 NKC |
804 | |
805 | init_completion(&info->completion); | |
806 | ||
10f5b148 NKC |
807 | info->clk = devm_clk_get(&pdev->dev, "adc"); |
808 | if (IS_ERR(info->clk)) { | |
809 | dev_err(&pdev->dev, "failed getting clock, err = %ld\n", | |
810 | PTR_ERR(info->clk)); | |
2bbc7247 | 811 | return PTR_ERR(info->clk); |
10f5b148 NKC |
812 | } |
813 | ||
adb4e3f4 CC |
814 | if (info->data->needs_sclk) { |
815 | info->sclk = devm_clk_get(&pdev->dev, "sclk"); | |
816 | if (IS_ERR(info->sclk)) { | |
817 | dev_err(&pdev->dev, | |
818 | "failed getting sclk clock, err = %ld\n", | |
819 | PTR_ERR(info->sclk)); | |
820 | return PTR_ERR(info->sclk); | |
821 | } | |
822 | } | |
823 | ||
10f5b148 NKC |
824 | info->vdd = devm_regulator_get(&pdev->dev, "vdd"); |
825 | if (IS_ERR(info->vdd)) { | |
826 | dev_err(&pdev->dev, "failed getting regulator, err = %ld\n", | |
827 | PTR_ERR(info->vdd)); | |
2bbc7247 | 828 | return PTR_ERR(info->vdd); |
10f5b148 NKC |
829 | } |
830 | ||
2bbc7247 NKC |
831 | ret = regulator_enable(info->vdd); |
832 | if (ret) | |
833 | return ret; | |
834 | ||
adb4e3f4 | 835 | ret = exynos_adc_prepare_clk(info); |
2bbc7247 NKC |
836 | if (ret) |
837 | goto err_disable_reg; | |
838 | ||
adb4e3f4 CC |
839 | ret = exynos_adc_enable_clk(info); |
840 | if (ret) | |
841 | goto err_unprepare_clk; | |
842 | ||
10f5b148 NKC |
843 | platform_set_drvdata(pdev, indio_dev); |
844 | ||
845 | indio_dev->name = dev_name(&pdev->dev); | |
846 | indio_dev->dev.parent = &pdev->dev; | |
847 | indio_dev->dev.of_node = pdev->dev.of_node; | |
848 | indio_dev->info = &exynos_adc_iio_info; | |
849 | indio_dev->modes = INDIO_DIRECT_MODE; | |
850 | indio_dev->channels = exynos_adc_iio_channels; | |
e49d99e0 | 851 | indio_dev->num_channels = info->data->num_channels; |
10f5b148 | 852 | |
2bbc7247 NKC |
853 | ret = request_irq(info->irq, exynos_adc_isr, |
854 | 0, dev_name(&pdev->dev), info); | |
855 | if (ret < 0) { | |
856 | dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", | |
857 | info->irq); | |
858 | goto err_disable_clk; | |
859 | } | |
860 | ||
10f5b148 NKC |
861 | ret = iio_device_register(indio_dev); |
862 | if (ret) | |
863 | goto err_irq; | |
864 | ||
e49d99e0 CC |
865 | if (info->data->init_hw) |
866 | info->data->init_hw(info); | |
10f5b148 | 867 | |
2bb8ad9b AB |
868 | /* leave out any TS related code if unreachable */ |
869 | if (IS_REACHABLE(CONFIG_INPUT)) { | |
870 | has_ts = of_property_read_bool(pdev->dev.of_node, | |
871 | "has-touchscreen") || pdata; | |
872 | } | |
873 | ||
874 | if (pdata) | |
875 | info->delay = pdata->delay; | |
876 | else | |
877 | info->delay = 10000; | |
878 | ||
879 | if (has_ts) | |
880 | ret = exynos_adc_ts_init(info); | |
881 | if (ret) | |
882 | goto err_iio; | |
883 | ||
3d821a17 | 884 | ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev); |
10f5b148 NKC |
885 | if (ret < 0) { |
886 | dev_err(&pdev->dev, "failed adding child nodes\n"); | |
887 | goto err_of_populate; | |
888 | } | |
889 | ||
890 | return 0; | |
891 | ||
892 | err_of_populate: | |
3d821a17 | 893 | device_for_each_child(&indio_dev->dev, NULL, |
10f5b148 | 894 | exynos_adc_remove_devices); |
2bb8ad9b AB |
895 | if (has_ts) { |
896 | input_unregister_device(info->input); | |
897 | free_irq(info->tsirq, info); | |
898 | } | |
899 | err_iio: | |
10f5b148 NKC |
900 | iio_device_unregister(indio_dev); |
901 | err_irq: | |
902 | free_irq(info->irq, info); | |
2bbc7247 | 903 | err_disable_clk: |
e49d99e0 CC |
904 | if (info->data->exit_hw) |
905 | info->data->exit_hw(info); | |
adb4e3f4 CC |
906 | exynos_adc_disable_clk(info); |
907 | err_unprepare_clk: | |
908 | exynos_adc_unprepare_clk(info); | |
2bbc7247 NKC |
909 | err_disable_reg: |
910 | regulator_disable(info->vdd); | |
10f5b148 NKC |
911 | return ret; |
912 | } | |
913 | ||
914 | static int exynos_adc_remove(struct platform_device *pdev) | |
915 | { | |
916 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); | |
917 | struct exynos_adc *info = iio_priv(indio_dev); | |
918 | ||
2bb8ad9b AB |
919 | if (IS_REACHABLE(CONFIG_INPUT)) { |
920 | free_irq(info->tsirq, info); | |
921 | input_unregister_device(info->input); | |
922 | } | |
3d821a17 | 923 | device_for_each_child(&indio_dev->dev, NULL, |
10f5b148 | 924 | exynos_adc_remove_devices); |
10f5b148 NKC |
925 | iio_device_unregister(indio_dev); |
926 | free_irq(info->irq, info); | |
e49d99e0 CC |
927 | if (info->data->exit_hw) |
928 | info->data->exit_hw(info); | |
adb4e3f4 CC |
929 | exynos_adc_disable_clk(info); |
930 | exynos_adc_unprepare_clk(info); | |
2bbc7247 | 931 | regulator_disable(info->vdd); |
10f5b148 NKC |
932 | |
933 | return 0; | |
934 | } | |
935 | ||
936 | #ifdef CONFIG_PM_SLEEP | |
937 | static int exynos_adc_suspend(struct device *dev) | |
938 | { | |
927b4dc3 NKC |
939 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
940 | struct exynos_adc *info = iio_priv(indio_dev); | |
10f5b148 | 941 | |
e49d99e0 CC |
942 | if (info->data->exit_hw) |
943 | info->data->exit_hw(info); | |
adb4e3f4 | 944 | exynos_adc_disable_clk(info); |
10f5b148 NKC |
945 | regulator_disable(info->vdd); |
946 | ||
947 | return 0; | |
948 | } | |
949 | ||
950 | static int exynos_adc_resume(struct device *dev) | |
951 | { | |
927b4dc3 NKC |
952 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
953 | struct exynos_adc *info = iio_priv(indio_dev); | |
10f5b148 NKC |
954 | int ret; |
955 | ||
956 | ret = regulator_enable(info->vdd); | |
957 | if (ret) | |
958 | return ret; | |
959 | ||
adb4e3f4 | 960 | ret = exynos_adc_enable_clk(info); |
2bbc7247 NKC |
961 | if (ret) |
962 | return ret; | |
10f5b148 | 963 | |
e49d99e0 CC |
964 | if (info->data->init_hw) |
965 | info->data->init_hw(info); | |
10f5b148 NKC |
966 | |
967 | return 0; | |
968 | } | |
969 | #endif | |
970 | ||
971 | static SIMPLE_DEV_PM_OPS(exynos_adc_pm_ops, | |
972 | exynos_adc_suspend, | |
973 | exynos_adc_resume); | |
974 | ||
975 | static struct platform_driver exynos_adc_driver = { | |
976 | .probe = exynos_adc_probe, | |
977 | .remove = exynos_adc_remove, | |
978 | .driver = { | |
979 | .name = "exynos-adc", | |
1ba0686b | 980 | .of_match_table = exynos_adc_match, |
10f5b148 NKC |
981 | .pm = &exynos_adc_pm_ops, |
982 | }, | |
983 | }; | |
984 | ||
985 | module_platform_driver(exynos_adc_driver); | |
986 | ||
987 | MODULE_AUTHOR("Naveen Krishna Chatradhi <ch.naveen@samsung.com>"); | |
988 | MODULE_DESCRIPTION("Samsung EXYNOS5 ADC driver"); | |
989 | MODULE_LICENSE("GPL v2"); |