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> 207db52e25SAndy Shevchenko #include <linux/mod_devicetable.h> 21a583c24dSJoachim Eastwood #include <linux/module.h> 22a583c24dSJoachim Eastwood #include <linux/mutex.h> 23a583c24dSJoachim Eastwood #include <linux/platform_device.h> 24a583c24dSJoachim Eastwood #include <linux/regulator/consumer.h> 25a583c24dSJoachim Eastwood 26a583c24dSJoachim Eastwood /* LPC18XX ADC registers and bits */ 27a583c24dSJoachim Eastwood #define LPC18XX_ADC_CR 0x000 28a583c24dSJoachim Eastwood #define LPC18XX_ADC_CR_CLKDIV_SHIFT 8 29a583c24dSJoachim Eastwood #define LPC18XX_ADC_CR_PDN BIT(21) 30a583c24dSJoachim Eastwood #define LPC18XX_ADC_CR_START_NOW (0x1 << 24) 31a583c24dSJoachim Eastwood #define LPC18XX_ADC_GDR 0x004 32a583c24dSJoachim Eastwood 33a583c24dSJoachim Eastwood /* Data register bits */ 34a583c24dSJoachim Eastwood #define LPC18XX_ADC_SAMPLE_SHIFT 6 35a583c24dSJoachim Eastwood #define LPC18XX_ADC_SAMPLE_MASK 0x3ff 36a583c24dSJoachim Eastwood #define LPC18XX_ADC_CONV_DONE BIT(31) 37a583c24dSJoachim Eastwood 38a583c24dSJoachim Eastwood /* Clock should be 4.5 MHz or less */ 39a583c24dSJoachim Eastwood #define LPC18XX_ADC_CLK_TARGET 4500000 40a583c24dSJoachim Eastwood 41a583c24dSJoachim Eastwood struct lpc18xx_adc { 42a583c24dSJoachim Eastwood struct regulator *vref; 43a583c24dSJoachim Eastwood void __iomem *base; 44a583c24dSJoachim Eastwood struct device *dev; 45a583c24dSJoachim Eastwood struct mutex lock; 46a583c24dSJoachim Eastwood struct clk *clk; 47a583c24dSJoachim Eastwood u32 cr_reg; 48a583c24dSJoachim Eastwood }; 49a583c24dSJoachim Eastwood 50a583c24dSJoachim Eastwood #define LPC18XX_ADC_CHAN(_idx) { \ 51a583c24dSJoachim Eastwood .type = IIO_VOLTAGE, \ 52a583c24dSJoachim Eastwood .indexed = 1, \ 53a583c24dSJoachim Eastwood .channel = _idx, \ 54a583c24dSJoachim Eastwood .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 55a583c24dSJoachim Eastwood .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 56a583c24dSJoachim Eastwood } 57a583c24dSJoachim Eastwood 58a583c24dSJoachim Eastwood static const struct iio_chan_spec lpc18xx_adc_iio_channels[] = { 59a583c24dSJoachim Eastwood LPC18XX_ADC_CHAN(0), 60a583c24dSJoachim Eastwood LPC18XX_ADC_CHAN(1), 61a583c24dSJoachim Eastwood LPC18XX_ADC_CHAN(2), 62a583c24dSJoachim Eastwood LPC18XX_ADC_CHAN(3), 63a583c24dSJoachim Eastwood LPC18XX_ADC_CHAN(4), 64a583c24dSJoachim Eastwood LPC18XX_ADC_CHAN(5), 65a583c24dSJoachim Eastwood LPC18XX_ADC_CHAN(6), 66a583c24dSJoachim Eastwood LPC18XX_ADC_CHAN(7), 67a583c24dSJoachim Eastwood }; 68a583c24dSJoachim Eastwood 69a583c24dSJoachim Eastwood static int lpc18xx_adc_read_chan(struct lpc18xx_adc *adc, unsigned int ch) 70a583c24dSJoachim Eastwood { 71a583c24dSJoachim Eastwood int ret; 72a583c24dSJoachim Eastwood u32 reg; 73a583c24dSJoachim Eastwood 74a583c24dSJoachim Eastwood reg = adc->cr_reg | BIT(ch) | LPC18XX_ADC_CR_START_NOW; 75a583c24dSJoachim Eastwood writel(reg, adc->base + LPC18XX_ADC_CR); 76a583c24dSJoachim Eastwood 77a583c24dSJoachim Eastwood ret = readl_poll_timeout(adc->base + LPC18XX_ADC_GDR, reg, 78a583c24dSJoachim Eastwood reg & LPC18XX_ADC_CONV_DONE, 3, 9); 79a583c24dSJoachim Eastwood if (ret) { 80a583c24dSJoachim Eastwood dev_warn(adc->dev, "adc read timed out\n"); 81a583c24dSJoachim Eastwood return ret; 82a583c24dSJoachim Eastwood } 83a583c24dSJoachim Eastwood 84a583c24dSJoachim Eastwood return (reg >> LPC18XX_ADC_SAMPLE_SHIFT) & LPC18XX_ADC_SAMPLE_MASK; 85a583c24dSJoachim Eastwood } 86a583c24dSJoachim Eastwood 87a583c24dSJoachim Eastwood static int lpc18xx_adc_read_raw(struct iio_dev *indio_dev, 88a583c24dSJoachim Eastwood struct iio_chan_spec const *chan, 89a583c24dSJoachim Eastwood int *val, int *val2, long mask) 90a583c24dSJoachim Eastwood { 91a583c24dSJoachim Eastwood struct lpc18xx_adc *adc = iio_priv(indio_dev); 92a583c24dSJoachim Eastwood 93a583c24dSJoachim Eastwood switch (mask) { 94a583c24dSJoachim Eastwood case IIO_CHAN_INFO_RAW: 95a583c24dSJoachim Eastwood mutex_lock(&adc->lock); 96a583c24dSJoachim Eastwood *val = lpc18xx_adc_read_chan(adc, chan->channel); 97a583c24dSJoachim Eastwood mutex_unlock(&adc->lock); 98a583c24dSJoachim Eastwood if (*val < 0) 99a583c24dSJoachim Eastwood return *val; 100a583c24dSJoachim Eastwood 101a583c24dSJoachim Eastwood return IIO_VAL_INT; 102a583c24dSJoachim Eastwood 103a583c24dSJoachim Eastwood case IIO_CHAN_INFO_SCALE: 104a583c24dSJoachim Eastwood *val = regulator_get_voltage(adc->vref) / 1000; 105a583c24dSJoachim Eastwood *val2 = 10; 106a583c24dSJoachim Eastwood 107a583c24dSJoachim Eastwood return IIO_VAL_FRACTIONAL_LOG2; 108a583c24dSJoachim Eastwood } 109a583c24dSJoachim Eastwood 110a583c24dSJoachim Eastwood return -EINVAL; 111a583c24dSJoachim Eastwood } 112a583c24dSJoachim Eastwood 113a583c24dSJoachim Eastwood static const struct iio_info lpc18xx_adc_info = { 114a583c24dSJoachim Eastwood .read_raw = lpc18xx_adc_read_raw, 115a583c24dSJoachim Eastwood }; 116a583c24dSJoachim Eastwood 1170be84447SAndré Gustavo Nakagomi Lopez static void lpc18xx_clear_cr_reg(void *data) 1180be84447SAndré Gustavo Nakagomi Lopez { 1190be84447SAndré Gustavo Nakagomi Lopez struct lpc18xx_adc *adc = data; 1200be84447SAndré Gustavo Nakagomi Lopez 1210be84447SAndré Gustavo Nakagomi Lopez writel(0, adc->base + LPC18XX_ADC_CR); 1220be84447SAndré Gustavo Nakagomi Lopez } 1230be84447SAndré Gustavo Nakagomi Lopez 1240be84447SAndré Gustavo Nakagomi Lopez static void lpc18xx_regulator_disable(void *vref) 1250be84447SAndré Gustavo Nakagomi Lopez { 1260be84447SAndré Gustavo Nakagomi Lopez regulator_disable(vref); 1270be84447SAndré Gustavo Nakagomi Lopez } 1280be84447SAndré Gustavo Nakagomi Lopez 129a583c24dSJoachim Eastwood static int lpc18xx_adc_probe(struct platform_device *pdev) 130a583c24dSJoachim Eastwood { 131a583c24dSJoachim Eastwood struct iio_dev *indio_dev; 132a583c24dSJoachim Eastwood struct lpc18xx_adc *adc; 133a583c24dSJoachim Eastwood unsigned int clkdiv; 134a583c24dSJoachim Eastwood unsigned long rate; 135a583c24dSJoachim Eastwood int ret; 136a583c24dSJoachim Eastwood 137a583c24dSJoachim Eastwood indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc)); 138a583c24dSJoachim Eastwood if (!indio_dev) 139a583c24dSJoachim Eastwood return -ENOMEM; 140a583c24dSJoachim Eastwood 141a583c24dSJoachim Eastwood adc = iio_priv(indio_dev); 142a583c24dSJoachim Eastwood adc->dev = &pdev->dev; 143a583c24dSJoachim Eastwood mutex_init(&adc->lock); 144a583c24dSJoachim Eastwood 14518d031f4SJonathan Cameron adc->base = devm_platform_ioremap_resource(pdev, 0); 146a583c24dSJoachim Eastwood if (IS_ERR(adc->base)) 147a583c24dSJoachim Eastwood return PTR_ERR(adc->base); 148a583c24dSJoachim Eastwood 149*4004912eSUwe Kleine-König adc->clk = devm_clk_get_enabled(&pdev->dev, NULL); 150922f694bSCai Huoqing if (IS_ERR(adc->clk)) 151922f694bSCai Huoqing return dev_err_probe(&pdev->dev, PTR_ERR(adc->clk), 152922f694bSCai Huoqing "error getting clock\n"); 153a583c24dSJoachim Eastwood 154a583c24dSJoachim Eastwood adc->vref = devm_regulator_get(&pdev->dev, "vref"); 155922f694bSCai Huoqing if (IS_ERR(adc->vref)) 156922f694bSCai Huoqing return dev_err_probe(&pdev->dev, PTR_ERR(adc->vref), 157922f694bSCai Huoqing "error getting regulator\n"); 158a583c24dSJoachim Eastwood 159a583c24dSJoachim Eastwood indio_dev->name = dev_name(&pdev->dev); 160a583c24dSJoachim Eastwood indio_dev->info = &lpc18xx_adc_info; 161a583c24dSJoachim Eastwood indio_dev->modes = INDIO_DIRECT_MODE; 162a583c24dSJoachim Eastwood indio_dev->channels = lpc18xx_adc_iio_channels; 163a583c24dSJoachim Eastwood indio_dev->num_channels = ARRAY_SIZE(lpc18xx_adc_iio_channels); 164a583c24dSJoachim Eastwood 165a583c24dSJoachim Eastwood ret = regulator_enable(adc->vref); 166a583c24dSJoachim Eastwood if (ret) { 167a583c24dSJoachim Eastwood dev_err(&pdev->dev, "unable to enable regulator\n"); 168a583c24dSJoachim Eastwood return ret; 169a583c24dSJoachim Eastwood } 170a583c24dSJoachim Eastwood 1710be84447SAndré Gustavo Nakagomi Lopez ret = devm_add_action_or_reset(&pdev->dev, lpc18xx_regulator_disable, adc->vref); 1720be84447SAndré Gustavo Nakagomi Lopez if (ret) 1730be84447SAndré Gustavo Nakagomi Lopez return ret; 1740be84447SAndré Gustavo Nakagomi Lopez 1758eebe628SAndré Gustavo Nakagomi Lopez rate = clk_get_rate(adc->clk); 1768eebe628SAndré Gustavo Nakagomi Lopez clkdiv = DIV_ROUND_UP(rate, LPC18XX_ADC_CLK_TARGET); 1778eebe628SAndré Gustavo Nakagomi Lopez 178a583c24dSJoachim Eastwood adc->cr_reg = (clkdiv << LPC18XX_ADC_CR_CLKDIV_SHIFT) | 179a583c24dSJoachim Eastwood LPC18XX_ADC_CR_PDN; 180a583c24dSJoachim Eastwood writel(adc->cr_reg, adc->base + LPC18XX_ADC_CR); 181a583c24dSJoachim Eastwood 1820be84447SAndré Gustavo Nakagomi Lopez ret = devm_add_action_or_reset(&pdev->dev, lpc18xx_clear_cr_reg, adc); 1830be84447SAndré Gustavo Nakagomi Lopez if (ret) 184a583c24dSJoachim Eastwood return ret; 185a583c24dSJoachim Eastwood 1860be84447SAndré Gustavo Nakagomi Lopez return devm_iio_device_register(&pdev->dev, indio_dev); 187a583c24dSJoachim Eastwood } 188a583c24dSJoachim Eastwood 189a583c24dSJoachim Eastwood static const struct of_device_id lpc18xx_adc_match[] = { 190a583c24dSJoachim Eastwood { .compatible = "nxp,lpc1850-adc" }, 191a583c24dSJoachim Eastwood { /* sentinel */ } 192a583c24dSJoachim Eastwood }; 193a583c24dSJoachim Eastwood MODULE_DEVICE_TABLE(of, lpc18xx_adc_match); 194a583c24dSJoachim Eastwood 195a583c24dSJoachim Eastwood static struct platform_driver lpc18xx_adc_driver = { 196a583c24dSJoachim Eastwood .probe = lpc18xx_adc_probe, 197a583c24dSJoachim Eastwood .driver = { 198a583c24dSJoachim Eastwood .name = "lpc18xx-adc", 199a583c24dSJoachim Eastwood .of_match_table = lpc18xx_adc_match, 200a583c24dSJoachim Eastwood }, 201a583c24dSJoachim Eastwood }; 202a583c24dSJoachim Eastwood module_platform_driver(lpc18xx_adc_driver); 203a583c24dSJoachim Eastwood 204a583c24dSJoachim Eastwood MODULE_DESCRIPTION("LPC18xx ADC driver"); 205a583c24dSJoachim Eastwood MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>"); 206a583c24dSJoachim Eastwood MODULE_LICENSE("GPL v2"); 207