aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/adc
diff options
context:
space:
mode:
authorChanwoo Choi <cw00.choi@samsung.com>2014-07-28 08:44:00 -0400
committerJonathan Cameron <jic23@kernel.org>2014-08-07 12:48:44 -0400
commit145b0a5d18565615724045dbc2ada32324faa395 (patch)
treee70377413b61a0d088e9033fedf714e02168db42 /drivers/iio/adc
parent249535d894216f5dcd922accfb435d32d417d56f (diff)
iio: adc: exynos_adc: Add support for s3c24xx ADC
This patch add support for s3c2410/s3c2416/s3c2440/s3c2443 ADC. The s3c24xx is alomost same as ADCv1. But, There are a little difference as following: - ADCMUX register address - ADCDAT mask (10 bit or 12 bit ADC resolution according to SoC version) - s3c24xx/s3c64xx has not included ADC_PHY enable register Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio/adc')
-rw-r--r--drivers/iio/adc/Kconfig2
-rw-r--r--drivers/iio/adc/exynos_adc.c109
2 files changed, 101 insertions, 10 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 6655fd41acd9..88bdc8f612e2 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -129,7 +129,7 @@ config AT91_ADC
129 129
130config EXYNOS_ADC 130config EXYNOS_ADC
131 tristate "Exynos ADC driver support" 131 tristate "Exynos ADC driver support"
132 depends on ARCH_EXYNOS || (OF && COMPILE_TEST) 132 depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
133 help 133 help
134 Core support for the ADC block found in the Samsung EXYNOS series 134 Core support for the ADC block found in the Samsung EXYNOS series
135 of SoCs for drivers such as the touchscreen and hwmon to use to share 135 of SoCs for drivers such as the touchscreen and hwmon to use to share
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 62631a778b1f..c59012d2d06f 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -47,6 +47,9 @@
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)
@@ -63,6 +66,8 @@
63 66
64/* Bit definitions for S3C2410 ADC */ 67/* Bit definitions for S3C2410 ADC */
65#define ADC_S3C2410_CON_SELMUX(x) (((x) & 7) << 3) 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)
66 71
67/* Bit definitions for ADC_V2 */ 72/* Bit definitions for ADC_V2 */
68#define ADC_V2_CON1_SOFT_RESET (1u << 2) 73#define ADC_V2_CON1_SOFT_RESET (1u << 2)
@@ -80,6 +85,7 @@
80 85
81/* Bit definitions common for ADC_V1 and ADC_V2 */ 86/* Bit definitions common for ADC_V1 and ADC_V2 */
82#define ADC_CON_EN_START (1u << 0) 87#define ADC_CON_EN_START (1u << 0)
88#define ADC_CON_EN_START_MASK (0x3 << 0)
83#define ADC_DATX_MASK 0xFFF 89#define ADC_DATX_MASK 0xFFF
84 90
85#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100)) 91#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100))
@@ -103,6 +109,8 @@ struct exynos_adc {
103struct exynos_adc_data { 109struct exynos_adc_data {
104 int num_channels; 110 int num_channels;
105 bool needs_sclk; 111 bool needs_sclk;
112 bool needs_adc_phy;
113 u32 mask;
106 114
107 void (*init_hw)(struct exynos_adc *info); 115 void (*init_hw)(struct exynos_adc *info);
108 void (*exit_hw)(struct exynos_adc *info); 116 void (*exit_hw)(struct exynos_adc *info);
@@ -174,7 +182,8 @@ static void exynos_adc_v1_init_hw(struct exynos_adc *info)
174{ 182{
175 u32 con1; 183 u32 con1;
176 184
177 writel(1, info->enable_reg); 185 if (info->data->needs_adc_phy)
186 writel(1, info->enable_reg);
178 187
179 /* set default prescaler values and Enable prescaler */ 188 /* set default prescaler values and Enable prescaler */
180 con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN; 189 con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
@@ -188,7 +197,8 @@ static void exynos_adc_v1_exit_hw(struct exynos_adc *info)
188{ 197{
189 u32 con; 198 u32 con;
190 199
191 writel(0, info->enable_reg); 200 if (info->data->needs_adc_phy)
201 writel(0, info->enable_reg);
192 202
193 con = readl(ADC_V1_CON(info->regs)); 203 con = readl(ADC_V1_CON(info->regs));
194 con |= ADC_V1_CON_STANDBY; 204 con |= ADC_V1_CON_STANDBY;
@@ -213,6 +223,8 @@ static void exynos_adc_v1_start_conv(struct exynos_adc *info,
213 223
214static const struct exynos_adc_data exynos_adc_v1_data = { 224static const struct exynos_adc_data exynos_adc_v1_data = {
215 .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,
216 228
217 .init_hw = exynos_adc_v1_init_hw, 229 .init_hw = exynos_adc_v1_init_hw,
218 .exit_hw = exynos_adc_v1_exit_hw, 230 .exit_hw = exynos_adc_v1_exit_hw,
@@ -220,6 +232,53 @@ static const struct exynos_adc_data exynos_adc_v1_data = {
220 .start_conv = exynos_adc_v1_start_conv, 232 .start_conv = exynos_adc_v1_start_conv,
221}; 233};
222 234
235static 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
252static 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
261static 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
273static 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
223static void exynos_adc_s3c64xx_start_conv(struct exynos_adc *info, 282static void exynos_adc_s3c64xx_start_conv(struct exynos_adc *info,
224 unsigned long addr) 283 unsigned long addr)
225{ 284{
@@ -231,8 +290,18 @@ static void exynos_adc_s3c64xx_start_conv(struct exynos_adc *info,
231 writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); 290 writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
232} 291}
233 292
293static 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
234static struct exynos_adc_data const exynos_adc_s3c64xx_data = { 302static struct exynos_adc_data const exynos_adc_s3c64xx_data = {
235 .num_channels = MAX_ADC_V1_CHANNELS, 303 .num_channels = MAX_ADC_V1_CHANNELS,
304 .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
236 305
237 .init_hw = exynos_adc_v1_init_hw, 306 .init_hw = exynos_adc_v1_init_hw,
238 .exit_hw = exynos_adc_v1_exit_hw, 307 .exit_hw = exynos_adc_v1_exit_hw,
@@ -244,7 +313,8 @@ static void exynos_adc_v2_init_hw(struct exynos_adc *info)
244{ 313{
245 u32 con1, con2; 314 u32 con1, con2;
246 315
247 writel(1, info->enable_reg); 316 if (info->data->needs_adc_phy)
317 writel(1, info->enable_reg);
248 318
249 con1 = ADC_V2_CON1_SOFT_RESET; 319 con1 = ADC_V2_CON1_SOFT_RESET;
250 writel(con1, ADC_V2_CON1(info->regs)); 320 writel(con1, ADC_V2_CON1(info->regs));
@@ -261,7 +331,8 @@ static void exynos_adc_v2_exit_hw(struct exynos_adc *info)
261{ 331{
262 u32 con; 332 u32 con;
263 333
264 writel(0, info->enable_reg); 334 if (info->data->needs_adc_phy)
335 writel(0, info->enable_reg);
265 336
266 con = readl(ADC_V2_CON1(info->regs)); 337 con = readl(ADC_V2_CON1(info->regs));
267 con &= ~ADC_CON_EN_START; 338 con &= ~ADC_CON_EN_START;
@@ -289,6 +360,8 @@ static void exynos_adc_v2_start_conv(struct exynos_adc *info,
289 360
290static const struct exynos_adc_data exynos_adc_v2_data = { 361static const struct exynos_adc_data exynos_adc_v2_data = {
291 .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,
292 365
293 .init_hw = exynos_adc_v2_init_hw, 366 .init_hw = exynos_adc_v2_init_hw,
294 .exit_hw = exynos_adc_v2_exit_hw, 367 .exit_hw = exynos_adc_v2_exit_hw,
@@ -298,7 +371,9 @@ static const struct exynos_adc_data exynos_adc_v2_data = {
298 371
299static const struct exynos_adc_data exynos3250_adc_data = { 372static const struct exynos_adc_data exynos3250_adc_data = {
300 .num_channels = MAX_EXYNOS3250_ADC_CHANNELS, 373 .num_channels = MAX_EXYNOS3250_ADC_CHANNELS,
374 .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
301 .needs_sclk = true, 375 .needs_sclk = true,
376 .needs_adc_phy = true,
302 377
303 .init_hw = exynos_adc_v2_init_hw, 378 .init_hw = exynos_adc_v2_init_hw,
304 .exit_hw = exynos_adc_v2_exit_hw, 379 .exit_hw = exynos_adc_v2_exit_hw,
@@ -308,6 +383,18 @@ static const struct exynos_adc_data exynos3250_adc_data = {
308 383
309static const struct of_device_id exynos_adc_match[] = { 384static const struct of_device_id exynos_adc_match[] = {
310 { 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 }, {
311 .compatible = "samsung,s3c6410-adc", 398 .compatible = "samsung,s3c6410-adc",
312 .data = &exynos_adc_s3c64xx_data, 399 .data = &exynos_adc_s3c64xx_data,
313 }, { 400 }, {
@@ -373,9 +460,10 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
373static irqreturn_t exynos_adc_isr(int irq, void *dev_id) 460static irqreturn_t exynos_adc_isr(int irq, void *dev_id)
374{ 461{
375 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;
376 464
377 /* Read value */ 465 /* Read value */
378 info->value = readl(ADC_V1_DATX(info->regs)) & ADC_DATX_MASK; 466 info->value = readl(ADC_V1_DATX(info->regs)) & mask;
379 467
380 /* clear irq */ 468 /* clear irq */
381 if (info->data->clear_irq) 469 if (info->data->clear_irq)
@@ -468,10 +556,13 @@ static int exynos_adc_probe(struct platform_device *pdev)
468 if (IS_ERR(info->regs)) 556 if (IS_ERR(info->regs))
469 return PTR_ERR(info->regs); 557 return PTR_ERR(info->regs);
470 558
471 mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); 559
472 info->enable_reg = devm_ioremap_resource(&pdev->dev, mem); 560 if (info->data->needs_adc_phy) {
473 if (IS_ERR(info->enable_reg)) 561 mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
474 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 }
475 566
476 irq = platform_get_irq(pdev, 0); 567 irq = platform_get_irq(pdev, 0);
477 if (irq < 0) { 568 if (irq < 0) {