1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2a583c24dSJoachim Eastwood /* 3a583c24dSJoachim Eastwood * IIO ADC driver for NXP LPC18xx ADC 4a583c24dSJoachim Eastwood * 5a583c24dSJoachim Eastwood * Copyright (C) 2016 Joachim Eastwood <manabian@gmail.com> 6a583c24dSJoachim Eastwood * 7a583c24dSJoachim Eastwood * UNSUPPORTED hardware features: 8a583c24dSJoachim Eastwood * - Hardware triggers 9a583c24dSJoachim Eastwood * - Burst mode 10a583c24dSJoachim Eastwood * - Interrupts 11a583c24dSJoachim Eastwood * - DMA 12a583c24dSJoachim Eastwood */ 13a583c24dSJoachim Eastwood 14a583c24dSJoachim Eastwood #include <linux/clk.h> 15a583c24dSJoachim Eastwood #include <linux/err.h> 16a583c24dSJoachim Eastwood #include <linux/iio/iio.h> 17a583c24dSJoachim Eastwood #include <linux/iio/driver.h> 18a583c24dSJoachim Eastwood #include <linux/io.h> 19a583c24dSJoachim Eastwood #include <linux/iopoll.h> 20a583c24dSJoachim Eastwood #include <linux/module.h> 21a583c24dSJoachim Eastwood #include <linux/mutex.h> 22a583c24dSJoachim Eastwood #include <linux/of.h> 23a583c24dSJoachim Eastwood #include <linux/of_device.h> 24a583c24dSJoachim Eastwood #include <linux/platform_device.h> 25a583c24dSJoachim Eastwood #include <linux/regulator/consumer.h> 26a583c24dSJoachim Eastwood 27a583c24dSJoachim Eastwood /* LPC18XX ADC registers and bits */ 28a583c24dSJoachim Eastwood #define LPC18XX_ADC_CR 0x000 29a583c24dSJoachim Eastwood #define LPC18XX_ADC_CR_CLKDIV_SHIFT 8 30a583c24dSJoachim Eastwood #define LPC18XX_ADC_CR_PDN BIT(21) 31a583c24dSJoachim Eastwood #define LPC18XX_ADC_CR_START_NOW (0x1 << 24) 32a583c24dSJoachim Eastwood #define LPC18XX_ADC_GDR 0x004 33a583c24dSJoachim Eastwood 34a583c24dSJoachim Eastwood /* Data register bits */ 35a583c24dSJoachim Eastwood #define LPC18XX_ADC_SAMPLE_SHIFT 6 36a583c24dSJoachim Eastwood #define LPC18XX_ADC_SAMPLE_MASK 0x3ff 37a583c24dSJoachim Eastwood #define LPC18XX_ADC_CONV_DONE BIT(31) 38a583c24dSJoachim Eastwood 39a583c24dSJoachim Eastwood /* Clock should be 4.5 MHz or less */ 40a583c24dSJoachim Eastwood #define LPC18XX_ADC_CLK_TARGET 4500000 41a583c24dSJoachim Eastwood 42a583c24dSJoachim Eastwood struct lpc18xx_adc { 43a583c24dSJoachim Eastwood struct regulator *vref; 44a583c24dSJoachim Eastwood void __iomem *base; 45a583c24dSJoachim Eastwood struct device *dev; 46a583c24dSJoachim Eastwood struct mutex lock; 47a583c24dSJoachim Eastwood struct clk *clk; 48a583c24dSJoachim Eastwood u32 cr_reg; 49a583c24dSJoachim Eastwood }; 50a583c24dSJoachim Eastwood 51a583c24dSJoachim Eastwood #define LPC18XX_ADC_CHAN(_idx) { \ 52a583c24dSJoachim Eastwood .type = IIO_VOLTAGE, \ 53a583c24dSJoachim Eastwood .indexed = 1, \ 54a583c24dSJoachim Eastwood .channel = _idx, \ 55a583c24dSJoachim Eastwood .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 56a583c24dSJoachim Eastwood .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 57a583c24dSJoachim Eastwood } 58a583c24dSJoachim Eastwood 59a583c24dSJoachim Eastwood static const struct iio_chan_spec lpc18xx_adc_iio_channels[] = { 60a583c24dSJoachim Eastwood LPC18XX_ADC_CHAN(0), 61a583c24dSJoachim Eastwood LPC18XX_ADC_CHAN(1), 62a583c24dSJoachim Eastwood LPC18XX_ADC_CHAN(2), 63a583c24dSJoachim Eastwood LPC18XX_ADC_CHAN(3), 64a583c24dSJoachim Eastwood LPC18XX_ADC_CHAN(4), 65a583c24dSJoachim Eastwood LPC18XX_ADC_CHAN(5), 66a583c24dSJoachim Eastwood LPC18XX_ADC_CHAN(6), 67a583c24dSJoachim Eastwood LPC18XX_ADC_CHAN(7), 68a583c24dSJoachim Eastwood }; 69a583c24dSJoachim Eastwood 70a583c24dSJoachim Eastwood static int lpc18xx_adc_read_chan(struct lpc18xx_adc *adc, unsigned int ch) 71a583c24dSJoachim Eastwood { 72a583c24dSJoachim Eastwood int ret; 73a583c24dSJoachim Eastwood u32 reg; 74a583c24dSJoachim Eastwood 75a583c24dSJoachim Eastwood reg = adc->cr_reg | BIT(ch) | LPC18XX_ADC_CR_START_NOW; 76a583c24dSJoachim Eastwood writel(reg, adc->base + LPC18XX_ADC_CR); 77a583c24dSJoachim Eastwood 78a583c24dSJoachim Eastwood ret = readl_poll_timeout(adc->base + LPC18XX_ADC_GDR, reg, 79a583c24dSJoachim Eastwood reg & LPC18XX_ADC_CONV_DONE, 3, 9); 80a583c24dSJoachim Eastwood if (ret) { 81a583c24dSJoachim Eastwood dev_warn(adc->dev, "adc read timed out\n"); 82a583c24dSJoachim Eastwood return ret; 83a583c24dSJoachim Eastwood } 84a583c24dSJoachim Eastwood 85a583c24dSJoachim Eastwood return (reg >> LPC18XX_ADC_SAMPLE_SHIFT) & LPC18XX_ADC_SAMPLE_MASK; 86a583c24dSJoachim Eastwood } 87a583c24dSJoachim Eastwood 88a583c24dSJoachim Eastwood static int lpc18xx_adc_read_raw(struct iio_dev *indio_dev, 89a583c24dSJoachim Eastwood struct iio_chan_spec const *chan, 90a583c24dSJoachim Eastwood int *val, int *val2, long mask) 91a583c24dSJoachim Eastwood { 92a583c24dSJoachim Eastwood struct lpc18xx_adc *adc = iio_priv(indio_dev); 93a583c24dSJoachim Eastwood 94a583c24dSJoachim Eastwood switch (mask) { 95a583c24dSJoachim Eastwood case IIO_CHAN_INFO_RAW: 96a583c24dSJoachim Eastwood mutex_lock(&adc->lock); 97a583c24dSJoachim Eastwood *val = lpc18xx_adc_read_chan(adc, chan->channel); 98a583c24dSJoachim Eastwood mutex_unlock(&adc->lock); 99a583c24dSJoachim Eastwood if (*val < 0) 100a583c24dSJoachim Eastwood return *val; 101a583c24dSJoachim Eastwood 102a583c24dSJoachim Eastwood return IIO_VAL_INT; 103a583c24dSJoachim Eastwood 104a583c24dSJoachim Eastwood case IIO_CHAN_INFO_SCALE: 105a583c24dSJoachim Eastwood *val = regulator_get_voltage(adc->vref) / 1000; 106a583c24dSJoachim Eastwood *val2 = 10; 107a583c24dSJoachim Eastwood 108a583c24dSJoachim Eastwood return IIO_VAL_FRACTIONAL_LOG2; 109a583c24dSJoachim Eastwood } 110a583c24dSJoachim Eastwood 111a583c24dSJoachim Eastwood return -EINVAL; 112a583c24dSJoachim Eastwood } 113a583c24dSJoachim Eastwood 114a583c24dSJoachim Eastwood static const struct iio_info lpc18xx_adc_info = { 115a583c24dSJoachim Eastwood .read_raw = lpc18xx_adc_read_raw, 116a583c24dSJoachim Eastwood }; 117a583c24dSJoachim Eastwood 1180be84447SAndré Gustavo Nakagomi Lopez static void lpc18xx_clear_cr_reg(void *data) 1190be84447SAndré Gustavo Nakagomi Lopez { 1200be84447SAndré Gustavo Nakagomi Lopez struct lpc18xx_adc *adc = data; 1210be84447SAndré Gustavo Nakagomi Lopez 1220be84447SAndré Gustavo Nakagomi Lopez writel(0, adc->base + LPC18XX_ADC_CR); 1230be84447SAndré Gustavo Nakagomi Lopez } 1240be84447SAndré Gustavo Nakagomi Lopez 1250be84447SAndré Gustavo Nakagomi Lopez static void lpc18xx_clk_disable(void *clk) 1260be84447SAndré Gustavo Nakagomi Lopez { 1270be84447SAndré Gustavo Nakagomi Lopez clk_disable_unprepare(clk); 1280be84447SAndré Gustavo Nakagomi Lopez } 1290be84447SAndré Gustavo Nakagomi Lopez 1300be84447SAndré Gustavo Nakagomi Lopez static void lpc18xx_regulator_disable(void *vref) 1310be84447SAndré Gustavo Nakagomi Lopez { 1320be84447SAndré Gustavo Nakagomi Lopez regulator_disable(vref); 1330be84447SAndré Gustavo Nakagomi Lopez } 1340be84447SAndré Gustavo Nakagomi Lopez 135a583c24dSJoachim Eastwood static int lpc18xx_adc_probe(struct platform_device *pdev) 136a583c24dSJoachim Eastwood { 137a583c24dSJoachim Eastwood struct iio_dev *indio_dev; 138a583c24dSJoachim Eastwood struct lpc18xx_adc *adc; 139a583c24dSJoachim Eastwood unsigned int clkdiv; 140a583c24dSJoachim Eastwood unsigned long rate; 141a583c24dSJoachim Eastwood int ret; 142a583c24dSJoachim Eastwood 143a583c24dSJoachim Eastwood indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc)); 144a583c24dSJoachim Eastwood if (!indio_dev) 145a583c24dSJoachim Eastwood return -ENOMEM; 146a583c24dSJoachim Eastwood 147a583c24dSJoachim Eastwood adc = iio_priv(indio_dev); 148a583c24dSJoachim Eastwood adc->dev = &pdev->dev; 149a583c24dSJoachim Eastwood mutex_init(&adc->lock); 150a583c24dSJoachim Eastwood 15118d031f4SJonathan Cameron adc->base = devm_platform_ioremap_resource(pdev, 0); 152a583c24dSJoachim Eastwood if (IS_ERR(adc->base)) 153a583c24dSJoachim Eastwood return PTR_ERR(adc->base); 154a583c24dSJoachim Eastwood 155a583c24dSJoachim Eastwood adc->clk = devm_clk_get(&pdev->dev, NULL); 156922f694bSCai Huoqing if (IS_ERR(adc->clk)) 157922f694bSCai Huoqing return dev_err_probe(&pdev->dev, PTR_ERR(adc->clk), 158922f694bSCai Huoqing "error getting clock\n"); 159a583c24dSJoachim Eastwood 160a583c24dSJoachim Eastwood adc->vref = devm_regulator_get(&pdev->dev, "vref"); 161922f694bSCai Huoqing if (IS_ERR(adc->vref)) 162922f694bSCai Huoqing return dev_err_probe(&pdev->dev, PTR_ERR(adc->vref), 163922f694bSCai Huoqing "error getting regulator\n"); 164a583c24dSJoachim Eastwood 165a583c24dSJoachim Eastwood indio_dev->name = dev_name(&pdev->dev); 166a583c24dSJoachim Eastwood indio_dev->info = &lpc18xx_adc_info; 167a583c24dSJoachim Eastwood indio_dev->modes = INDIO_DIRECT_MODE; 168a583c24dSJoachim Eastwood indio_dev->channels = lpc18xx_adc_iio_channels; 169a583c24dSJoachim Eastwood indio_dev->num_channels = ARRAY_SIZE(lpc18xx_adc_iio_channels); 170a583c24dSJoachim Eastwood 171a583c24dSJoachim Eastwood ret = regulator_enable(adc->vref); 172a583c24dSJoachim Eastwood if (ret) { 173a583c24dSJoachim Eastwood dev_err(&pdev->dev, "unable to enable regulator\n"); 174a583c24dSJoachim Eastwood return ret; 175a583c24dSJoachim Eastwood } 176a583c24dSJoachim Eastwood 1770be84447SAndré Gustavo Nakagomi Lopez ret = devm_add_action_or_reset(&pdev->dev, lpc18xx_regulator_disable, adc->vref); 1780be84447SAndré Gustavo Nakagomi Lopez if (ret) 1790be84447SAndré Gustavo Nakagomi Lopez return ret; 1800be84447SAndré Gustavo Nakagomi Lopez 181a583c24dSJoachim Eastwood ret = clk_prepare_enable(adc->clk); 182a583c24dSJoachim Eastwood if (ret) { 183a583c24dSJoachim Eastwood dev_err(&pdev->dev, "unable to enable clock\n"); 1840be84447SAndré Gustavo Nakagomi Lopez return ret; 185a583c24dSJoachim Eastwood } 186a583c24dSJoachim Eastwood 1870be84447SAndré Gustavo Nakagomi Lopez ret = devm_add_action_or_reset(&pdev->dev, lpc18xx_clk_disable, 1880be84447SAndré Gustavo Nakagomi Lopez adc->clk); 1890be84447SAndré Gustavo Nakagomi Lopez if (ret) 1900be84447SAndré Gustavo Nakagomi Lopez return ret; 1910be84447SAndré Gustavo Nakagomi Lopez 192*8eebe628SAndré Gustavo Nakagomi Lopez rate = clk_get_rate(adc->clk); 193*8eebe628SAndré Gustavo Nakagomi Lopez clkdiv = DIV_ROUND_UP(rate, LPC18XX_ADC_CLK_TARGET); 194*8eebe628SAndré Gustavo Nakagomi Lopez 195a583c24dSJoachim Eastwood adc->cr_reg = (clkdiv << LPC18XX_ADC_CR_CLKDIV_SHIFT) | 196a583c24dSJoachim Eastwood LPC18XX_ADC_CR_PDN; 197a583c24dSJoachim Eastwood writel(adc->cr_reg, adc->base + LPC18XX_ADC_CR); 198a583c24dSJoachim Eastwood 1990be84447SAndré Gustavo Nakagomi Lopez ret = devm_add_action_or_reset(&pdev->dev, lpc18xx_clear_cr_reg, adc); 2000be84447SAndré Gustavo Nakagomi Lopez if (ret) 201a583c24dSJoachim Eastwood return ret; 202a583c24dSJoachim Eastwood 2030be84447SAndré Gustavo Nakagomi Lopez return devm_iio_device_register(&pdev->dev, indio_dev); 204a583c24dSJoachim Eastwood } 205a583c24dSJoachim Eastwood 206a583c24dSJoachim Eastwood static const struct of_device_id lpc18xx_adc_match[] = { 207a583c24dSJoachim Eastwood { .compatible = "nxp,lpc1850-adc" }, 208a583c24dSJoachim Eastwood { /* sentinel */ } 209a583c24dSJoachim Eastwood }; 210a583c24dSJoachim Eastwood MODULE_DEVICE_TABLE(of, lpc18xx_adc_match); 211a583c24dSJoachim Eastwood 212a583c24dSJoachim Eastwood static struct platform_driver lpc18xx_adc_driver = { 213a583c24dSJoachim Eastwood .probe = lpc18xx_adc_probe, 214a583c24dSJoachim Eastwood .driver = { 215a583c24dSJoachim Eastwood .name = "lpc18xx-adc", 216a583c24dSJoachim Eastwood .of_match_table = lpc18xx_adc_match, 217a583c24dSJoachim Eastwood }, 218a583c24dSJoachim Eastwood }; 219a583c24dSJoachim Eastwood module_platform_driver(lpc18xx_adc_driver); 220a583c24dSJoachim Eastwood 221a583c24dSJoachim Eastwood MODULE_DESCRIPTION("LPC18xx ADC driver"); 222a583c24dSJoachim Eastwood MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>"); 223a583c24dSJoachim Eastwood MODULE_LICENSE("GPL v2"); 224