cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fsl-imx25-gcq.c (10388B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2014-2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de>
      4 *
      5 * This is the driver for the imx25 GCQ (Generic Conversion Queue)
      6 * connected to the imx25 ADC.
      7 */
      8
      9#include <dt-bindings/iio/adc/fsl-imx25-gcq.h>
     10#include <linux/clk.h>
     11#include <linux/iio/iio.h>
     12#include <linux/interrupt.h>
     13#include <linux/mfd/imx25-tsadc.h>
     14#include <linux/module.h>
     15#include <linux/of.h>
     16#include <linux/platform_device.h>
     17#include <linux/regmap.h>
     18#include <linux/regulator/consumer.h>
     19
     20#define MX25_GCQ_TIMEOUT (msecs_to_jiffies(2000))
     21
     22static const char * const driver_name = "mx25-gcq";
     23
     24enum mx25_gcq_cfgs {
     25	MX25_CFG_XP = 0,
     26	MX25_CFG_YP,
     27	MX25_CFG_XN,
     28	MX25_CFG_YN,
     29	MX25_CFG_WIPER,
     30	MX25_CFG_INAUX0,
     31	MX25_CFG_INAUX1,
     32	MX25_CFG_INAUX2,
     33	MX25_NUM_CFGS,
     34};
     35
     36struct mx25_gcq_priv {
     37	struct regmap *regs;
     38	struct completion completed;
     39	struct clk *clk;
     40	int irq;
     41	struct regulator *vref[4];
     42	u32 channel_vref_mv[MX25_NUM_CFGS];
     43	/*
     44	 * Lock to protect the device state during a potential concurrent
     45	 * read access from userspace. Reading a raw value requires a sequence
     46	 * of register writes, then a wait for a completion callback,
     47	 * and finally a register read, during which userspace could issue
     48	 * another read request. This lock protects a read access from
     49	 * ocurring before another one has finished.
     50	 */
     51	struct mutex lock;
     52};
     53
     54#define MX25_CQG_CHAN(chan, id) {\
     55	.type = IIO_VOLTAGE,\
     56	.indexed = 1,\
     57	.channel = chan,\
     58	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
     59			      BIT(IIO_CHAN_INFO_SCALE),\
     60	.datasheet_name = id,\
     61}
     62
     63static const struct iio_chan_spec mx25_gcq_channels[MX25_NUM_CFGS] = {
     64	MX25_CQG_CHAN(MX25_CFG_XP, "xp"),
     65	MX25_CQG_CHAN(MX25_CFG_YP, "yp"),
     66	MX25_CQG_CHAN(MX25_CFG_XN, "xn"),
     67	MX25_CQG_CHAN(MX25_CFG_YN, "yn"),
     68	MX25_CQG_CHAN(MX25_CFG_WIPER, "wiper"),
     69	MX25_CQG_CHAN(MX25_CFG_INAUX0, "inaux0"),
     70	MX25_CQG_CHAN(MX25_CFG_INAUX1, "inaux1"),
     71	MX25_CQG_CHAN(MX25_CFG_INAUX2, "inaux2"),
     72};
     73
     74static const char * const mx25_gcq_refp_names[] = {
     75	[MX25_ADC_REFP_YP] = "yp",
     76	[MX25_ADC_REFP_XP] = "xp",
     77	[MX25_ADC_REFP_INT] = "int",
     78	[MX25_ADC_REFP_EXT] = "ext",
     79};
     80
     81static irqreturn_t mx25_gcq_irq(int irq, void *data)
     82{
     83	struct mx25_gcq_priv *priv = data;
     84	u32 stats;
     85
     86	regmap_read(priv->regs, MX25_ADCQ_SR, &stats);
     87
     88	if (stats & MX25_ADCQ_SR_EOQ) {
     89		regmap_update_bits(priv->regs, MX25_ADCQ_MR,
     90				   MX25_ADCQ_MR_EOQ_IRQ, MX25_ADCQ_MR_EOQ_IRQ);
     91		complete(&priv->completed);
     92	}
     93
     94	/* Disable conversion queue run */
     95	regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS, 0);
     96
     97	/* Acknowledge all possible irqs */
     98	regmap_write(priv->regs, MX25_ADCQ_SR, MX25_ADCQ_SR_FRR |
     99		     MX25_ADCQ_SR_FUR | MX25_ADCQ_SR_FOR |
    100		     MX25_ADCQ_SR_EOQ | MX25_ADCQ_SR_PD);
    101
    102	return IRQ_HANDLED;
    103}
    104
    105static int mx25_gcq_get_raw_value(struct device *dev,
    106				  struct iio_chan_spec const *chan,
    107				  struct mx25_gcq_priv *priv,
    108				  int *val)
    109{
    110	long timeout;
    111	u32 data;
    112
    113	/* Setup the configuration we want to use */
    114	regmap_write(priv->regs, MX25_ADCQ_ITEM_7_0,
    115		     MX25_ADCQ_ITEM(0, chan->channel));
    116
    117	regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_EOQ_IRQ, 0);
    118
    119	/* Trigger queue for one run */
    120	regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS,
    121			   MX25_ADCQ_CR_FQS);
    122
    123	timeout = wait_for_completion_interruptible_timeout(
    124		&priv->completed, MX25_GCQ_TIMEOUT);
    125	if (timeout < 0) {
    126		dev_err(dev, "ADC wait for measurement failed\n");
    127		return timeout;
    128	} else if (timeout == 0) {
    129		dev_err(dev, "ADC timed out\n");
    130		return -ETIMEDOUT;
    131	}
    132
    133	regmap_read(priv->regs, MX25_ADCQ_FIFO, &data);
    134
    135	*val = MX25_ADCQ_FIFO_DATA(data);
    136
    137	return IIO_VAL_INT;
    138}
    139
    140static int mx25_gcq_read_raw(struct iio_dev *indio_dev,
    141			     struct iio_chan_spec const *chan, int *val,
    142			     int *val2, long mask)
    143{
    144	struct mx25_gcq_priv *priv = iio_priv(indio_dev);
    145	int ret;
    146
    147	switch (mask) {
    148	case IIO_CHAN_INFO_RAW:
    149		mutex_lock(&priv->lock);
    150		ret = mx25_gcq_get_raw_value(&indio_dev->dev, chan, priv, val);
    151		mutex_unlock(&priv->lock);
    152		return ret;
    153
    154	case IIO_CHAN_INFO_SCALE:
    155		*val = priv->channel_vref_mv[chan->channel];
    156		*val2 = 12;
    157		return IIO_VAL_FRACTIONAL_LOG2;
    158
    159	default:
    160		return -EINVAL;
    161	}
    162}
    163
    164static const struct iio_info mx25_gcq_iio_info = {
    165	.read_raw = mx25_gcq_read_raw,
    166};
    167
    168static const struct regmap_config mx25_gcq_regconfig = {
    169	.max_register = 0x5c,
    170	.reg_bits = 32,
    171	.val_bits = 32,
    172	.reg_stride = 4,
    173};
    174
    175static int mx25_gcq_ext_regulator_setup(struct device *dev,
    176					struct mx25_gcq_priv *priv, u32 refp)
    177{
    178	char reg_name[12];
    179	int ret;
    180
    181	if (priv->vref[refp])
    182		return 0;
    183
    184	ret = snprintf(reg_name, sizeof(reg_name), "vref-%s",
    185		       mx25_gcq_refp_names[refp]);
    186	if (ret < 0)
    187		return ret;
    188
    189	priv->vref[refp] = devm_regulator_get_optional(dev, reg_name);
    190	if (IS_ERR(priv->vref[refp]))
    191		return dev_err_probe(dev, PTR_ERR(priv->vref[refp]),
    192				     "Error, trying to use external voltage reference without a %s regulator.",
    193				     reg_name);
    194
    195	return 0;
    196}
    197
    198static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
    199			       struct mx25_gcq_priv *priv)
    200{
    201	struct device_node *np = pdev->dev.of_node;
    202	struct device_node *child;
    203	struct device *dev = &pdev->dev;
    204	int ret, i;
    205
    206	/*
    207	 * Setup all configurations registers with a default conversion
    208	 * configuration for each input
    209	 */
    210	for (i = 0; i < MX25_NUM_CFGS; ++i)
    211		regmap_write(priv->regs, MX25_ADCQ_CFG(i),
    212			     MX25_ADCQ_CFG_YPLL_OFF |
    213			     MX25_ADCQ_CFG_XNUR_OFF |
    214			     MX25_ADCQ_CFG_XPUL_OFF |
    215			     MX25_ADCQ_CFG_REFP_INT |
    216			     MX25_ADCQ_CFG_IN(i) |
    217			     MX25_ADCQ_CFG_REFN_NGND2);
    218
    219	for_each_child_of_node(np, child) {
    220		u32 reg;
    221		u32 refp = MX25_ADCQ_CFG_REFP_INT;
    222		u32 refn = MX25_ADCQ_CFG_REFN_NGND2;
    223
    224		ret = of_property_read_u32(child, "reg", &reg);
    225		if (ret) {
    226			dev_err(dev, "Failed to get reg property\n");
    227			of_node_put(child);
    228			return ret;
    229		}
    230
    231		if (reg >= MX25_NUM_CFGS) {
    232			dev_err(dev,
    233				"reg value is greater than the number of available configuration registers\n");
    234			of_node_put(child);
    235			return -EINVAL;
    236		}
    237
    238		of_property_read_u32(child, "fsl,adc-refp", &refp);
    239		of_property_read_u32(child, "fsl,adc-refn", &refn);
    240
    241		switch (refp) {
    242		case MX25_ADC_REFP_EXT:
    243		case MX25_ADC_REFP_XP:
    244		case MX25_ADC_REFP_YP:
    245			ret = mx25_gcq_ext_regulator_setup(&pdev->dev, priv, refp);
    246			if (ret) {
    247				of_node_put(child);
    248				return ret;
    249			}
    250			priv->channel_vref_mv[reg] =
    251				regulator_get_voltage(priv->vref[refp]);
    252			/* Conversion from uV to mV */
    253			priv->channel_vref_mv[reg] /= 1000;
    254			break;
    255		case MX25_ADC_REFP_INT:
    256			priv->channel_vref_mv[reg] = 2500;
    257			break;
    258		default:
    259			dev_err(dev, "Invalid positive reference %d\n", refp);
    260			of_node_put(child);
    261			return -EINVAL;
    262		}
    263
    264		/*
    265		 * Shift the read values to the correct positions within the
    266		 * register.
    267		 */
    268		refp = MX25_ADCQ_CFG_REFP(refp);
    269		refn = MX25_ADCQ_CFG_REFN(refn);
    270
    271		if ((refp & MX25_ADCQ_CFG_REFP_MASK) != refp) {
    272			dev_err(dev, "Invalid fsl,adc-refp property value\n");
    273			of_node_put(child);
    274			return -EINVAL;
    275		}
    276		if ((refn & MX25_ADCQ_CFG_REFN_MASK) != refn) {
    277			dev_err(dev, "Invalid fsl,adc-refn property value\n");
    278			of_node_put(child);
    279			return -EINVAL;
    280		}
    281
    282		regmap_update_bits(priv->regs, MX25_ADCQ_CFG(reg),
    283				   MX25_ADCQ_CFG_REFP_MASK |
    284				   MX25_ADCQ_CFG_REFN_MASK,
    285				   refp | refn);
    286	}
    287	regmap_update_bits(priv->regs, MX25_ADCQ_CR,
    288			   MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST,
    289			   MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST);
    290
    291	regmap_write(priv->regs, MX25_ADCQ_CR,
    292		     MX25_ADCQ_CR_PDMSK | MX25_ADCQ_CR_QSM_FQS);
    293
    294	return 0;
    295}
    296
    297static int mx25_gcq_probe(struct platform_device *pdev)
    298{
    299	struct iio_dev *indio_dev;
    300	struct mx25_gcq_priv *priv;
    301	struct mx25_tsadc *tsadc = dev_get_drvdata(pdev->dev.parent);
    302	struct device *dev = &pdev->dev;
    303	void __iomem *mem;
    304	int ret;
    305	int i;
    306
    307	indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
    308	if (!indio_dev)
    309		return -ENOMEM;
    310
    311	priv = iio_priv(indio_dev);
    312
    313	mem = devm_platform_ioremap_resource(pdev, 0);
    314	if (IS_ERR(mem))
    315		return PTR_ERR(mem);
    316
    317	priv->regs = devm_regmap_init_mmio(dev, mem, &mx25_gcq_regconfig);
    318	if (IS_ERR(priv->regs)) {
    319		dev_err(dev, "Failed to initialize regmap\n");
    320		return PTR_ERR(priv->regs);
    321	}
    322
    323	mutex_init(&priv->lock);
    324
    325	init_completion(&priv->completed);
    326
    327	ret = mx25_gcq_setup_cfgs(pdev, priv);
    328	if (ret)
    329		return ret;
    330
    331	for (i = 0; i != 4; ++i) {
    332		if (!priv->vref[i])
    333			continue;
    334
    335		ret = regulator_enable(priv->vref[i]);
    336		if (ret)
    337			goto err_regulator_disable;
    338	}
    339
    340	priv->clk = tsadc->clk;
    341	ret = clk_prepare_enable(priv->clk);
    342	if (ret) {
    343		dev_err(dev, "Failed to enable clock\n");
    344		goto err_vref_disable;
    345	}
    346
    347	ret = platform_get_irq(pdev, 0);
    348	if (ret < 0)
    349		goto err_clk_unprepare;
    350
    351	priv->irq = ret;
    352	ret = request_irq(priv->irq, mx25_gcq_irq, 0, pdev->name, priv);
    353	if (ret) {
    354		dev_err(dev, "Failed requesting IRQ\n");
    355		goto err_clk_unprepare;
    356	}
    357
    358	indio_dev->channels = mx25_gcq_channels;
    359	indio_dev->num_channels = ARRAY_SIZE(mx25_gcq_channels);
    360	indio_dev->info = &mx25_gcq_iio_info;
    361	indio_dev->name = driver_name;
    362
    363	ret = iio_device_register(indio_dev);
    364	if (ret) {
    365		dev_err(dev, "Failed to register iio device\n");
    366		goto err_irq_free;
    367	}
    368
    369	platform_set_drvdata(pdev, indio_dev);
    370
    371	return 0;
    372
    373err_irq_free:
    374	free_irq(priv->irq, priv);
    375err_clk_unprepare:
    376	clk_disable_unprepare(priv->clk);
    377err_vref_disable:
    378	i = 4;
    379err_regulator_disable:
    380	for (; i-- > 0;) {
    381		if (priv->vref[i])
    382			regulator_disable(priv->vref[i]);
    383	}
    384	return ret;
    385}
    386
    387static int mx25_gcq_remove(struct platform_device *pdev)
    388{
    389	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
    390	struct mx25_gcq_priv *priv = iio_priv(indio_dev);
    391	int i;
    392
    393	iio_device_unregister(indio_dev);
    394	free_irq(priv->irq, priv);
    395	clk_disable_unprepare(priv->clk);
    396	for (i = 4; i-- > 0;) {
    397		if (priv->vref[i])
    398			regulator_disable(priv->vref[i]);
    399	}
    400
    401	return 0;
    402}
    403
    404static const struct of_device_id mx25_gcq_ids[] = {
    405	{ .compatible = "fsl,imx25-gcq", },
    406	{ /* Sentinel */ }
    407};
    408MODULE_DEVICE_TABLE(of, mx25_gcq_ids);
    409
    410static struct platform_driver mx25_gcq_driver = {
    411	.driver		= {
    412		.name	= "mx25-gcq",
    413		.of_match_table = mx25_gcq_ids,
    414	},
    415	.probe		= mx25_gcq_probe,
    416	.remove		= mx25_gcq_remove,
    417};
    418module_platform_driver(mx25_gcq_driver);
    419
    420MODULE_DESCRIPTION("ADC driver for Freescale mx25");
    421MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>");
    422MODULE_LICENSE("GPL v2");