Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Chanwoo Choi and committed by
Jonathan Cameron
145b0a5d 249535d8

+114 -13
+13 -3
Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
··· 11 11 12 12 Required properties: 13 13 - compatible: Must be "samsung,exynos-adc-v1" 14 - for exynos4412/5250 controllers. 14 + for exynos4412/5250 and s5pv210 controllers. 15 15 Must be "samsung,exynos-adc-v2" for 16 16 future controllers. 17 17 Must be "samsung,exynos3250-adc" for 18 18 controllers compatible with ADC of Exynos3250. 19 + Must be "samsung,s3c2410-adc" for 20 + the ADC in s3c2410 and compatibles 21 + Must be "samsung,s3c2416-adc" for 22 + the ADC in s3c2416 and compatibles 23 + Must be "samsung,s3c2440-adc" for 24 + the ADC in s3c2440 and compatibles 25 + Must be "samsung,s3c2443-adc" for 26 + the ADC in s3c2443 and compatibles 19 27 Must be "samsung,s3c6410-adc" for 20 28 the ADC in s3c6410 and compatibles 21 - - reg: Contains ADC register address range (base address and 22 - length) and the address of the phy enable register. 29 + - reg: List of ADC register address range 30 + - The base address and range of ADC register 31 + - The base address and range of ADC_PHY register (every 32 + SoC except for s3c24xx/s3c64xx ADC) 23 33 - interrupts: Contains the interrupt information for the timer. The 24 34 format is being dependent on which interrupt controller 25 35 the Samsung device uses.
+1 -1
drivers/iio/adc/Kconfig
··· 129 129 130 130 config EXYNOS_ADC 131 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 133 help 134 134 Core support for the ADC block found in the Samsung EXYNOS series 135 135 of SoCs for drivers such as the touchscreen and hwmon to use to share
+100 -9
drivers/iio/adc/exynos_adc.c
··· 47 47 #define ADC_V1_INTCLR(x) ((x) + 0x18) 48 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 53 /* Future ADC_V2 registers definitions */ 51 54 #define ADC_V2_CON1(x) ((x) + 0x00) 52 55 #define ADC_V2_CON2(x) ((x) + 0x04) ··· 66 63 67 64 /* Bit definitions for S3C2410 ADC */ 68 65 #define ADC_S3C2410_CON_SELMUX(x) (((x) & 7) << 3) 66 + #define ADC_S3C2410_DATX_MASK 0x3FF 67 + #define ADC_S3C2416_CON_RES_SEL (1u << 3) 69 68 70 69 /* Bit definitions for ADC_V2 */ 71 70 #define ADC_V2_CON1_SOFT_RESET (1u << 2) ··· 85 80 86 81 /* Bit definitions common for ADC_V1 and ADC_V2 */ 87 82 #define ADC_CON_EN_START (1u << 0) 83 + #define ADC_CON_EN_START_MASK (0x3 << 0) 88 84 #define ADC_DATX_MASK 0xFFF 89 85 90 86 #define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100)) ··· 109 103 struct exynos_adc_data { 110 104 int num_channels; 111 105 bool needs_sclk; 106 + bool needs_adc_phy; 107 + u32 mask; 112 108 113 109 void (*init_hw)(struct exynos_adc *info); 114 110 void (*exit_hw)(struct exynos_adc *info); ··· 182 174 { 183 175 u32 con1; 184 176 185 - writel(1, info->enable_reg); 177 + if (info->data->needs_adc_phy) 178 + writel(1, info->enable_reg); 186 179 187 180 /* set default prescaler values and Enable prescaler */ 188 181 con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN; ··· 197 188 { 198 189 u32 con; 199 190 200 - writel(0, info->enable_reg); 191 + if (info->data->needs_adc_phy) 192 + writel(0, info->enable_reg); 201 193 202 194 con = readl(ADC_V1_CON(info->regs)); 203 195 con |= ADC_V1_CON_STANDBY; ··· 223 213 224 214 static const struct exynos_adc_data exynos_adc_v1_data = { 225 215 .num_channels = MAX_ADC_V1_CHANNELS, 216 + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ 217 + .needs_adc_phy = true, 226 218 227 219 .init_hw = exynos_adc_v1_init_hw, 228 220 .exit_hw = exynos_adc_v1_exit_hw, 229 221 .clear_irq = exynos_adc_v1_clear_irq, 230 222 .start_conv = exynos_adc_v1_start_conv, 223 + }; 224 + 225 + static void exynos_adc_s3c2416_start_conv(struct exynos_adc *info, 226 + unsigned long addr) 227 + { 228 + u32 con1; 229 + 230 + /* Enable 12 bit ADC resolution */ 231 + con1 = readl(ADC_V1_CON(info->regs)); 232 + con1 |= ADC_S3C2416_CON_RES_SEL; 233 + writel(con1, ADC_V1_CON(info->regs)); 234 + 235 + /* Select channel for S3C2416 */ 236 + writel(addr, ADC_S3C2410_MUX(info->regs)); 237 + 238 + con1 = readl(ADC_V1_CON(info->regs)); 239 + writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); 240 + } 241 + 242 + static struct exynos_adc_data const exynos_adc_s3c2416_data = { 243 + .num_channels = MAX_ADC_V1_CHANNELS, 244 + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ 245 + 246 + .init_hw = exynos_adc_v1_init_hw, 247 + .exit_hw = exynos_adc_v1_exit_hw, 248 + .start_conv = exynos_adc_s3c2416_start_conv, 249 + }; 250 + 251 + static void exynos_adc_s3c2443_start_conv(struct exynos_adc *info, 252 + unsigned long addr) 253 + { 254 + u32 con1; 255 + 256 + /* Select channel for S3C2433 */ 257 + writel(addr, ADC_S3C2410_MUX(info->regs)); 258 + 259 + con1 = readl(ADC_V1_CON(info->regs)); 260 + writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); 261 + } 262 + 263 + static struct exynos_adc_data const exynos_adc_s3c2443_data = { 264 + .num_channels = MAX_ADC_V1_CHANNELS, 265 + .mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */ 266 + 267 + .init_hw = exynos_adc_v1_init_hw, 268 + .exit_hw = exynos_adc_v1_exit_hw, 269 + .start_conv = exynos_adc_s3c2443_start_conv, 231 270 }; 232 271 233 272 static void exynos_adc_s3c64xx_start_conv(struct exynos_adc *info, ··· 290 231 writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); 291 232 } 292 233 234 + static struct exynos_adc_data const exynos_adc_s3c24xx_data = { 235 + .num_channels = MAX_ADC_V1_CHANNELS, 236 + .mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */ 237 + 238 + .init_hw = exynos_adc_v1_init_hw, 239 + .exit_hw = exynos_adc_v1_exit_hw, 240 + .start_conv = exynos_adc_s3c64xx_start_conv, 241 + }; 242 + 293 243 static struct exynos_adc_data const exynos_adc_s3c64xx_data = { 294 244 .num_channels = MAX_ADC_V1_CHANNELS, 245 + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ 295 246 296 247 .init_hw = exynos_adc_v1_init_hw, 297 248 .exit_hw = exynos_adc_v1_exit_hw, ··· 313 244 { 314 245 u32 con1, con2; 315 246 316 - writel(1, info->enable_reg); 247 + if (info->data->needs_adc_phy) 248 + writel(1, info->enable_reg); 317 249 318 250 con1 = ADC_V2_CON1_SOFT_RESET; 319 251 writel(con1, ADC_V2_CON1(info->regs)); ··· 331 261 { 332 262 u32 con; 333 263 334 - writel(0, info->enable_reg); 264 + if (info->data->needs_adc_phy) 265 + writel(0, info->enable_reg); 335 266 336 267 con = readl(ADC_V2_CON1(info->regs)); 337 268 con &= ~ADC_CON_EN_START; ··· 360 289 361 290 static const struct exynos_adc_data exynos_adc_v2_data = { 362 291 .num_channels = MAX_ADC_V2_CHANNELS, 292 + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ 293 + .needs_adc_phy = true, 363 294 364 295 .init_hw = exynos_adc_v2_init_hw, 365 296 .exit_hw = exynos_adc_v2_exit_hw, ··· 371 298 372 299 static const struct exynos_adc_data exynos3250_adc_data = { 373 300 .num_channels = MAX_EXYNOS3250_ADC_CHANNELS, 301 + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ 374 302 .needs_sclk = true, 303 + .needs_adc_phy = true, 375 304 376 305 .init_hw = exynos_adc_v2_init_hw, 377 306 .exit_hw = exynos_adc_v2_exit_hw, ··· 383 308 384 309 static const struct of_device_id exynos_adc_match[] = { 385 310 { 311 + .compatible = "samsung,s3c2410-adc", 312 + .data = &exynos_adc_s3c24xx_data, 313 + }, { 314 + .compatible = "samsung,s3c2416-adc", 315 + .data = &exynos_adc_s3c2416_data, 316 + }, { 317 + .compatible = "samsung,s3c2440-adc", 318 + .data = &exynos_adc_s3c24xx_data, 319 + }, { 320 + .compatible = "samsung,s3c2443-adc", 321 + .data = &exynos_adc_s3c2443_data, 322 + }, { 386 323 .compatible = "samsung,s3c6410-adc", 387 324 .data = &exynos_adc_s3c64xx_data, 388 325 }, { ··· 460 373 static irqreturn_t exynos_adc_isr(int irq, void *dev_id) 461 374 { 462 375 struct exynos_adc *info = (struct exynos_adc *)dev_id; 376 + u32 mask = info->data->mask; 463 377 464 378 /* Read value */ 465 - info->value = readl(ADC_V1_DATX(info->regs)) & ADC_DATX_MASK; 379 + info->value = readl(ADC_V1_DATX(info->regs)) & mask; 466 380 467 381 /* clear irq */ 468 382 if (info->data->clear_irq) ··· 556 468 if (IS_ERR(info->regs)) 557 469 return PTR_ERR(info->regs); 558 470 559 - mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); 560 - info->enable_reg = devm_ioremap_resource(&pdev->dev, mem); 561 - if (IS_ERR(info->enable_reg)) 562 - return PTR_ERR(info->enable_reg); 471 + 472 + if (info->data->needs_adc_phy) { 473 + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); 474 + info->enable_reg = devm_ioremap_resource(&pdev->dev, mem); 475 + if (IS_ERR(info->enable_reg)) 476 + return PTR_ERR(info->enable_reg); 477 + } 563 478 564 479 irq = platform_get_irq(pdev, 0); 565 480 if (irq < 0) {