19f3d0849SStefan Agner // SPDX-License-Identifier: GPL-2.0
29f3d0849SStefan Agner /*
39f3d0849SStefan Agner * STMicroelectronics STMPE811 IIO ADC Driver
49f3d0849SStefan Agner *
59f3d0849SStefan Agner * 4 channel, 10/12-bit ADC
69f3d0849SStefan Agner *
79f3d0849SStefan Agner * Copyright (C) 2013-2018 Toradex AG <stefan.agner@toradex.com>
89f3d0849SStefan Agner */
99f3d0849SStefan Agner
109f3d0849SStefan Agner #include <linux/completion.h>
119f3d0849SStefan Agner #include <linux/err.h>
129f3d0849SStefan Agner #include <linux/iio/iio.h>
139f3d0849SStefan Agner #include <linux/interrupt.h>
149f3d0849SStefan Agner #include <linux/kernel.h>
159f3d0849SStefan Agner #include <linux/mfd/stmpe.h>
169f3d0849SStefan Agner #include <linux/module.h>
17*1240c94cSRob Herring #include <linux/of.h>
189f3d0849SStefan Agner #include <linux/platform_device.h>
199f3d0849SStefan Agner #include <linux/device.h>
209f3d0849SStefan Agner
219f3d0849SStefan Agner #define STMPE_REG_INT_STA 0x0B
229f3d0849SStefan Agner #define STMPE_REG_ADC_INT_EN 0x0E
239f3d0849SStefan Agner #define STMPE_REG_ADC_INT_STA 0x0F
249f3d0849SStefan Agner
259f3d0849SStefan Agner #define STMPE_REG_ADC_CTRL1 0x20
269f3d0849SStefan Agner #define STMPE_REG_ADC_CTRL2 0x21
279f3d0849SStefan Agner #define STMPE_REG_ADC_CAPT 0x22
289f3d0849SStefan Agner #define STMPE_REG_ADC_DATA_CH(channel) (0x30 + 2 * (channel))
299f3d0849SStefan Agner
309f3d0849SStefan Agner #define STMPE_REG_TEMP_CTRL 0x60
319f3d0849SStefan Agner #define STMPE_TEMP_CTRL_ENABLE BIT(0)
329f3d0849SStefan Agner #define STMPE_TEMP_CTRL_ACQ BIT(1)
339f3d0849SStefan Agner #define STMPE_TEMP_CTRL_THRES_EN BIT(3)
349f3d0849SStefan Agner #define STMPE_START_ONE_TEMP_CONV (STMPE_TEMP_CTRL_ENABLE | \
359f3d0849SStefan Agner STMPE_TEMP_CTRL_ACQ | \
369f3d0849SStefan Agner STMPE_TEMP_CTRL_THRES_EN)
379f3d0849SStefan Agner #define STMPE_REG_TEMP_DATA 0x61
389f3d0849SStefan Agner #define STMPE_REG_TEMP_TH 0x63
399f3d0849SStefan Agner #define STMPE_ADC_LAST_NR 7
409f3d0849SStefan Agner #define STMPE_TEMP_CHANNEL (STMPE_ADC_LAST_NR + 1)
419f3d0849SStefan Agner
429f3d0849SStefan Agner #define STMPE_ADC_CH(channel) ((1 << (channel)) & 0xff)
439f3d0849SStefan Agner
449f3d0849SStefan Agner #define STMPE_ADC_TIMEOUT msecs_to_jiffies(1000)
459f3d0849SStefan Agner
469f3d0849SStefan Agner struct stmpe_adc {
479f3d0849SStefan Agner struct stmpe *stmpe;
489f3d0849SStefan Agner struct clk *clk;
499f3d0849SStefan Agner struct device *dev;
509f3d0849SStefan Agner struct mutex lock;
519f3d0849SStefan Agner
529f3d0849SStefan Agner /* We are allocating plus one for the temperature channel */
539f3d0849SStefan Agner struct iio_chan_spec stmpe_adc_iio_channels[STMPE_ADC_LAST_NR + 2];
549f3d0849SStefan Agner
559f3d0849SStefan Agner struct completion completion;
569f3d0849SStefan Agner
579f3d0849SStefan Agner u8 channel;
589f3d0849SStefan Agner u32 value;
599f3d0849SStefan Agner };
609f3d0849SStefan Agner
stmpe_read_voltage(struct stmpe_adc * info,struct iio_chan_spec const * chan,int * val)619f3d0849SStefan Agner static int stmpe_read_voltage(struct stmpe_adc *info,
629f3d0849SStefan Agner struct iio_chan_spec const *chan, int *val)
639f3d0849SStefan Agner {
64d345b232SMiaoqian Lin unsigned long ret;
659f3d0849SStefan Agner
669f3d0849SStefan Agner mutex_lock(&info->lock);
679f3d0849SStefan Agner
68263d21cdSPhilippe Schenker reinit_completion(&info->completion);
69263d21cdSPhilippe Schenker
709f3d0849SStefan Agner info->channel = (u8)chan->channel;
719f3d0849SStefan Agner
729f3d0849SStefan Agner if (info->channel > STMPE_ADC_LAST_NR) {
739f3d0849SStefan Agner mutex_unlock(&info->lock);
749f3d0849SStefan Agner return -EINVAL;
759f3d0849SStefan Agner }
769f3d0849SStefan Agner
779f3d0849SStefan Agner stmpe_reg_write(info->stmpe, STMPE_REG_ADC_CAPT,
789f3d0849SStefan Agner STMPE_ADC_CH(info->channel));
799f3d0849SStefan Agner
80e813dde6SPhilippe Schenker ret = wait_for_completion_timeout(&info->completion, STMPE_ADC_TIMEOUT);
819f3d0849SStefan Agner
82d345b232SMiaoqian Lin if (ret == 0) {
83ed1f310eSPhilippe Schenker stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_STA,
84ed1f310eSPhilippe Schenker STMPE_ADC_CH(info->channel));
859f3d0849SStefan Agner mutex_unlock(&info->lock);
869f3d0849SStefan Agner return -ETIMEDOUT;
879f3d0849SStefan Agner }
889f3d0849SStefan Agner
899f3d0849SStefan Agner *val = info->value;
909f3d0849SStefan Agner
919f3d0849SStefan Agner mutex_unlock(&info->lock);
929f3d0849SStefan Agner
939f3d0849SStefan Agner return 0;
949f3d0849SStefan Agner }
959f3d0849SStefan Agner
stmpe_read_temp(struct stmpe_adc * info,struct iio_chan_spec const * chan,int * val)969f3d0849SStefan Agner static int stmpe_read_temp(struct stmpe_adc *info,
979f3d0849SStefan Agner struct iio_chan_spec const *chan, int *val)
989f3d0849SStefan Agner {
99d345b232SMiaoqian Lin unsigned long ret;
1009f3d0849SStefan Agner
1019f3d0849SStefan Agner mutex_lock(&info->lock);
1029f3d0849SStefan Agner
103263d21cdSPhilippe Schenker reinit_completion(&info->completion);
104263d21cdSPhilippe Schenker
1059f3d0849SStefan Agner info->channel = (u8)chan->channel;
1069f3d0849SStefan Agner
1079f3d0849SStefan Agner if (info->channel != STMPE_TEMP_CHANNEL) {
1089f3d0849SStefan Agner mutex_unlock(&info->lock);
1099f3d0849SStefan Agner return -EINVAL;
1109f3d0849SStefan Agner }
1119f3d0849SStefan Agner
1129f3d0849SStefan Agner stmpe_reg_write(info->stmpe, STMPE_REG_TEMP_CTRL,
1139f3d0849SStefan Agner STMPE_START_ONE_TEMP_CONV);
1149f3d0849SStefan Agner
115e813dde6SPhilippe Schenker ret = wait_for_completion_timeout(&info->completion, STMPE_ADC_TIMEOUT);
1169f3d0849SStefan Agner
117d345b232SMiaoqian Lin if (ret == 0) {
1189f3d0849SStefan Agner mutex_unlock(&info->lock);
1199f3d0849SStefan Agner return -ETIMEDOUT;
1209f3d0849SStefan Agner }
1219f3d0849SStefan Agner
1229f3d0849SStefan Agner /*
1239f3d0849SStefan Agner * absolute temp = +V3.3 * value /7.51 [K]
1249f3d0849SStefan Agner * scale to [milli °C]
1259f3d0849SStefan Agner */
1269f3d0849SStefan Agner *val = ((449960l * info->value) / 1024l) - 273150;
1279f3d0849SStefan Agner
1289f3d0849SStefan Agner mutex_unlock(&info->lock);
1299f3d0849SStefan Agner
1309f3d0849SStefan Agner return 0;
1319f3d0849SStefan Agner }
1329f3d0849SStefan Agner
stmpe_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)1339f3d0849SStefan Agner static int stmpe_read_raw(struct iio_dev *indio_dev,
1349f3d0849SStefan Agner struct iio_chan_spec const *chan,
1359f3d0849SStefan Agner int *val,
1369f3d0849SStefan Agner int *val2,
1379f3d0849SStefan Agner long mask)
1389f3d0849SStefan Agner {
1399f3d0849SStefan Agner struct stmpe_adc *info = iio_priv(indio_dev);
1409f3d0849SStefan Agner long ret;
1419f3d0849SStefan Agner
1429f3d0849SStefan Agner switch (mask) {
1439f3d0849SStefan Agner case IIO_CHAN_INFO_RAW:
1449f3d0849SStefan Agner case IIO_CHAN_INFO_PROCESSED:
1459f3d0849SStefan Agner
1469f3d0849SStefan Agner switch (chan->type) {
1479f3d0849SStefan Agner case IIO_VOLTAGE:
1489f3d0849SStefan Agner ret = stmpe_read_voltage(info, chan, val);
1499f3d0849SStefan Agner break;
1509f3d0849SStefan Agner
1519f3d0849SStefan Agner case IIO_TEMP:
1529f3d0849SStefan Agner ret = stmpe_read_temp(info, chan, val);
1539f3d0849SStefan Agner break;
1549f3d0849SStefan Agner default:
1559f3d0849SStefan Agner return -EINVAL;
1569f3d0849SStefan Agner }
1579f3d0849SStefan Agner
1589f3d0849SStefan Agner if (ret < 0)
1599f3d0849SStefan Agner return ret;
1609f3d0849SStefan Agner
1619f3d0849SStefan Agner return IIO_VAL_INT;
1629f3d0849SStefan Agner
1639f3d0849SStefan Agner case IIO_CHAN_INFO_SCALE:
1649f3d0849SStefan Agner *val = 3300;
1659f3d0849SStefan Agner *val2 = info->stmpe->mod_12b ? 12 : 10;
1669f3d0849SStefan Agner return IIO_VAL_FRACTIONAL_LOG2;
1679f3d0849SStefan Agner
1689f3d0849SStefan Agner default:
1699f3d0849SStefan Agner break;
1709f3d0849SStefan Agner }
1719f3d0849SStefan Agner
1729f3d0849SStefan Agner return -EINVAL;
1739f3d0849SStefan Agner }
1749f3d0849SStefan Agner
stmpe_adc_isr(int irq,void * dev_id)1759f3d0849SStefan Agner static irqreturn_t stmpe_adc_isr(int irq, void *dev_id)
1769f3d0849SStefan Agner {
1779f3d0849SStefan Agner struct stmpe_adc *info = (struct stmpe_adc *)dev_id;
17847f3b26eSJonathan Cameron __be16 data;
1799f3d0849SStefan Agner
1809f3d0849SStefan Agner if (info->channel <= STMPE_ADC_LAST_NR) {
1819f3d0849SStefan Agner int int_sta;
1829f3d0849SStefan Agner
1839f3d0849SStefan Agner int_sta = stmpe_reg_read(info->stmpe, STMPE_REG_ADC_INT_STA);
1849f3d0849SStefan Agner
1859f3d0849SStefan Agner /* Is the interrupt relevant */
1869f3d0849SStefan Agner if (!(int_sta & STMPE_ADC_CH(info->channel)))
1879f3d0849SStefan Agner return IRQ_NONE;
1889f3d0849SStefan Agner
1899f3d0849SStefan Agner /* Read value */
1909f3d0849SStefan Agner stmpe_block_read(info->stmpe,
1919f3d0849SStefan Agner STMPE_REG_ADC_DATA_CH(info->channel), 2, (u8 *) &data);
1929f3d0849SStefan Agner
1939f3d0849SStefan Agner stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_STA, int_sta);
1949f3d0849SStefan Agner } else if (info->channel == STMPE_TEMP_CHANNEL) {
1959f3d0849SStefan Agner /* Read value */
1969f3d0849SStefan Agner stmpe_block_read(info->stmpe, STMPE_REG_TEMP_DATA, 2,
1979f3d0849SStefan Agner (u8 *) &data);
19817104ca2SNathan Chancellor } else {
19917104ca2SNathan Chancellor return IRQ_NONE;
2009f3d0849SStefan Agner }
2019f3d0849SStefan Agner
2029f3d0849SStefan Agner info->value = (u32) be16_to_cpu(data);
2039f3d0849SStefan Agner complete(&info->completion);
2049f3d0849SStefan Agner
2059f3d0849SStefan Agner return IRQ_HANDLED;
2069f3d0849SStefan Agner }
2079f3d0849SStefan Agner
2089f3d0849SStefan Agner static const struct iio_info stmpe_adc_iio_info = {
2099f3d0849SStefan Agner .read_raw = &stmpe_read_raw,
2109f3d0849SStefan Agner };
2119f3d0849SStefan Agner
stmpe_adc_voltage_chan(struct iio_chan_spec * ics,int chan)2129f3d0849SStefan Agner static void stmpe_adc_voltage_chan(struct iio_chan_spec *ics, int chan)
2139f3d0849SStefan Agner {
2149f3d0849SStefan Agner ics->type = IIO_VOLTAGE;
2159f3d0849SStefan Agner ics->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
2169f3d0849SStefan Agner ics->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
2179f3d0849SStefan Agner ics->indexed = 1;
2189f3d0849SStefan Agner ics->channel = chan;
2199f3d0849SStefan Agner }
2209f3d0849SStefan Agner
stmpe_adc_temp_chan(struct iio_chan_spec * ics,int chan)2219f3d0849SStefan Agner static void stmpe_adc_temp_chan(struct iio_chan_spec *ics, int chan)
2229f3d0849SStefan Agner {
2239f3d0849SStefan Agner ics->type = IIO_TEMP;
2249f3d0849SStefan Agner ics->info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED);
2259f3d0849SStefan Agner ics->indexed = 1;
2269f3d0849SStefan Agner ics->channel = chan;
2279f3d0849SStefan Agner }
2289f3d0849SStefan Agner
stmpe_adc_init_hw(struct stmpe_adc * adc)2299f3d0849SStefan Agner static int stmpe_adc_init_hw(struct stmpe_adc *adc)
2309f3d0849SStefan Agner {
2319f3d0849SStefan Agner int ret;
2329f3d0849SStefan Agner struct stmpe *stmpe = adc->stmpe;
2339f3d0849SStefan Agner
2349f3d0849SStefan Agner ret = stmpe_enable(stmpe, STMPE_BLOCK_ADC);
2359f3d0849SStefan Agner if (ret) {
2369f3d0849SStefan Agner dev_err(stmpe->dev, "Could not enable clock for ADC\n");
2379f3d0849SStefan Agner return ret;
2389f3d0849SStefan Agner }
2399f3d0849SStefan Agner
2409f3d0849SStefan Agner ret = stmpe811_adc_common_init(stmpe);
2419f3d0849SStefan Agner if (ret) {
2429f3d0849SStefan Agner stmpe_disable(stmpe, STMPE_BLOCK_ADC);
2439f3d0849SStefan Agner return ret;
2449f3d0849SStefan Agner }
2459f3d0849SStefan Agner
2469f3d0849SStefan Agner /* use temp irq for each conversion completion */
2479f3d0849SStefan Agner stmpe_reg_write(stmpe, STMPE_REG_TEMP_TH, 0);
2489f3d0849SStefan Agner stmpe_reg_write(stmpe, STMPE_REG_TEMP_TH + 1, 0);
2499f3d0849SStefan Agner
2509f3d0849SStefan Agner return 0;
2519f3d0849SStefan Agner }
2529f3d0849SStefan Agner
stmpe_adc_probe(struct platform_device * pdev)2539f3d0849SStefan Agner static int stmpe_adc_probe(struct platform_device *pdev)
2549f3d0849SStefan Agner {
2559f3d0849SStefan Agner struct iio_dev *indio_dev;
2569f3d0849SStefan Agner struct stmpe_adc *info;
2579f3d0849SStefan Agner struct device_node *np;
2589f3d0849SStefan Agner u32 norequest_mask = 0;
2593511989cSKees Cook unsigned long bits;
2609f3d0849SStefan Agner int irq_temp, irq_adc;
2619f3d0849SStefan Agner int num_chan = 0;
2629f3d0849SStefan Agner int i = 0;
2639f3d0849SStefan Agner int ret;
2649f3d0849SStefan Agner
2659f3d0849SStefan Agner irq_adc = platform_get_irq_byname(pdev, "STMPE_ADC");
2669f3d0849SStefan Agner if (irq_adc < 0)
2679f3d0849SStefan Agner return irq_adc;
2689f3d0849SStefan Agner
2699f3d0849SStefan Agner indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct stmpe_adc));
2709f3d0849SStefan Agner if (!indio_dev) {
2719f3d0849SStefan Agner dev_err(&pdev->dev, "failed allocating iio device\n");
2729f3d0849SStefan Agner return -ENOMEM;
2739f3d0849SStefan Agner }
2749f3d0849SStefan Agner
2759f3d0849SStefan Agner info = iio_priv(indio_dev);
2769f3d0849SStefan Agner mutex_init(&info->lock);
2779f3d0849SStefan Agner
2789f3d0849SStefan Agner init_completion(&info->completion);
2799f3d0849SStefan Agner ret = devm_request_threaded_irq(&pdev->dev, irq_adc, NULL,
2809f3d0849SStefan Agner stmpe_adc_isr, IRQF_ONESHOT,
2819f3d0849SStefan Agner "stmpe-adc", info);
2829f3d0849SStefan Agner if (ret < 0) {
2839f3d0849SStefan Agner dev_err(&pdev->dev, "failed requesting irq, irq = %d\n",
2849f3d0849SStefan Agner irq_adc);
2859f3d0849SStefan Agner return ret;
2869f3d0849SStefan Agner }
2879f3d0849SStefan Agner
2889f3d0849SStefan Agner irq_temp = platform_get_irq_byname(pdev, "STMPE_TEMP_SENS");
2899f3d0849SStefan Agner if (irq_temp >= 0) {
2909f3d0849SStefan Agner ret = devm_request_threaded_irq(&pdev->dev, irq_temp, NULL,
2919f3d0849SStefan Agner stmpe_adc_isr, IRQF_ONESHOT,
2929f3d0849SStefan Agner "stmpe-adc", info);
2939f3d0849SStefan Agner if (ret < 0)
2949f3d0849SStefan Agner dev_warn(&pdev->dev, "failed requesting irq for"
2959f3d0849SStefan Agner " temp sensor, irq = %d\n", irq_temp);
2969f3d0849SStefan Agner }
2979f3d0849SStefan Agner
2989f3d0849SStefan Agner platform_set_drvdata(pdev, indio_dev);
2999f3d0849SStefan Agner
3009f3d0849SStefan Agner indio_dev->name = dev_name(&pdev->dev);
3019f3d0849SStefan Agner indio_dev->info = &stmpe_adc_iio_info;
3029f3d0849SStefan Agner indio_dev->modes = INDIO_DIRECT_MODE;
3039f3d0849SStefan Agner
3049f3d0849SStefan Agner info->stmpe = dev_get_drvdata(pdev->dev.parent);
3059f3d0849SStefan Agner
3069f3d0849SStefan Agner np = pdev->dev.of_node;
3079f3d0849SStefan Agner
3089f3d0849SStefan Agner if (!np)
3099f3d0849SStefan Agner dev_err(&pdev->dev, "no device tree node found\n");
3109f3d0849SStefan Agner
3119f3d0849SStefan Agner of_property_read_u32(np, "st,norequest-mask", &norequest_mask);
3129f3d0849SStefan Agner
3133511989cSKees Cook bits = norequest_mask;
3143511989cSKees Cook for_each_clear_bit(i, &bits, (STMPE_ADC_LAST_NR + 1)) {
3159f3d0849SStefan Agner stmpe_adc_voltage_chan(&info->stmpe_adc_iio_channels[num_chan], i);
3169f3d0849SStefan Agner num_chan++;
3179f3d0849SStefan Agner }
3189f3d0849SStefan Agner stmpe_adc_temp_chan(&info->stmpe_adc_iio_channels[num_chan], i);
3199f3d0849SStefan Agner num_chan++;
3209f3d0849SStefan Agner indio_dev->channels = info->stmpe_adc_iio_channels;
3219f3d0849SStefan Agner indio_dev->num_channels = num_chan;
3229f3d0849SStefan Agner
3239f3d0849SStefan Agner ret = stmpe_adc_init_hw(info);
3249f3d0849SStefan Agner if (ret)
3259f3d0849SStefan Agner return ret;
3269f3d0849SStefan Agner
3274bd44bb2SPhilippe Schenker stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_EN,
3284bd44bb2SPhilippe Schenker ~(norequest_mask & 0xFF));
3294bd44bb2SPhilippe Schenker
330ed1f310eSPhilippe Schenker stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_STA,
331ed1f310eSPhilippe Schenker ~(norequest_mask & 0xFF));
332ed1f310eSPhilippe Schenker
3339f3d0849SStefan Agner return devm_iio_device_register(&pdev->dev, indio_dev);
3349f3d0849SStefan Agner }
3359f3d0849SStefan Agner
stmpe_adc_resume(struct device * dev)3360b1e58e9SJonathan Cameron static int stmpe_adc_resume(struct device *dev)
3379f3d0849SStefan Agner {
3389f3d0849SStefan Agner struct iio_dev *indio_dev = dev_get_drvdata(dev);
3399f3d0849SStefan Agner struct stmpe_adc *info = iio_priv(indio_dev);
3409f3d0849SStefan Agner
3419f3d0849SStefan Agner stmpe_adc_init_hw(info);
3429f3d0849SStefan Agner
3439f3d0849SStefan Agner return 0;
3449f3d0849SStefan Agner }
3459f3d0849SStefan Agner
3460b1e58e9SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(stmpe_adc_pm_ops, NULL, stmpe_adc_resume);
3479f3d0849SStefan Agner
3482abd2937SPhilippe Schenker static const struct of_device_id stmpe_adc_ids[] = {
3492abd2937SPhilippe Schenker { .compatible = "st,stmpe-adc", },
3502abd2937SPhilippe Schenker { },
3512abd2937SPhilippe Schenker };
3522abd2937SPhilippe Schenker MODULE_DEVICE_TABLE(of, stmpe_adc_ids);
3532abd2937SPhilippe Schenker
354046dab28SKrzysztof Kozlowski static struct platform_driver stmpe_adc_driver = {
355046dab28SKrzysztof Kozlowski .probe = stmpe_adc_probe,
356046dab28SKrzysztof Kozlowski .driver = {
357046dab28SKrzysztof Kozlowski .name = "stmpe-adc",
3580b1e58e9SJonathan Cameron .pm = pm_sleep_ptr(&stmpe_adc_pm_ops),
359046dab28SKrzysztof Kozlowski .of_match_table = stmpe_adc_ids,
360046dab28SKrzysztof Kozlowski },
361046dab28SKrzysztof Kozlowski };
362046dab28SKrzysztof Kozlowski module_platform_driver(stmpe_adc_driver);
363046dab28SKrzysztof Kozlowski
3649f3d0849SStefan Agner MODULE_AUTHOR("Stefan Agner <stefan.agner@toradex.com>");
3659f3d0849SStefan Agner MODULE_DESCRIPTION("STMPEXXX ADC driver");
3669f3d0849SStefan Agner MODULE_LICENSE("GPL v2");
3679f3d0849SStefan Agner MODULE_ALIAS("platform:stmpe-adc");
368