diff options
Diffstat (limited to 'drivers/iio/adc/exynos_adc.c')
-rw-r--r-- | drivers/iio/adc/exynos_adc.c | 138 |
1 files changed, 127 insertions, 11 deletions
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index fc9dfc23ecb7..43620fd4c66a 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c | |||
@@ -40,13 +40,16 @@ | |||
40 | #include <linux/iio/machine.h> | 40 | #include <linux/iio/machine.h> |
41 | #include <linux/iio/driver.h> | 41 | #include <linux/iio/driver.h> |
42 | 42 | ||
43 | /* EXYNOS4412/5250 ADC_V1 registers definitions */ | 43 | /* S3C/EXYNOS4412/5250 ADC_V1 registers definitions */ |
44 | #define ADC_V1_CON(x) ((x) + 0x00) | 44 | #define ADC_V1_CON(x) ((x) + 0x00) |
45 | #define ADC_V1_DLY(x) ((x) + 0x08) | 45 | #define ADC_V1_DLY(x) ((x) + 0x08) |
46 | #define ADC_V1_DATX(x) ((x) + 0x0C) | 46 | #define ADC_V1_DATX(x) ((x) + 0x0C) |
47 | #define ADC_V1_INTCLR(x) ((x) + 0x18) | 47 | #define ADC_V1_INTCLR(x) ((x) + 0x18) |
48 | #define ADC_V1_MUX(x) ((x) + 0x1c) | 48 | #define ADC_V1_MUX(x) ((x) + 0x1c) |
49 | 49 | ||
50 | /* S3C2410 ADC registers definitions */ | ||
51 | #define ADC_S3C2410_MUX(x) ((x) + 0x18) | ||
52 | |||
50 | /* Future ADC_V2 registers definitions */ | 53 | /* Future ADC_V2 registers definitions */ |
51 | #define ADC_V2_CON1(x) ((x) + 0x00) | 54 | #define ADC_V2_CON1(x) ((x) + 0x00) |
52 | #define ADC_V2_CON2(x) ((x) + 0x04) | 55 | #define ADC_V2_CON2(x) ((x) + 0x04) |
@@ -61,6 +64,11 @@ | |||
61 | #define ADC_V1_CON_PRSCLV(x) (((x) & 0xFF) << 6) | 64 | #define ADC_V1_CON_PRSCLV(x) (((x) & 0xFF) << 6) |
62 | #define ADC_V1_CON_STANDBY (1u << 2) | 65 | #define ADC_V1_CON_STANDBY (1u << 2) |
63 | 66 | ||
67 | /* Bit definitions for S3C2410 ADC */ | ||
68 | #define ADC_S3C2410_CON_SELMUX(x) (((x) & 7) << 3) | ||
69 | #define ADC_S3C2410_DATX_MASK 0x3FF | ||
70 | #define ADC_S3C2416_CON_RES_SEL (1u << 3) | ||
71 | |||
64 | /* Bit definitions for ADC_V2 */ | 72 | /* Bit definitions for ADC_V2 */ |
65 | #define ADC_V2_CON1_SOFT_RESET (1u << 2) | 73 | #define ADC_V2_CON1_SOFT_RESET (1u << 2) |
66 | 74 | ||
@@ -77,6 +85,7 @@ | |||
77 | 85 | ||
78 | /* Bit definitions common for ADC_V1 and ADC_V2 */ | 86 | /* Bit definitions common for ADC_V1 and ADC_V2 */ |
79 | #define ADC_CON_EN_START (1u << 0) | 87 | #define ADC_CON_EN_START (1u << 0) |
88 | #define ADC_CON_EN_START_MASK (0x3 << 0) | ||
80 | #define ADC_DATX_MASK 0xFFF | 89 | #define ADC_DATX_MASK 0xFFF |
81 | 90 | ||
82 | #define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100)) | 91 | #define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100)) |
@@ -100,6 +109,8 @@ struct exynos_adc { | |||
100 | struct exynos_adc_data { | 109 | struct exynos_adc_data { |
101 | int num_channels; | 110 | int num_channels; |
102 | bool needs_sclk; | 111 | bool needs_sclk; |
112 | bool needs_adc_phy; | ||
113 | u32 mask; | ||
103 | 114 | ||
104 | void (*init_hw)(struct exynos_adc *info); | 115 | void (*init_hw)(struct exynos_adc *info); |
105 | void (*exit_hw)(struct exynos_adc *info); | 116 | void (*exit_hw)(struct exynos_adc *info); |
@@ -171,7 +182,8 @@ static void exynos_adc_v1_init_hw(struct exynos_adc *info) | |||
171 | { | 182 | { |
172 | u32 con1; | 183 | u32 con1; |
173 | 184 | ||
174 | writel(1, info->enable_reg); | 185 | if (info->data->needs_adc_phy) |
186 | writel(1, info->enable_reg); | ||
175 | 187 | ||
176 | /* set default prescaler values and Enable prescaler */ | 188 | /* set default prescaler values and Enable prescaler */ |
177 | con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN; | 189 | con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN; |
@@ -185,7 +197,8 @@ static void exynos_adc_v1_exit_hw(struct exynos_adc *info) | |||
185 | { | 197 | { |
186 | u32 con; | 198 | u32 con; |
187 | 199 | ||
188 | writel(0, info->enable_reg); | 200 | if (info->data->needs_adc_phy) |
201 | writel(0, info->enable_reg); | ||
189 | 202 | ||
190 | con = readl(ADC_V1_CON(info->regs)); | 203 | con = readl(ADC_V1_CON(info->regs)); |
191 | con |= ADC_V1_CON_STANDBY; | 204 | con |= ADC_V1_CON_STANDBY; |
@@ -210,6 +223,8 @@ static void exynos_adc_v1_start_conv(struct exynos_adc *info, | |||
210 | 223 | ||
211 | static const struct exynos_adc_data exynos_adc_v1_data = { | 224 | static const struct exynos_adc_data exynos_adc_v1_data = { |
212 | .num_channels = MAX_ADC_V1_CHANNELS, | 225 | .num_channels = MAX_ADC_V1_CHANNELS, |
226 | .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ | ||
227 | .needs_adc_phy = true, | ||
213 | 228 | ||
214 | .init_hw = exynos_adc_v1_init_hw, | 229 | .init_hw = exynos_adc_v1_init_hw, |
215 | .exit_hw = exynos_adc_v1_exit_hw, | 230 | .exit_hw = exynos_adc_v1_exit_hw, |
@@ -217,11 +232,89 @@ static const struct exynos_adc_data exynos_adc_v1_data = { | |||
217 | .start_conv = exynos_adc_v1_start_conv, | 232 | .start_conv = exynos_adc_v1_start_conv, |
218 | }; | 233 | }; |
219 | 234 | ||
235 | static void exynos_adc_s3c2416_start_conv(struct exynos_adc *info, | ||
236 | unsigned long addr) | ||
237 | { | ||
238 | u32 con1; | ||
239 | |||
240 | /* Enable 12 bit ADC resolution */ | ||
241 | con1 = readl(ADC_V1_CON(info->regs)); | ||
242 | con1 |= ADC_S3C2416_CON_RES_SEL; | ||
243 | writel(con1, ADC_V1_CON(info->regs)); | ||
244 | |||
245 | /* Select channel for S3C2416 */ | ||
246 | writel(addr, ADC_S3C2410_MUX(info->regs)); | ||
247 | |||
248 | con1 = readl(ADC_V1_CON(info->regs)); | ||
249 | writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); | ||
250 | } | ||
251 | |||
252 | static struct exynos_adc_data const exynos_adc_s3c2416_data = { | ||
253 | .num_channels = MAX_ADC_V1_CHANNELS, | ||
254 | .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ | ||
255 | |||
256 | .init_hw = exynos_adc_v1_init_hw, | ||
257 | .exit_hw = exynos_adc_v1_exit_hw, | ||
258 | .start_conv = exynos_adc_s3c2416_start_conv, | ||
259 | }; | ||
260 | |||
261 | static void exynos_adc_s3c2443_start_conv(struct exynos_adc *info, | ||
262 | unsigned long addr) | ||
263 | { | ||
264 | u32 con1; | ||
265 | |||
266 | /* Select channel for S3C2433 */ | ||
267 | writel(addr, ADC_S3C2410_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 struct exynos_adc_data const exynos_adc_s3c2443_data = { | ||
274 | .num_channels = MAX_ADC_V1_CHANNELS, | ||
275 | .mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */ | ||
276 | |||
277 | .init_hw = exynos_adc_v1_init_hw, | ||
278 | .exit_hw = exynos_adc_v1_exit_hw, | ||
279 | .start_conv = exynos_adc_s3c2443_start_conv, | ||
280 | }; | ||
281 | |||
282 | static void exynos_adc_s3c64xx_start_conv(struct exynos_adc *info, | ||
283 | unsigned long addr) | ||
284 | { | ||
285 | u32 con1; | ||
286 | |||
287 | con1 = readl(ADC_V1_CON(info->regs)); | ||
288 | con1 &= ~ADC_S3C2410_CON_SELMUX(0x7); | ||
289 | con1 |= ADC_S3C2410_CON_SELMUX(addr); | ||
290 | writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); | ||
291 | } | ||
292 | |||
293 | static struct exynos_adc_data const exynos_adc_s3c24xx_data = { | ||
294 | .num_channels = MAX_ADC_V1_CHANNELS, | ||
295 | .mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */ | ||
296 | |||
297 | .init_hw = exynos_adc_v1_init_hw, | ||
298 | .exit_hw = exynos_adc_v1_exit_hw, | ||
299 | .start_conv = exynos_adc_s3c64xx_start_conv, | ||
300 | }; | ||
301 | |||
302 | static struct exynos_adc_data const exynos_adc_s3c64xx_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 | .clear_irq = exynos_adc_v1_clear_irq, | ||
309 | .start_conv = exynos_adc_s3c64xx_start_conv, | ||
310 | }; | ||
311 | |||
220 | static void exynos_adc_v2_init_hw(struct exynos_adc *info) | 312 | static void exynos_adc_v2_init_hw(struct exynos_adc *info) |
221 | { | 313 | { |
222 | u32 con1, con2; | 314 | u32 con1, con2; |
223 | 315 | ||
224 | writel(1, info->enable_reg); | 316 | if (info->data->needs_adc_phy) |
317 | writel(1, info->enable_reg); | ||
225 | 318 | ||
226 | con1 = ADC_V2_CON1_SOFT_RESET; | 319 | con1 = ADC_V2_CON1_SOFT_RESET; |
227 | writel(con1, ADC_V2_CON1(info->regs)); | 320 | writel(con1, ADC_V2_CON1(info->regs)); |
@@ -238,7 +331,8 @@ static void exynos_adc_v2_exit_hw(struct exynos_adc *info) | |||
238 | { | 331 | { |
239 | u32 con; | 332 | u32 con; |
240 | 333 | ||
241 | writel(0, info->enable_reg); | 334 | if (info->data->needs_adc_phy) |
335 | writel(0, info->enable_reg); | ||
242 | 336 | ||
243 | con = readl(ADC_V2_CON1(info->regs)); | 337 | con = readl(ADC_V2_CON1(info->regs)); |
244 | con &= ~ADC_CON_EN_START; | 338 | con &= ~ADC_CON_EN_START; |
@@ -266,6 +360,8 @@ static void exynos_adc_v2_start_conv(struct exynos_adc *info, | |||
266 | 360 | ||
267 | static const struct exynos_adc_data exynos_adc_v2_data = { | 361 | static const struct exynos_adc_data exynos_adc_v2_data = { |
268 | .num_channels = MAX_ADC_V2_CHANNELS, | 362 | .num_channels = MAX_ADC_V2_CHANNELS, |
363 | .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ | ||
364 | .needs_adc_phy = true, | ||
269 | 365 | ||
270 | .init_hw = exynos_adc_v2_init_hw, | 366 | .init_hw = exynos_adc_v2_init_hw, |
271 | .exit_hw = exynos_adc_v2_exit_hw, | 367 | .exit_hw = exynos_adc_v2_exit_hw, |
@@ -275,7 +371,9 @@ static const struct exynos_adc_data exynos_adc_v2_data = { | |||
275 | 371 | ||
276 | static const struct exynos_adc_data exynos3250_adc_data = { | 372 | static const struct exynos_adc_data exynos3250_adc_data = { |
277 | .num_channels = MAX_EXYNOS3250_ADC_CHANNELS, | 373 | .num_channels = MAX_EXYNOS3250_ADC_CHANNELS, |
374 | .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ | ||
278 | .needs_sclk = true, | 375 | .needs_sclk = true, |
376 | .needs_adc_phy = true, | ||
279 | 377 | ||
280 | .init_hw = exynos_adc_v2_init_hw, | 378 | .init_hw = exynos_adc_v2_init_hw, |
281 | .exit_hw = exynos_adc_v2_exit_hw, | 379 | .exit_hw = exynos_adc_v2_exit_hw, |
@@ -285,6 +383,21 @@ static const struct exynos_adc_data exynos3250_adc_data = { | |||
285 | 383 | ||
286 | static const struct of_device_id exynos_adc_match[] = { | 384 | static const struct of_device_id exynos_adc_match[] = { |
287 | { | 385 | { |
386 | .compatible = "samsung,s3c2410-adc", | ||
387 | .data = &exynos_adc_s3c24xx_data, | ||
388 | }, { | ||
389 | .compatible = "samsung,s3c2416-adc", | ||
390 | .data = &exynos_adc_s3c2416_data, | ||
391 | }, { | ||
392 | .compatible = "samsung,s3c2440-adc", | ||
393 | .data = &exynos_adc_s3c24xx_data, | ||
394 | }, { | ||
395 | .compatible = "samsung,s3c2443-adc", | ||
396 | .data = &exynos_adc_s3c2443_data, | ||
397 | }, { | ||
398 | .compatible = "samsung,s3c6410-adc", | ||
399 | .data = &exynos_adc_s3c64xx_data, | ||
400 | }, { | ||
288 | .compatible = "samsung,exynos-adc-v1", | 401 | .compatible = "samsung,exynos-adc-v1", |
289 | .data = &exynos_adc_v1_data, | 402 | .data = &exynos_adc_v1_data, |
290 | }, { | 403 | }, { |
@@ -347,9 +460,10 @@ static int exynos_read_raw(struct iio_dev *indio_dev, | |||
347 | static irqreturn_t exynos_adc_isr(int irq, void *dev_id) | 460 | static irqreturn_t exynos_adc_isr(int irq, void *dev_id) |
348 | { | 461 | { |
349 | struct exynos_adc *info = (struct exynos_adc *)dev_id; | 462 | struct exynos_adc *info = (struct exynos_adc *)dev_id; |
463 | u32 mask = info->data->mask; | ||
350 | 464 | ||
351 | /* Read value */ | 465 | /* Read value */ |
352 | info->value = readl(ADC_V1_DATX(info->regs)) & ADC_DATX_MASK; | 466 | info->value = readl(ADC_V1_DATX(info->regs)) & mask; |
353 | 467 | ||
354 | /* clear irq */ | 468 | /* clear irq */ |
355 | if (info->data->clear_irq) | 469 | if (info->data->clear_irq) |
@@ -442,10 +556,13 @@ static int exynos_adc_probe(struct platform_device *pdev) | |||
442 | if (IS_ERR(info->regs)) | 556 | if (IS_ERR(info->regs)) |
443 | return PTR_ERR(info->regs); | 557 | return PTR_ERR(info->regs); |
444 | 558 | ||
445 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 559 | |
446 | info->enable_reg = devm_ioremap_resource(&pdev->dev, mem); | 560 | if (info->data->needs_adc_phy) { |
447 | if (IS_ERR(info->enable_reg)) | 561 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
448 | return PTR_ERR(info->enable_reg); | 562 | info->enable_reg = devm_ioremap_resource(&pdev->dev, mem); |
563 | if (IS_ERR(info->enable_reg)) | ||
564 | return PTR_ERR(info->enable_reg); | ||
565 | } | ||
449 | 566 | ||
450 | irq = platform_get_irq(pdev, 0); | 567 | irq = platform_get_irq(pdev, 0); |
451 | if (irq < 0) { | 568 | if (irq < 0) { |
@@ -606,7 +723,6 @@ static struct platform_driver exynos_adc_driver = { | |||
606 | .remove = exynos_adc_remove, | 723 | .remove = exynos_adc_remove, |
607 | .driver = { | 724 | .driver = { |
608 | .name = "exynos-adc", | 725 | .name = "exynos-adc", |
609 | .owner = THIS_MODULE, | ||
610 | .of_match_table = exynos_adc_match, | 726 | .of_match_table = exynos_adc_match, |
611 | .pm = &exynos_adc_pm_ops, | 727 | .pm = &exynos_adc_pm_ops, |
612 | }, | 728 | }, |