123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * RZ/G2L A/D Converter driver
- *
- * Copyright (c) 2021 Renesas Electronics Europe GmbH
- *
- * Author: Lad Prabhakar <[email protected]>
- */
- #include <linux/bitfield.h>
- #include <linux/clk.h>
- #include <linux/completion.h>
- #include <linux/delay.h>
- #include <linux/iio/iio.h>
- #include <linux/interrupt.h>
- #include <linux/io.h>
- #include <linux/mod_devicetable.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/pm_runtime.h>
- #include <linux/property.h>
- #include <linux/reset.h>
- #define DRIVER_NAME "rzg2l-adc"
- #define RZG2L_ADM(n) ((n) * 0x4)
- #define RZG2L_ADM0_ADCE BIT(0)
- #define RZG2L_ADM0_ADBSY BIT(1)
- #define RZG2L_ADM0_PWDWNB BIT(2)
- #define RZG2L_ADM0_SRESB BIT(15)
- #define RZG2L_ADM1_TRG BIT(0)
- #define RZG2L_ADM1_MS BIT(2)
- #define RZG2L_ADM1_BS BIT(4)
- #define RZG2L_ADM1_EGA_MASK GENMASK(13, 12)
- #define RZG2L_ADM2_CHSEL_MASK GENMASK(7, 0)
- #define RZG2L_ADM3_ADIL_MASK GENMASK(31, 24)
- #define RZG2L_ADM3_ADCMP_MASK GENMASK(23, 16)
- #define RZG2L_ADM3_ADCMP_E FIELD_PREP(RZG2L_ADM3_ADCMP_MASK, 0xe)
- #define RZG2L_ADM3_ADSMP_MASK GENMASK(15, 0)
- #define RZG2L_ADINT 0x20
- #define RZG2L_ADINT_INTEN_MASK GENMASK(7, 0)
- #define RZG2L_ADINT_CSEEN BIT(16)
- #define RZG2L_ADINT_INTS BIT(31)
- #define RZG2L_ADSTS 0x24
- #define RZG2L_ADSTS_CSEST BIT(16)
- #define RZG2L_ADSTS_INTST_MASK GENMASK(7, 0)
- #define RZG2L_ADIVC 0x28
- #define RZG2L_ADIVC_DIVADC_MASK GENMASK(8, 0)
- #define RZG2L_ADIVC_DIVADC_4 FIELD_PREP(RZG2L_ADIVC_DIVADC_MASK, 0x4)
- #define RZG2L_ADFIL 0x2c
- #define RZG2L_ADCR(n) (0x30 + ((n) * 0x4))
- #define RZG2L_ADCR_AD_MASK GENMASK(11, 0)
- #define RZG2L_ADSMP_DEFAULT_SAMPLING 0x578
- #define RZG2L_ADC_MAX_CHANNELS 8
- #define RZG2L_ADC_CHN_MASK 0x7
- #define RZG2L_ADC_TIMEOUT usecs_to_jiffies(1 * 4)
- struct rzg2l_adc_data {
- const struct iio_chan_spec *channels;
- u8 num_channels;
- };
- struct rzg2l_adc {
- void __iomem *base;
- struct clk *pclk;
- struct clk *adclk;
- struct reset_control *presetn;
- struct reset_control *adrstn;
- struct completion completion;
- const struct rzg2l_adc_data *data;
- struct mutex lock;
- u16 last_val[RZG2L_ADC_MAX_CHANNELS];
- };
- static const char * const rzg2l_adc_channel_name[] = {
- "adc0",
- "adc1",
- "adc2",
- "adc3",
- "adc4",
- "adc5",
- "adc6",
- "adc7",
- };
- static unsigned int rzg2l_adc_readl(struct rzg2l_adc *adc, u32 reg)
- {
- return readl(adc->base + reg);
- }
- static void rzg2l_adc_writel(struct rzg2l_adc *adc, unsigned int reg, u32 val)
- {
- writel(val, adc->base + reg);
- }
- static void rzg2l_adc_pwr(struct rzg2l_adc *adc, bool on)
- {
- u32 reg;
- reg = rzg2l_adc_readl(adc, RZG2L_ADM(0));
- if (on)
- reg |= RZG2L_ADM0_PWDWNB;
- else
- reg &= ~RZG2L_ADM0_PWDWNB;
- rzg2l_adc_writel(adc, RZG2L_ADM(0), reg);
- udelay(2);
- }
- static void rzg2l_adc_start_stop(struct rzg2l_adc *adc, bool start)
- {
- int timeout = 5;
- u32 reg;
- reg = rzg2l_adc_readl(adc, RZG2L_ADM(0));
- if (start)
- reg |= RZG2L_ADM0_ADCE;
- else
- reg &= ~RZG2L_ADM0_ADCE;
- rzg2l_adc_writel(adc, RZG2L_ADM(0), reg);
- if (start)
- return;
- do {
- usleep_range(100, 200);
- reg = rzg2l_adc_readl(adc, RZG2L_ADM(0));
- timeout--;
- if (!timeout) {
- pr_err("%s stopping ADC timed out\n", __func__);
- break;
- }
- } while (((reg & RZG2L_ADM0_ADBSY) || (reg & RZG2L_ADM0_ADCE)));
- }
- static void rzg2l_set_trigger(struct rzg2l_adc *adc)
- {
- u32 reg;
- /*
- * Setup ADM1 for SW trigger
- * EGA[13:12] - Set 00 to indicate hardware trigger is invalid
- * BS[4] - Enable 1-buffer mode
- * MS[1] - Enable Select mode
- * TRG[0] - Enable software trigger mode
- */
- reg = rzg2l_adc_readl(adc, RZG2L_ADM(1));
- reg &= ~RZG2L_ADM1_EGA_MASK;
- reg &= ~RZG2L_ADM1_BS;
- reg &= ~RZG2L_ADM1_TRG;
- reg |= RZG2L_ADM1_MS;
- rzg2l_adc_writel(adc, RZG2L_ADM(1), reg);
- }
- static int rzg2l_adc_conversion_setup(struct rzg2l_adc *adc, u8 ch)
- {
- u32 reg;
- if (rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_ADBSY)
- return -EBUSY;
- rzg2l_set_trigger(adc);
- /* Select analog input channel subjected to conversion. */
- reg = rzg2l_adc_readl(adc, RZG2L_ADM(2));
- reg &= ~RZG2L_ADM2_CHSEL_MASK;
- reg |= BIT(ch);
- rzg2l_adc_writel(adc, RZG2L_ADM(2), reg);
- /*
- * Setup ADINT
- * INTS[31] - Select pulse signal
- * CSEEN[16] - Enable channel select error interrupt
- * INTEN[7:0] - Select channel interrupt
- */
- reg = rzg2l_adc_readl(adc, RZG2L_ADINT);
- reg &= ~RZG2L_ADINT_INTS;
- reg &= ~RZG2L_ADINT_INTEN_MASK;
- reg |= (RZG2L_ADINT_CSEEN | BIT(ch));
- rzg2l_adc_writel(adc, RZG2L_ADINT, reg);
- return 0;
- }
- static int rzg2l_adc_set_power(struct iio_dev *indio_dev, bool on)
- {
- struct device *dev = indio_dev->dev.parent;
- if (on)
- return pm_runtime_resume_and_get(dev);
- return pm_runtime_put_sync(dev);
- }
- static int rzg2l_adc_conversion(struct iio_dev *indio_dev, struct rzg2l_adc *adc, u8 ch)
- {
- int ret;
- ret = rzg2l_adc_set_power(indio_dev, true);
- if (ret)
- return ret;
- ret = rzg2l_adc_conversion_setup(adc, ch);
- if (ret) {
- rzg2l_adc_set_power(indio_dev, false);
- return ret;
- }
- reinit_completion(&adc->completion);
- rzg2l_adc_start_stop(adc, true);
- if (!wait_for_completion_timeout(&adc->completion, RZG2L_ADC_TIMEOUT)) {
- rzg2l_adc_writel(adc, RZG2L_ADINT,
- rzg2l_adc_readl(adc, RZG2L_ADINT) & ~RZG2L_ADINT_INTEN_MASK);
- rzg2l_adc_start_stop(adc, false);
- rzg2l_adc_set_power(indio_dev, false);
- return -ETIMEDOUT;
- }
- return rzg2l_adc_set_power(indio_dev, false);
- }
- static int rzg2l_adc_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2, long mask)
- {
- struct rzg2l_adc *adc = iio_priv(indio_dev);
- int ret;
- u8 ch;
- switch (mask) {
- case IIO_CHAN_INFO_RAW:
- if (chan->type != IIO_VOLTAGE)
- return -EINVAL;
- mutex_lock(&adc->lock);
- ch = chan->channel & RZG2L_ADC_CHN_MASK;
- ret = rzg2l_adc_conversion(indio_dev, adc, ch);
- if (ret) {
- mutex_unlock(&adc->lock);
- return ret;
- }
- *val = adc->last_val[ch];
- mutex_unlock(&adc->lock);
- return IIO_VAL_INT;
- default:
- return -EINVAL;
- }
- }
- static int rzg2l_adc_read_label(struct iio_dev *iio_dev,
- const struct iio_chan_spec *chan,
- char *label)
- {
- return sysfs_emit(label, "%s\n", rzg2l_adc_channel_name[chan->channel]);
- }
- static const struct iio_info rzg2l_adc_iio_info = {
- .read_raw = rzg2l_adc_read_raw,
- .read_label = rzg2l_adc_read_label,
- };
- static irqreturn_t rzg2l_adc_isr(int irq, void *dev_id)
- {
- struct rzg2l_adc *adc = dev_id;
- unsigned long intst;
- u32 reg;
- int ch;
- reg = rzg2l_adc_readl(adc, RZG2L_ADSTS);
- /* A/D conversion channel select error interrupt */
- if (reg & RZG2L_ADSTS_CSEST) {
- rzg2l_adc_writel(adc, RZG2L_ADSTS, reg);
- return IRQ_HANDLED;
- }
- intst = reg & RZG2L_ADSTS_INTST_MASK;
- if (!intst)
- return IRQ_NONE;
- for_each_set_bit(ch, &intst, RZG2L_ADC_MAX_CHANNELS)
- adc->last_val[ch] = rzg2l_adc_readl(adc, RZG2L_ADCR(ch)) & RZG2L_ADCR_AD_MASK;
- /* clear the channel interrupt */
- rzg2l_adc_writel(adc, RZG2L_ADSTS, reg);
- complete(&adc->completion);
- return IRQ_HANDLED;
- }
- static int rzg2l_adc_parse_properties(struct platform_device *pdev, struct rzg2l_adc *adc)
- {
- struct iio_chan_spec *chan_array;
- struct fwnode_handle *fwnode;
- struct rzg2l_adc_data *data;
- unsigned int channel;
- int num_channels;
- int ret;
- u8 i;
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
- num_channels = device_get_child_node_count(&pdev->dev);
- if (!num_channels) {
- dev_err(&pdev->dev, "no channel children\n");
- return -ENODEV;
- }
- if (num_channels > RZG2L_ADC_MAX_CHANNELS) {
- dev_err(&pdev->dev, "num of channel children out of range\n");
- return -EINVAL;
- }
- chan_array = devm_kcalloc(&pdev->dev, num_channels, sizeof(*chan_array),
- GFP_KERNEL);
- if (!chan_array)
- return -ENOMEM;
- i = 0;
- device_for_each_child_node(&pdev->dev, fwnode) {
- ret = fwnode_property_read_u32(fwnode, "reg", &channel);
- if (ret) {
- fwnode_handle_put(fwnode);
- return ret;
- }
- if (channel >= RZG2L_ADC_MAX_CHANNELS) {
- fwnode_handle_put(fwnode);
- return -EINVAL;
- }
- chan_array[i].type = IIO_VOLTAGE;
- chan_array[i].indexed = 1;
- chan_array[i].channel = channel;
- chan_array[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
- chan_array[i].datasheet_name = rzg2l_adc_channel_name[channel];
- i++;
- }
- data->num_channels = num_channels;
- data->channels = chan_array;
- adc->data = data;
- return 0;
- }
- static int rzg2l_adc_hw_init(struct rzg2l_adc *adc)
- {
- int timeout = 5;
- u32 reg;
- int ret;
- ret = clk_prepare_enable(adc->pclk);
- if (ret)
- return ret;
- /* SW reset */
- reg = rzg2l_adc_readl(adc, RZG2L_ADM(0));
- reg |= RZG2L_ADM0_SRESB;
- rzg2l_adc_writel(adc, RZG2L_ADM(0), reg);
- while (!(rzg2l_adc_readl(adc, RZG2L_ADM(0)) & RZG2L_ADM0_SRESB)) {
- if (!timeout) {
- ret = -EBUSY;
- goto exit_hw_init;
- }
- timeout--;
- usleep_range(100, 200);
- }
- /* Only division by 4 can be set */
- reg = rzg2l_adc_readl(adc, RZG2L_ADIVC);
- reg &= ~RZG2L_ADIVC_DIVADC_MASK;
- reg |= RZG2L_ADIVC_DIVADC_4;
- rzg2l_adc_writel(adc, RZG2L_ADIVC, reg);
- /*
- * Setup AMD3
- * ADIL[31:24] - Should be always set to 0
- * ADCMP[23:16] - Should be always set to 0xe
- * ADSMP[15:0] - Set default (0x578) sampling period
- */
- reg = rzg2l_adc_readl(adc, RZG2L_ADM(3));
- reg &= ~RZG2L_ADM3_ADIL_MASK;
- reg &= ~RZG2L_ADM3_ADCMP_MASK;
- reg &= ~RZG2L_ADM3_ADSMP_MASK;
- reg |= (RZG2L_ADM3_ADCMP_E | RZG2L_ADSMP_DEFAULT_SAMPLING);
- rzg2l_adc_writel(adc, RZG2L_ADM(3), reg);
- exit_hw_init:
- clk_disable_unprepare(adc->pclk);
- return ret;
- }
- static void rzg2l_adc_pm_runtime_disable(void *data)
- {
- struct device *dev = data;
- pm_runtime_disable(dev->parent);
- }
- static void rzg2l_adc_pm_runtime_set_suspended(void *data)
- {
- struct device *dev = data;
- pm_runtime_set_suspended(dev->parent);
- }
- static void rzg2l_adc_reset_assert(void *data)
- {
- reset_control_assert(data);
- }
- static int rzg2l_adc_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
- struct iio_dev *indio_dev;
- struct rzg2l_adc *adc;
- int ret;
- int irq;
- indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
- if (!indio_dev)
- return -ENOMEM;
- adc = iio_priv(indio_dev);
- ret = rzg2l_adc_parse_properties(pdev, adc);
- if (ret)
- return ret;
- mutex_init(&adc->lock);
- adc->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(adc->base))
- return PTR_ERR(adc->base);
- adc->pclk = devm_clk_get(dev, "pclk");
- if (IS_ERR(adc->pclk)) {
- dev_err(dev, "Failed to get pclk");
- return PTR_ERR(adc->pclk);
- }
- adc->adclk = devm_clk_get(dev, "adclk");
- if (IS_ERR(adc->adclk)) {
- dev_err(dev, "Failed to get adclk");
- return PTR_ERR(adc->adclk);
- }
- adc->adrstn = devm_reset_control_get_exclusive(dev, "adrst-n");
- if (IS_ERR(adc->adrstn)) {
- dev_err(dev, "failed to get adrstn\n");
- return PTR_ERR(adc->adrstn);
- }
- adc->presetn = devm_reset_control_get_exclusive(dev, "presetn");
- if (IS_ERR(adc->presetn)) {
- dev_err(dev, "failed to get presetn\n");
- return PTR_ERR(adc->presetn);
- }
- ret = reset_control_deassert(adc->adrstn);
- if (ret) {
- dev_err(&pdev->dev, "failed to deassert adrstn pin, %d\n", ret);
- return ret;
- }
- ret = devm_add_action_or_reset(&pdev->dev,
- rzg2l_adc_reset_assert, adc->adrstn);
- if (ret) {
- dev_err(&pdev->dev, "failed to register adrstn assert devm action, %d\n",
- ret);
- return ret;
- }
- ret = reset_control_deassert(adc->presetn);
- if (ret) {
- dev_err(&pdev->dev, "failed to deassert presetn pin, %d\n", ret);
- return ret;
- }
- ret = devm_add_action_or_reset(&pdev->dev,
- rzg2l_adc_reset_assert, adc->presetn);
- if (ret) {
- dev_err(&pdev->dev, "failed to register presetn assert devm action, %d\n",
- ret);
- return ret;
- }
- ret = rzg2l_adc_hw_init(adc);
- if (ret) {
- dev_err(&pdev->dev, "failed to initialize ADC HW, %d\n", ret);
- return ret;
- }
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
- ret = devm_request_irq(dev, irq, rzg2l_adc_isr,
- 0, dev_name(dev), adc);
- if (ret < 0)
- return ret;
- init_completion(&adc->completion);
- platform_set_drvdata(pdev, indio_dev);
- indio_dev->name = DRIVER_NAME;
- indio_dev->info = &rzg2l_adc_iio_info;
- indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = adc->data->channels;
- indio_dev->num_channels = adc->data->num_channels;
- pm_runtime_set_suspended(dev);
- ret = devm_add_action_or_reset(&pdev->dev,
- rzg2l_adc_pm_runtime_set_suspended, &indio_dev->dev);
- if (ret)
- return ret;
- pm_runtime_enable(dev);
- ret = devm_add_action_or_reset(&pdev->dev,
- rzg2l_adc_pm_runtime_disable, &indio_dev->dev);
- if (ret)
- return ret;
- return devm_iio_device_register(dev, indio_dev);
- }
- static const struct of_device_id rzg2l_adc_match[] = {
- { .compatible = "renesas,rzg2l-adc",},
- { /* sentinel */ }
- };
- MODULE_DEVICE_TABLE(of, rzg2l_adc_match);
- static int __maybe_unused rzg2l_adc_pm_runtime_suspend(struct device *dev)
- {
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct rzg2l_adc *adc = iio_priv(indio_dev);
- rzg2l_adc_pwr(adc, false);
- clk_disable_unprepare(adc->adclk);
- clk_disable_unprepare(adc->pclk);
- return 0;
- }
- static int __maybe_unused rzg2l_adc_pm_runtime_resume(struct device *dev)
- {
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct rzg2l_adc *adc = iio_priv(indio_dev);
- int ret;
- ret = clk_prepare_enable(adc->pclk);
- if (ret)
- return ret;
- ret = clk_prepare_enable(adc->adclk);
- if (ret) {
- clk_disable_unprepare(adc->pclk);
- return ret;
- }
- rzg2l_adc_pwr(adc, true);
- return 0;
- }
- static const struct dev_pm_ops rzg2l_adc_pm_ops = {
- SET_RUNTIME_PM_OPS(rzg2l_adc_pm_runtime_suspend,
- rzg2l_adc_pm_runtime_resume,
- NULL)
- };
- static struct platform_driver rzg2l_adc_driver = {
- .probe = rzg2l_adc_probe,
- .driver = {
- .name = DRIVER_NAME,
- .of_match_table = rzg2l_adc_match,
- .pm = &rzg2l_adc_pm_ops,
- },
- };
- module_platform_driver(rzg2l_adc_driver);
- MODULE_AUTHOR("Lad Prabhakar <[email protected]>");
- MODULE_DESCRIPTION("Renesas RZ/G2L ADC driver");
- MODULE_LICENSE("GPL v2");
|