brintos

brintos / linux-shallow public Read only

0
0
Text · 8.8 KiB · 3a55465 Raw
352 lines · c
1// SPDX-License-Identifier: GPL-2.02// Copyright (c) 2019 Nuvoton Technology corporation.3 4#include <linux/clk.h>5#include <linux/device.h>6#include <linux/mfd/syscon.h>7#include <linux/io.h>8#include <linux/iio/iio.h>9#include <linux/interrupt.h>10#include <linux/kernel.h>11#include <linux/mod_devicetable.h>12#include <linux/module.h>13#include <linux/platform_device.h>14#include <linux/property.h>15#include <linux/regmap.h>16#include <linux/regulator/consumer.h>17#include <linux/spinlock.h>18#include <linux/uaccess.h>19#include <linux/reset.h>20 21struct npcm_adc_info {22	u32 data_mask;23	u32 internal_vref;24	u32 res_bits;25};26 27struct npcm_adc {28	bool int_status;29	u32 adc_sample_hz;30	struct device *dev;31	void __iomem *regs;32	struct clk *adc_clk;33	wait_queue_head_t wq;34	struct regulator *vref;35	struct reset_control *reset;36	/*37	 * Lock to protect the device state during a potential concurrent38	 * read access from userspace. Reading a raw value requires a sequence39	 * of register writes, then a wait for a event and finally a register40	 * read, during which userspace could issue another read request.41	 * This lock protects a read access from ocurring before another one42	 * has finished.43	 */44	struct mutex lock;45	const struct npcm_adc_info *data;46};47 48/* ADC registers */49#define NPCM_ADCCON	 0x0050#define NPCM_ADCDATA	 0x0451 52/* ADCCON Register Bits */53#define NPCM_ADCCON_ADC_INT_EN		BIT(21)54#define NPCM_ADCCON_REFSEL		BIT(19)55#define NPCM_ADCCON_ADC_INT_ST		BIT(18)56#define NPCM_ADCCON_ADC_EN		BIT(17)57#define NPCM_ADCCON_ADC_RST		BIT(16)58#define NPCM_ADCCON_ADC_CONV		BIT(13)59 60#define NPCM_ADCCON_CH_MASK		GENMASK(27, 24)61#define NPCM_ADCCON_CH(x)		((x) << 24)62#define NPCM_ADCCON_DIV_SHIFT		163#define NPCM_ADCCON_DIV_MASK		GENMASK(8, 1)64 65#define NPCM_ADC_ENABLE		(NPCM_ADCCON_ADC_EN | NPCM_ADCCON_ADC_INT_EN)66 67/* ADC General Definition */68static const struct npcm_adc_info npxm7xx_adc_info = {69	.data_mask = GENMASK(9, 0),70	.internal_vref = 2048,71	.res_bits = 10,72};73 74static const struct npcm_adc_info npxm8xx_adc_info = {75	.data_mask = GENMASK(11, 0),76	.internal_vref = 1229,77	.res_bits = 12,78};79 80#define NPCM_ADC_CHAN(ch) {					\81	.type = IIO_VOLTAGE,					\82	.indexed = 1,						\83	.channel = ch,						\84	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\85	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\86				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\87}88 89static const struct iio_chan_spec npcm_adc_iio_channels[] = {90	NPCM_ADC_CHAN(0),91	NPCM_ADC_CHAN(1),92	NPCM_ADC_CHAN(2),93	NPCM_ADC_CHAN(3),94	NPCM_ADC_CHAN(4),95	NPCM_ADC_CHAN(5),96	NPCM_ADC_CHAN(6),97	NPCM_ADC_CHAN(7),98};99 100static irqreturn_t npcm_adc_isr(int irq, void *data)101{102	u32 regtemp;103	struct iio_dev *indio_dev = data;104	struct npcm_adc *info = iio_priv(indio_dev);105 106	regtemp = ioread32(info->regs + NPCM_ADCCON);107	if (regtemp & NPCM_ADCCON_ADC_INT_ST) {108		iowrite32(regtemp, info->regs + NPCM_ADCCON);109		wake_up_interruptible(&info->wq);110		info->int_status = true;111	}112 113	return IRQ_HANDLED;114}115 116static int npcm_adc_read(struct npcm_adc *info, int *val, u8 channel)117{118	int ret;119	u32 regtemp;120 121	/* Select ADC channel */122	regtemp = ioread32(info->regs + NPCM_ADCCON);123	regtemp &= ~NPCM_ADCCON_CH_MASK;124	info->int_status = false;125	iowrite32(regtemp | NPCM_ADCCON_CH(channel) |126		  NPCM_ADCCON_ADC_CONV, info->regs + NPCM_ADCCON);127 128	ret = wait_event_interruptible_timeout(info->wq, info->int_status,129					       msecs_to_jiffies(10));130	if (ret == 0) {131		regtemp = ioread32(info->regs + NPCM_ADCCON);132		if (regtemp & NPCM_ADCCON_ADC_CONV) {133			/* if conversion failed - reset ADC module */134			reset_control_assert(info->reset);135			msleep(100);136			reset_control_deassert(info->reset);137			msleep(100);138 139			/* Enable ADC and start conversion module */140			iowrite32(NPCM_ADC_ENABLE | NPCM_ADCCON_ADC_CONV,141				  info->regs + NPCM_ADCCON);142			dev_err(info->dev, "RESET ADC Complete\n");143		}144		return -ETIMEDOUT;145	}146	if (ret < 0)147		return ret;148 149	*val = ioread32(info->regs + NPCM_ADCDATA);150	*val &= info->data->data_mask;151 152	return 0;153}154 155static int npcm_adc_read_raw(struct iio_dev *indio_dev,156			     struct iio_chan_spec const *chan, int *val,157			     int *val2, long mask)158{159	int ret;160	int vref_uv;161	struct npcm_adc *info = iio_priv(indio_dev);162 163	switch (mask) {164	case IIO_CHAN_INFO_RAW:165		mutex_lock(&info->lock);166		ret = npcm_adc_read(info, val, chan->channel);167		mutex_unlock(&info->lock);168		if (ret) {169			dev_err(info->dev, "NPCM ADC read failed\n");170			return ret;171		}172		return IIO_VAL_INT;173	case IIO_CHAN_INFO_SCALE:174		if (!IS_ERR(info->vref)) {175			vref_uv = regulator_get_voltage(info->vref);176			*val = vref_uv / 1000;177		} else {178			*val = info->data->internal_vref;179		}180		*val2 = info->data->res_bits;181		return IIO_VAL_FRACTIONAL_LOG2;182	case IIO_CHAN_INFO_SAMP_FREQ:183		*val = info->adc_sample_hz;184		return IIO_VAL_INT;185	default:186		return -EINVAL;187	}188 189	return 0;190}191 192static const struct iio_info npcm_adc_iio_info = {193	.read_raw = &npcm_adc_read_raw,194};195 196static const struct of_device_id npcm_adc_match[] = {197	{ .compatible = "nuvoton,npcm750-adc", .data = &npxm7xx_adc_info},198	{ .compatible = "nuvoton,npcm845-adc", .data = &npxm8xx_adc_info},199	{ /* sentinel */ }200};201MODULE_DEVICE_TABLE(of, npcm_adc_match);202 203static int npcm_adc_probe(struct platform_device *pdev)204{205	int ret;206	int irq;207	u32 div;208	u32 reg_con;209	struct npcm_adc *info;210	struct iio_dev *indio_dev;211	struct device *dev = &pdev->dev;212 213	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));214	if (!indio_dev)215		return -ENOMEM;216	info = iio_priv(indio_dev);217 218	info->data = device_get_match_data(dev);219	if (!info->data)220		return -EINVAL;221 222	mutex_init(&info->lock);223 224	info->dev = &pdev->dev;225 226	info->regs = devm_platform_ioremap_resource(pdev, 0);227	if (IS_ERR(info->regs))228		return PTR_ERR(info->regs);229 230	info->reset = devm_reset_control_get(&pdev->dev, NULL);231	if (IS_ERR(info->reset))232		return PTR_ERR(info->reset);233 234	info->adc_clk = devm_clk_get(&pdev->dev, NULL);235	if (IS_ERR(info->adc_clk)) {236		dev_warn(&pdev->dev, "ADC clock failed: can't read clk\n");237		return PTR_ERR(info->adc_clk);238	}239 240	/* calculate ADC clock sample rate */241	reg_con = ioread32(info->regs + NPCM_ADCCON);242	div = reg_con & NPCM_ADCCON_DIV_MASK;243	div = div >> NPCM_ADCCON_DIV_SHIFT;244	info->adc_sample_hz = clk_get_rate(info->adc_clk) / ((div + 1) * 2);245 246	irq = platform_get_irq(pdev, 0);247	if (irq < 0) {248		ret = irq;249		goto err_disable_clk;250	}251 252	ret = devm_request_irq(&pdev->dev, irq, npcm_adc_isr, 0,253			       "NPCM_ADC", indio_dev);254	if (ret < 0) {255		dev_err(dev, "failed requesting interrupt\n");256		goto err_disable_clk;257	}258 259	reg_con = ioread32(info->regs + NPCM_ADCCON);260	info->vref = devm_regulator_get_optional(&pdev->dev, "vref");261	if (!IS_ERR(info->vref)) {262		ret = regulator_enable(info->vref);263		if (ret) {264			dev_err(&pdev->dev, "Can't enable ADC reference voltage\n");265			goto err_disable_clk;266		}267 268		iowrite32(reg_con & ~NPCM_ADCCON_REFSEL,269			  info->regs + NPCM_ADCCON);270	} else {271		/*272		 * Any error which is not ENODEV indicates the regulator273		 * has been specified and so is a failure case.274		 */275		if (PTR_ERR(info->vref) != -ENODEV) {276			ret = PTR_ERR(info->vref);277			goto err_disable_clk;278		}279 280		/* Use internal reference */281		iowrite32(reg_con | NPCM_ADCCON_REFSEL,282			  info->regs + NPCM_ADCCON);283	}284 285	init_waitqueue_head(&info->wq);286 287	reg_con = ioread32(info->regs + NPCM_ADCCON);288	reg_con |= NPCM_ADC_ENABLE;289 290	/* Enable the ADC Module */291	iowrite32(reg_con, info->regs + NPCM_ADCCON);292 293	/* Start ADC conversion */294	iowrite32(reg_con | NPCM_ADCCON_ADC_CONV, info->regs + NPCM_ADCCON);295 296	platform_set_drvdata(pdev, indio_dev);297	indio_dev->name = dev_name(&pdev->dev);298	indio_dev->info = &npcm_adc_iio_info;299	indio_dev->modes = INDIO_DIRECT_MODE;300	indio_dev->channels = npcm_adc_iio_channels;301	indio_dev->num_channels = ARRAY_SIZE(npcm_adc_iio_channels);302 303	ret = iio_device_register(indio_dev);304	if (ret) {305		dev_err(&pdev->dev, "Couldn't register the device.\n");306		goto err_iio_register;307	}308 309	pr_info("NPCM ADC driver probed\n");310 311	return 0;312 313err_iio_register:314	iowrite32(reg_con & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON);315	if (!IS_ERR(info->vref))316		regulator_disable(info->vref);317err_disable_clk:318	clk_disable_unprepare(info->adc_clk);319 320	return ret;321}322 323static void npcm_adc_remove(struct platform_device *pdev)324{325	struct iio_dev *indio_dev = platform_get_drvdata(pdev);326	struct npcm_adc *info = iio_priv(indio_dev);327	u32 regtemp;328 329	iio_device_unregister(indio_dev);330 331	regtemp = ioread32(info->regs + NPCM_ADCCON);332	iowrite32(regtemp & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON);333	if (!IS_ERR(info->vref))334		regulator_disable(info->vref);335	clk_disable_unprepare(info->adc_clk);336}337 338static struct platform_driver npcm_adc_driver = {339	.probe		= npcm_adc_probe,340	.remove_new	= npcm_adc_remove,341	.driver		= {342		.name	= "npcm_adc",343		.of_match_table = npcm_adc_match,344	},345};346 347module_platform_driver(npcm_adc_driver);348 349MODULE_DESCRIPTION("Nuvoton NPCM ADC Driver");350MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");351MODULE_LICENSE("GPL v2");352