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

iio: adc: add driver for Rockchip saradc

The ADC is a 3-channel signal-ended 10-bit Successive Approximation
Register (SAR) A/D Converter. It uses the supply and ground as its reference
and converts the analog input signal into 10-bit binary digital codes.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Reviewed-by: Hartmut Knaack <knaack.h@gmx.de>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>

authored by

Heiko Stübner and committed by
Jonathan Cameron
44d6f2ef af097e86

+328
+10
drivers/iio/adc/Kconfig
··· 206 206 To compile this driver as a module, choose M here: the 207 207 module will be called nau7802. 208 208 209 + config ROCKCHIP_SARADC 210 + tristate "Rockchip SARADC driver" 211 + depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST) 212 + help 213 + Say yes here to build support for the SARADC found in SoCs from 214 + Rockchip. 215 + 216 + To compile this driver as a module, choose M here: the 217 + module will be called rockchip_saradc. 218 + 209 219 config TI_ADC081C 210 220 tristate "Texas Instruments ADC081C021/027" 211 221 depends on I2C
+1
drivers/iio/adc/Makefile
··· 22 22 obj-$(CONFIG_MCP3422) += mcp3422.o 23 23 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o 24 24 obj-$(CONFIG_NAU7802) += nau7802.o 25 + obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o 25 26 obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o 26 27 obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o 27 28 obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
+317
drivers/iio/adc/rockchip_saradc.c
··· 1 + /* 2 + * Rockchip Successive Approximation Register (SAR) A/D Converter 3 + * Copyright (C) 2014 ROCKCHIP, Inc. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License as published by 7 + * the Free Software Foundation; either version 2 of the License, or 8 + * (at your option) any later version. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + */ 15 + 16 + #include <linux/module.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/interrupt.h> 19 + #include <linux/io.h> 20 + #include <linux/of.h> 21 + #include <linux/clk.h> 22 + #include <linux/completion.h> 23 + #include <linux/regulator/consumer.h> 24 + #include <linux/iio/iio.h> 25 + 26 + #define SARADC_DATA 0x00 27 + #define SARADC_DATA_MASK 0x3ff 28 + 29 + #define SARADC_STAS 0x04 30 + #define SARADC_STAS_BUSY BIT(0) 31 + 32 + #define SARADC_CTRL 0x08 33 + #define SARADC_CTRL_IRQ_STATUS BIT(6) 34 + #define SARADC_CTRL_IRQ_ENABLE BIT(5) 35 + #define SARADC_CTRL_POWER_CTRL BIT(3) 36 + #define SARADC_CTRL_CHN_MASK 0x7 37 + 38 + #define SARADC_DLY_PU_SOC 0x0c 39 + #define SARADC_DLY_PU_SOC_MASK 0x3f 40 + 41 + #define SARADC_BITS 10 42 + #define SARADC_TIMEOUT msecs_to_jiffies(100) 43 + 44 + struct rockchip_saradc { 45 + void __iomem *regs; 46 + struct clk *pclk; 47 + struct clk *clk; 48 + struct completion completion; 49 + struct regulator *vref; 50 + u16 last_val; 51 + }; 52 + 53 + static int rockchip_saradc_read_raw(struct iio_dev *indio_dev, 54 + struct iio_chan_spec const *chan, 55 + int *val, int *val2, long mask) 56 + { 57 + struct rockchip_saradc *info = iio_priv(indio_dev); 58 + int ret; 59 + 60 + switch (mask) { 61 + case IIO_CHAN_INFO_RAW: 62 + mutex_lock(&indio_dev->mlock); 63 + 64 + reinit_completion(&info->completion); 65 + 66 + /* 8 clock periods as delay between power up and start cmd */ 67 + writel_relaxed(8, info->regs + SARADC_DLY_PU_SOC); 68 + 69 + /* Select the channel to be used and trigger conversion */ 70 + writel(SARADC_CTRL_POWER_CTRL 71 + | (chan->channel & SARADC_CTRL_CHN_MASK) 72 + | SARADC_CTRL_IRQ_ENABLE, 73 + info->regs + SARADC_CTRL); 74 + 75 + if (!wait_for_completion_timeout(&info->completion, 76 + SARADC_TIMEOUT)) { 77 + writel_relaxed(0, info->regs + SARADC_CTRL); 78 + mutex_unlock(&indio_dev->mlock); 79 + return -ETIMEDOUT; 80 + } 81 + 82 + *val = info->last_val; 83 + mutex_unlock(&indio_dev->mlock); 84 + return IIO_VAL_INT; 85 + case IIO_CHAN_INFO_SCALE: 86 + ret = regulator_get_voltage(info->vref); 87 + if (ret < 0) { 88 + dev_err(&indio_dev->dev, "failed to get voltage\n"); 89 + return ret; 90 + } 91 + 92 + *val = ret / 1000; 93 + *val2 = SARADC_BITS; 94 + return IIO_VAL_FRACTIONAL_LOG2; 95 + default: 96 + return -EINVAL; 97 + } 98 + } 99 + 100 + static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id) 101 + { 102 + struct rockchip_saradc *info = (struct rockchip_saradc *)dev_id; 103 + 104 + /* Read value */ 105 + info->last_val = readl_relaxed(info->regs + SARADC_DATA); 106 + info->last_val &= SARADC_DATA_MASK; 107 + 108 + /* Clear irq & power down adc */ 109 + writel_relaxed(0, info->regs + SARADC_CTRL); 110 + 111 + complete(&info->completion); 112 + 113 + return IRQ_HANDLED; 114 + } 115 + 116 + static const struct iio_info rockchip_saradc_iio_info = { 117 + .read_raw = rockchip_saradc_read_raw, 118 + .driver_module = THIS_MODULE, 119 + }; 120 + 121 + #define ADC_CHANNEL(_index, _id) { \ 122 + .type = IIO_VOLTAGE, \ 123 + .indexed = 1, \ 124 + .channel = _index, \ 125 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 126 + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 127 + .datasheet_name = _id, \ 128 + } 129 + 130 + static const struct iio_chan_spec rockchip_saradc_iio_channels[] = { 131 + ADC_CHANNEL(0, "adc0"), 132 + ADC_CHANNEL(1, "adc1"), 133 + ADC_CHANNEL(2, "adc2"), 134 + }; 135 + 136 + static int rockchip_saradc_probe(struct platform_device *pdev) 137 + { 138 + struct rockchip_saradc *info = NULL; 139 + struct device_node *np = pdev->dev.of_node; 140 + struct iio_dev *indio_dev = NULL; 141 + struct resource *mem; 142 + int ret; 143 + int irq; 144 + u32 rate; 145 + 146 + if (!np) 147 + return -ENODEV; 148 + 149 + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info)); 150 + if (!indio_dev) { 151 + dev_err(&pdev->dev, "failed allocating iio device\n"); 152 + return -ENOMEM; 153 + } 154 + info = iio_priv(indio_dev); 155 + 156 + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 157 + info->regs = devm_ioremap_resource(&pdev->dev, mem); 158 + if (IS_ERR(info->regs)) 159 + return PTR_ERR(info->regs); 160 + 161 + init_completion(&info->completion); 162 + 163 + irq = platform_get_irq(pdev, 0); 164 + if (irq < 0) { 165 + dev_err(&pdev->dev, "no irq resource?\n"); 166 + return irq; 167 + } 168 + 169 + ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr, 170 + 0, dev_name(&pdev->dev), info); 171 + if (ret < 0) { 172 + dev_err(&pdev->dev, "failed requesting irq %d\n", irq); 173 + return ret; 174 + } 175 + 176 + info->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); 177 + if (IS_ERR(info->pclk)) { 178 + dev_err(&pdev->dev, "failed to get pclk\n"); 179 + return PTR_ERR(info->pclk); 180 + } 181 + 182 + info->clk = devm_clk_get(&pdev->dev, "saradc"); 183 + if (IS_ERR(info->clk)) { 184 + dev_err(&pdev->dev, "failed to get adc clock\n"); 185 + return PTR_ERR(info->clk); 186 + } 187 + 188 + info->vref = devm_regulator_get(&pdev->dev, "vref"); 189 + if (IS_ERR(info->vref)) { 190 + dev_err(&pdev->dev, "failed to get regulator, %ld\n", 191 + PTR_ERR(info->vref)); 192 + return PTR_ERR(info->vref); 193 + } 194 + 195 + /* 196 + * Use a default of 1MHz for the converter clock. 197 + * This may become user-configurable in the future. 198 + */ 199 + ret = clk_set_rate(info->clk, 1000000); 200 + if (ret < 0) { 201 + dev_err(&pdev->dev, "failed to set adc clk rate, %d\n", ret); 202 + return ret; 203 + } 204 + 205 + ret = regulator_enable(info->vref); 206 + if (ret < 0) { 207 + dev_err(&pdev->dev, "failed to enable vref regulator\n"); 208 + return ret; 209 + } 210 + 211 + ret = clk_prepare_enable(info->pclk); 212 + if (ret < 0) { 213 + dev_err(&pdev->dev, "failed to enable pclk\n"); 214 + goto err_reg_voltage; 215 + } 216 + 217 + ret = clk_prepare_enable(info->clk); 218 + if (ret < 0) { 219 + dev_err(&pdev->dev, "failed to enable converter clock\n"); 220 + goto err_pclk; 221 + } 222 + 223 + platform_set_drvdata(pdev, indio_dev); 224 + 225 + indio_dev->name = dev_name(&pdev->dev); 226 + indio_dev->dev.parent = &pdev->dev; 227 + indio_dev->dev.of_node = pdev->dev.of_node; 228 + indio_dev->info = &rockchip_saradc_iio_info; 229 + indio_dev->modes = INDIO_DIRECT_MODE; 230 + 231 + indio_dev->channels = rockchip_saradc_iio_channels; 232 + indio_dev->num_channels = ARRAY_SIZE(rockchip_saradc_iio_channels); 233 + 234 + ret = iio_device_register(indio_dev); 235 + if (ret) 236 + goto err_clk; 237 + 238 + return 0; 239 + 240 + err_clk: 241 + clk_disable_unprepare(info->clk); 242 + err_pclk: 243 + clk_disable_unprepare(info->pclk); 244 + err_reg_voltage: 245 + regulator_disable(info->vref); 246 + return ret; 247 + } 248 + 249 + static int rockchip_saradc_remove(struct platform_device *pdev) 250 + { 251 + struct iio_dev *indio_dev = platform_get_drvdata(pdev); 252 + struct rockchip_saradc *info = iio_priv(indio_dev); 253 + 254 + iio_device_unregister(indio_dev); 255 + clk_disable_unprepare(info->clk); 256 + clk_disable_unprepare(info->pclk); 257 + regulator_disable(info->vref); 258 + 259 + return 0; 260 + } 261 + 262 + #ifdef CONFIG_PM_SLEEP 263 + static int rockchip_saradc_suspend(struct device *dev) 264 + { 265 + struct iio_dev *indio_dev = dev_get_drvdata(dev); 266 + struct rockchip_saradc *info = iio_priv(indio_dev); 267 + 268 + clk_disable_unprepare(info->clk); 269 + clk_disable_unprepare(info->pclk); 270 + regulator_disable(info->vref); 271 + 272 + return 0; 273 + } 274 + 275 + static int rockchip_saradc_resume(struct device *dev) 276 + { 277 + struct iio_dev *indio_dev = dev_get_drvdata(dev); 278 + struct rockchip_saradc *info = iio_priv(indio_dev); 279 + int ret; 280 + 281 + ret = regulator_enable(info->vref); 282 + if (ret) 283 + return ret; 284 + 285 + ret = clk_prepare_enable(info->pclk); 286 + if (ret) 287 + return ret; 288 + 289 + ret = clk_prepare_enable(info->clk); 290 + if (ret) 291 + return ret; 292 + 293 + return ret; 294 + } 295 + #endif 296 + 297 + static SIMPLE_DEV_PM_OPS(rockchip_saradc_pm_ops, 298 + rockchip_saradc_suspend, rockchip_saradc_resume); 299 + 300 + static const struct of_device_id rockchip_saradc_match[] = { 301 + { .compatible = "rockchip,saradc" }, 302 + {}, 303 + }; 304 + MODULE_DEVICE_TABLE(of, rockchip_saradc_match); 305 + 306 + static struct platform_driver rockchip_saradc_driver = { 307 + .probe = rockchip_saradc_probe, 308 + .remove = rockchip_saradc_remove, 309 + .driver = { 310 + .name = "rockchip-saradc", 311 + .owner = THIS_MODULE, 312 + .of_match_table = rockchip_saradc_match, 313 + .pm = &rockchip_saradc_pm_ops, 314 + }, 315 + }; 316 + 317 + module_platform_driver(rockchip_saradc_driver);