xref: /openbmc/linux/drivers/iio/adc/adi-axi-adc.c (revision 6c71a0574249f5e5a45fe055ab5f837023d5eeca)
1ef040706SMichael Hennerich // SPDX-License-Identifier: GPL-2.0-only
2ef040706SMichael Hennerich /*
3ef040706SMichael Hennerich  * Analog Devices Generic AXI ADC IP core
4ef040706SMichael Hennerich  * Link: https://wiki.analog.com/resources/fpga/docs/axi_adc_ip
5ef040706SMichael Hennerich  *
6ef040706SMichael Hennerich  * Copyright 2012-2020 Analog Devices Inc.
7ef040706SMichael Hennerich  */
8ef040706SMichael Hennerich 
9ef040706SMichael Hennerich #include <linux/bitfield.h>
10ef040706SMichael Hennerich #include <linux/clk.h>
11d3513f12SNuno Sa #include <linux/err.h>
12ef040706SMichael Hennerich #include <linux/io.h>
13ef040706SMichael Hennerich #include <linux/delay.h>
14ef040706SMichael Hennerich #include <linux/module.h>
151240c94cSRob Herring #include <linux/of.h>
16ef040706SMichael Hennerich #include <linux/platform_device.h>
171240c94cSRob Herring #include <linux/property.h>
18b70042e4SNuno Sa #include <linux/regmap.h>
19ef040706SMichael Hennerich #include <linux/slab.h>
20ef040706SMichael Hennerich 
21ef040706SMichael Hennerich #include <linux/fpga/adi-axi-common.h>
22d3513f12SNuno Sa 
23d3513f12SNuno Sa #include <linux/iio/backend.h>
24d3513f12SNuno Sa #include <linux/iio/buffer-dmaengine.h>
25d3513f12SNuno Sa #include <linux/iio/buffer.h>
26d3513f12SNuno Sa #include <linux/iio/iio.h>
27ef040706SMichael Hennerich 
2863abed2aSJonathan Cameron /*
29ef040706SMichael Hennerich  * Register definitions:
30ef040706SMichael Hennerich  *   https://wiki.analog.com/resources/fpga/docs/axi_adc_ip#register_map
31ef040706SMichael Hennerich  */
32ef040706SMichael Hennerich 
33ef040706SMichael Hennerich /* ADC controls */
34ef040706SMichael Hennerich 
35ef040706SMichael Hennerich #define ADI_AXI_REG_RSTN			0x0040
36ef040706SMichael Hennerich #define   ADI_AXI_REG_RSTN_CE_N			BIT(2)
37ef040706SMichael Hennerich #define   ADI_AXI_REG_RSTN_MMCM_RSTN		BIT(1)
38ef040706SMichael Hennerich #define   ADI_AXI_REG_RSTN_RSTN			BIT(0)
39ef040706SMichael Hennerich 
40ef040706SMichael Hennerich /* ADC Channel controls */
41ef040706SMichael Hennerich 
42ef040706SMichael Hennerich #define ADI_AXI_REG_CHAN_CTRL(c)		(0x0400 + (c) * 0x40)
43ef040706SMichael Hennerich #define   ADI_AXI_REG_CHAN_CTRL_LB_OWR		BIT(11)
44ef040706SMichael Hennerich #define   ADI_AXI_REG_CHAN_CTRL_PN_SEL_OWR	BIT(10)
45ef040706SMichael Hennerich #define   ADI_AXI_REG_CHAN_CTRL_IQCOR_EN	BIT(9)
46ef040706SMichael Hennerich #define   ADI_AXI_REG_CHAN_CTRL_DCFILT_EN	BIT(8)
47d3513f12SNuno Sa #define   ADI_AXI_REG_CHAN_CTRL_FMT_MASK	GENMASK(6, 4)
48ef040706SMichael Hennerich #define   ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT	BIT(6)
49ef040706SMichael Hennerich #define   ADI_AXI_REG_CHAN_CTRL_FMT_TYPE	BIT(5)
50ef040706SMichael Hennerich #define   ADI_AXI_REG_CHAN_CTRL_FMT_EN		BIT(4)
51ef040706SMichael Hennerich #define   ADI_AXI_REG_CHAN_CTRL_PN_TYPE_OWR	BIT(1)
52ef040706SMichael Hennerich #define   ADI_AXI_REG_CHAN_CTRL_ENABLE		BIT(0)
53ef040706SMichael Hennerich 
54ef040706SMichael Hennerich #define ADI_AXI_REG_CHAN_CTRL_DEFAULTS		\
55ef040706SMichael Hennerich 	(ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT |	\
56ef040706SMichael Hennerich 	 ADI_AXI_REG_CHAN_CTRL_FMT_EN |		\
57ef040706SMichael Hennerich 	 ADI_AXI_REG_CHAN_CTRL_ENABLE)
58ef040706SMichael Hennerich 
59ef040706SMichael Hennerich struct adi_axi_adc_state {
60b70042e4SNuno Sa 	struct regmap				*regmap;
61ef040706SMichael Hennerich 	struct device				*dev;
62ef040706SMichael Hennerich };
63ef040706SMichael Hennerich 
axi_adc_enable(struct iio_backend * back)64d3513f12SNuno Sa static int axi_adc_enable(struct iio_backend *back)
65ef040706SMichael Hennerich {
66d3513f12SNuno Sa 	struct adi_axi_adc_state *st = iio_backend_get_priv(back);
67b70042e4SNuno Sa 	int ret;
68ef040706SMichael Hennerich 
69d3513f12SNuno Sa 	ret = regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN,
70b70042e4SNuno Sa 			      ADI_AXI_REG_RSTN_MMCM_RSTN);
71b70042e4SNuno Sa 	if (ret)
72b70042e4SNuno Sa 		return ret;
73b70042e4SNuno Sa 
74d3513f12SNuno Sa 	fsleep(10000);
75d3513f12SNuno Sa 	return regmap_set_bits(st->regmap, ADI_AXI_REG_RSTN,
76ef040706SMichael Hennerich 			       ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN);
77ef040706SMichael Hennerich }
78ef040706SMichael Hennerich 
axi_adc_disable(struct iio_backend * back)79d3513f12SNuno Sa static void axi_adc_disable(struct iio_backend *back)
80ef040706SMichael Hennerich {
81d3513f12SNuno Sa 	struct adi_axi_adc_state *st = iio_backend_get_priv(back);
82ef040706SMichael Hennerich 
83d3513f12SNuno Sa 	regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0);
84d3513f12SNuno Sa }
85d3513f12SNuno Sa 
axi_adc_data_format_set(struct iio_backend * back,unsigned int chan,const struct iio_backend_data_fmt * data)86d3513f12SNuno Sa static int axi_adc_data_format_set(struct iio_backend *back, unsigned int chan,
87d3513f12SNuno Sa 				   const struct iio_backend_data_fmt *data)
88d3513f12SNuno Sa {
89d3513f12SNuno Sa 	struct adi_axi_adc_state *st = iio_backend_get_priv(back);
90d3513f12SNuno Sa 	u32 val;
91d3513f12SNuno Sa 
92d3513f12SNuno Sa 	if (!data->enable)
93d3513f12SNuno Sa 		return regmap_clear_bits(st->regmap,
94d3513f12SNuno Sa 					 ADI_AXI_REG_CHAN_CTRL(chan),
95d3513f12SNuno Sa 					 ADI_AXI_REG_CHAN_CTRL_FMT_EN);
96d3513f12SNuno Sa 
97d3513f12SNuno Sa 	val = FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_EN, true);
98d3513f12SNuno Sa 	if (data->sign_extend)
99d3513f12SNuno Sa 		val |= FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT, true);
100d3513f12SNuno Sa 	if (data->type == IIO_BACKEND_OFFSET_BINARY)
101d3513f12SNuno Sa 		val |= FIELD_PREP(ADI_AXI_REG_CHAN_CTRL_FMT_TYPE, true);
102d3513f12SNuno Sa 
103d3513f12SNuno Sa 	return regmap_update_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan),
104d3513f12SNuno Sa 				  ADI_AXI_REG_CHAN_CTRL_FMT_MASK, val);
105d3513f12SNuno Sa }
106d3513f12SNuno Sa 
axi_adc_chan_enable(struct iio_backend * back,unsigned int chan)107d3513f12SNuno Sa static int axi_adc_chan_enable(struct iio_backend *back, unsigned int chan)
108d3513f12SNuno Sa {
109d3513f12SNuno Sa 	struct adi_axi_adc_state *st = iio_backend_get_priv(back);
110d3513f12SNuno Sa 
111d3513f12SNuno Sa 	return regmap_set_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan),
112d3513f12SNuno Sa 			       ADI_AXI_REG_CHAN_CTRL_ENABLE);
113d3513f12SNuno Sa }
114d3513f12SNuno Sa 
axi_adc_chan_disable(struct iio_backend * back,unsigned int chan)115d3513f12SNuno Sa static int axi_adc_chan_disable(struct iio_backend *back, unsigned int chan)
116d3513f12SNuno Sa {
117d3513f12SNuno Sa 	struct adi_axi_adc_state *st = iio_backend_get_priv(back);
118d3513f12SNuno Sa 
119d3513f12SNuno Sa 	return regmap_clear_bits(st->regmap, ADI_AXI_REG_CHAN_CTRL(chan),
120d3513f12SNuno Sa 				 ADI_AXI_REG_CHAN_CTRL_ENABLE);
121d3513f12SNuno Sa }
122d3513f12SNuno Sa 
axi_adc_request_buffer(struct iio_backend * back,struct iio_dev * indio_dev)123d3513f12SNuno Sa static struct iio_buffer *axi_adc_request_buffer(struct iio_backend *back,
124d3513f12SNuno Sa 						 struct iio_dev *indio_dev)
125d3513f12SNuno Sa {
126d3513f12SNuno Sa 	struct adi_axi_adc_state *st = iio_backend_get_priv(back);
127d3513f12SNuno Sa 	struct iio_buffer *buffer;
128d3513f12SNuno Sa 	const char *dma_name;
129d3513f12SNuno Sa 	int ret;
130d3513f12SNuno Sa 
131d3513f12SNuno Sa 	if (device_property_read_string(st->dev, "dma-names", &dma_name))
132d3513f12SNuno Sa 		dma_name = "rx";
133d3513f12SNuno Sa 
134d3513f12SNuno Sa 	buffer = iio_dmaengine_buffer_alloc(st->dev, dma_name);
135d3513f12SNuno Sa 	if (IS_ERR(buffer)) {
136d3513f12SNuno Sa 		dev_err(st->dev, "Could not get DMA buffer, %ld\n",
137d3513f12SNuno Sa 			PTR_ERR(buffer));
138d3513f12SNuno Sa 		return ERR_CAST(buffer);
139d3513f12SNuno Sa 	}
140d3513f12SNuno Sa 
141d3513f12SNuno Sa 	indio_dev->modes |= INDIO_BUFFER_HARDWARE;
142d3513f12SNuno Sa 	ret = iio_device_attach_buffer(indio_dev, buffer);
143d3513f12SNuno Sa 	if (ret)
144d3513f12SNuno Sa 		return ERR_PTR(ret);
145d3513f12SNuno Sa 
146d3513f12SNuno Sa 	return buffer;
147d3513f12SNuno Sa }
148d3513f12SNuno Sa 
axi_adc_free_buffer(struct iio_backend * back,struct iio_buffer * buffer)149d3513f12SNuno Sa static void axi_adc_free_buffer(struct iio_backend *back,
150d3513f12SNuno Sa 				struct iio_buffer *buffer)
151d3513f12SNuno Sa {
152d3513f12SNuno Sa 	iio_dmaengine_buffer_free(buffer);
153ef040706SMichael Hennerich }
154ef040706SMichael Hennerich 
155b70042e4SNuno Sa static const struct regmap_config axi_adc_regmap_config = {
156b70042e4SNuno Sa 	.val_bits = 32,
157b70042e4SNuno Sa 	.reg_bits = 32,
158b70042e4SNuno Sa 	.reg_stride = 4,
159b70042e4SNuno Sa 	.max_register = 0x0800,
160b70042e4SNuno Sa };
161b70042e4SNuno Sa 
162d3513f12SNuno Sa static const struct iio_backend_ops adi_axi_adc_generic = {
163d3513f12SNuno Sa 	.enable = axi_adc_enable,
164d3513f12SNuno Sa 	.disable = axi_adc_disable,
165d3513f12SNuno Sa 	.data_format_set = axi_adc_data_format_set,
166d3513f12SNuno Sa 	.chan_enable = axi_adc_chan_enable,
167d3513f12SNuno Sa 	.chan_disable = axi_adc_chan_disable,
168d3513f12SNuno Sa 	.request_buffer = axi_adc_request_buffer,
169d3513f12SNuno Sa 	.free_buffer = axi_adc_free_buffer,
170d3513f12SNuno Sa };
171d3513f12SNuno Sa 
adi_axi_adc_probe(struct platform_device * pdev)172ef040706SMichael Hennerich static int adi_axi_adc_probe(struct platform_device *pdev)
173ef040706SMichael Hennerich {
174d3513f12SNuno Sa 	const unsigned int *expected_ver;
175ef040706SMichael Hennerich 	struct adi_axi_adc_state *st;
176b70042e4SNuno Sa 	void __iomem *base;
177ef040706SMichael Hennerich 	unsigned int ver;
178*955c824dSNuno Sa 	struct clk *clk;
179ef040706SMichael Hennerich 	int ret;
180ef040706SMichael Hennerich 
181d3513f12SNuno Sa 	st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL);
182d3513f12SNuno Sa 	if (!st)
183ef040706SMichael Hennerich 		return -ENOMEM;
184ef040706SMichael Hennerich 
185b70042e4SNuno Sa 	base = devm_platform_ioremap_resource(pdev, 0);
186b70042e4SNuno Sa 	if (IS_ERR(base))
187b70042e4SNuno Sa 		return PTR_ERR(base);
188b70042e4SNuno Sa 
189d3513f12SNuno Sa 	st->dev = &pdev->dev;
190b70042e4SNuno Sa 	st->regmap = devm_regmap_init_mmio(&pdev->dev, base,
191b70042e4SNuno Sa 					   &axi_adc_regmap_config);
192b70042e4SNuno Sa 	if (IS_ERR(st->regmap))
193b70042e4SNuno Sa 		return PTR_ERR(st->regmap);
194ef040706SMichael Hennerich 
195d3513f12SNuno Sa 	expected_ver = device_get_match_data(&pdev->dev);
196d3513f12SNuno Sa 	if (!expected_ver)
197d3513f12SNuno Sa 		return -ENODEV;
198ef040706SMichael Hennerich 
199*955c824dSNuno Sa 	clk = devm_clk_get_enabled(&pdev->dev, NULL);
200*955c824dSNuno Sa 	if (IS_ERR(clk))
201*955c824dSNuno Sa 		return PTR_ERR(clk);
202*955c824dSNuno Sa 
203d3513f12SNuno Sa 	/*
204d3513f12SNuno Sa 	 * Force disable the core. Up to the frontend to enable us. And we can
205d3513f12SNuno Sa 	 * still read/write registers...
206d3513f12SNuno Sa 	 */
207d3513f12SNuno Sa 	ret = regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0);
208b70042e4SNuno Sa 	if (ret)
209b70042e4SNuno Sa 		return ret;
210ef040706SMichael Hennerich 
211b70042e4SNuno Sa 	ret = regmap_read(st->regmap, ADI_AXI_REG_VERSION, &ver);
212b70042e4SNuno Sa 	if (ret)
213b70042e4SNuno Sa 		return ret;
214ef040706SMichael Hennerich 
215720d2766SNuno Sa 	if (ADI_AXI_PCORE_VER_MAJOR(ver) != ADI_AXI_PCORE_VER_MAJOR(*expected_ver)) {
216ef040706SMichael Hennerich 		dev_err(&pdev->dev,
217720d2766SNuno Sa 			"Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n",
218d3513f12SNuno Sa 			ADI_AXI_PCORE_VER_MAJOR(*expected_ver),
219d3513f12SNuno Sa 			ADI_AXI_PCORE_VER_MINOR(*expected_ver),
220d3513f12SNuno Sa 			ADI_AXI_PCORE_VER_PATCH(*expected_ver),
221ef040706SMichael Hennerich 			ADI_AXI_PCORE_VER_MAJOR(ver),
222ef040706SMichael Hennerich 			ADI_AXI_PCORE_VER_MINOR(ver),
223ef040706SMichael Hennerich 			ADI_AXI_PCORE_VER_PATCH(ver));
224ef040706SMichael Hennerich 		return -ENODEV;
225ef040706SMichael Hennerich 	}
226ef040706SMichael Hennerich 
227d3513f12SNuno Sa 	ret = devm_iio_backend_register(&pdev->dev, &adi_axi_adc_generic, st);
228ef040706SMichael Hennerich 	if (ret)
229ef040706SMichael Hennerich 		return ret;
230ef040706SMichael Hennerich 
231ef040706SMichael Hennerich 	dev_info(&pdev->dev, "AXI ADC IP core (%d.%.2d.%c) probed\n",
232ef040706SMichael Hennerich 		 ADI_AXI_PCORE_VER_MAJOR(ver),
233ef040706SMichael Hennerich 		 ADI_AXI_PCORE_VER_MINOR(ver),
234ef040706SMichael Hennerich 		 ADI_AXI_PCORE_VER_PATCH(ver));
235ef040706SMichael Hennerich 
236ef040706SMichael Hennerich 	return 0;
237ef040706SMichael Hennerich }
238ef040706SMichael Hennerich 
239d3513f12SNuno Sa static unsigned int adi_axi_adc_10_0_a_info = ADI_AXI_PCORE_VER(10, 0, 'a');
240d3513f12SNuno Sa 
241ef040706SMichael Hennerich /* Match table for of_platform binding */
242ef040706SMichael Hennerich static const struct of_device_id adi_axi_adc_of_match[] = {
243ef040706SMichael Hennerich 	{ .compatible = "adi,axi-adc-10.0.a", .data = &adi_axi_adc_10_0_a_info },
244ef040706SMichael Hennerich 	{ /* end of list */ }
245ef040706SMichael Hennerich };
246ef040706SMichael Hennerich MODULE_DEVICE_TABLE(of, adi_axi_adc_of_match);
247ef040706SMichael Hennerich 
248ef040706SMichael Hennerich static struct platform_driver adi_axi_adc_driver = {
249ef040706SMichael Hennerich 	.driver = {
250ef040706SMichael Hennerich 		.name = KBUILD_MODNAME,
251ef040706SMichael Hennerich 		.of_match_table = adi_axi_adc_of_match,
252ef040706SMichael Hennerich 	},
253ef040706SMichael Hennerich 	.probe = adi_axi_adc_probe,
254ef040706SMichael Hennerich };
255ef040706SMichael Hennerich module_platform_driver(adi_axi_adc_driver);
256ef040706SMichael Hennerich 
257ef040706SMichael Hennerich MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
258ef040706SMichael Hennerich MODULE_DESCRIPTION("Analog Devices Generic AXI ADC IP core driver");
259ef040706SMichael Hennerich MODULE_LICENSE("GPL v2");
260e1fc56c4SNuno Sa MODULE_IMPORT_NS(IIO_DMAENGINE_BUFFER);
261d3513f12SNuno Sa MODULE_IMPORT_NS(IIO_BACKEND);
262