xref: /rk3399_rockchip-uboot/drivers/adc/rockchip-saradc.c (revision 90aa625c9a9e1fb7a2f001fd8e50099bacaf92b8)
1ae6cbe8aSDavid Wu /*
2ae6cbe8aSDavid Wu  * (C) Copyright 2017, Fuzhou Rockchip Electronics Co., Ltd
3ae6cbe8aSDavid Wu  *
4ae6cbe8aSDavid Wu  * SPDX-License-Identifier:	GPL-2.0+
5ae6cbe8aSDavid Wu  *
6ae6cbe8aSDavid Wu  * Rockchip SARADC driver for U-Boot
7ae6cbe8aSDavid Wu  */
8ae6cbe8aSDavid Wu 
9ae6cbe8aSDavid Wu #include <common.h>
10ae6cbe8aSDavid Wu #include <adc.h>
11ae6cbe8aSDavid Wu #include <clk.h>
12ae6cbe8aSDavid Wu #include <dm.h>
13ae6cbe8aSDavid Wu #include <errno.h>
14ae6cbe8aSDavid Wu #include <asm/io.h>
15ae6cbe8aSDavid Wu 
16ae6cbe8aSDavid Wu #define SARADC_CTRL_CHN_MASK		GENMASK(2, 0)
17ae6cbe8aSDavid Wu #define SARADC_CTRL_POWER_CTRL		BIT(3)
18ae6cbe8aSDavid Wu #define SARADC_CTRL_IRQ_ENABLE		BIT(5)
19ae6cbe8aSDavid Wu #define SARADC_CTRL_IRQ_STATUS		BIT(6)
20ae6cbe8aSDavid Wu 
21ae6cbe8aSDavid Wu #define SARADC_TIMEOUT			(100 * 1000)
22ae6cbe8aSDavid Wu 
23ae6cbe8aSDavid Wu struct rockchip_saradc_regs {
24ae6cbe8aSDavid Wu 	unsigned int data;
25ae6cbe8aSDavid Wu 	unsigned int stas;
26ae6cbe8aSDavid Wu 	unsigned int ctrl;
27ae6cbe8aSDavid Wu 	unsigned int dly_pu_soc;
28ae6cbe8aSDavid Wu };
29ae6cbe8aSDavid Wu 
30ae6cbe8aSDavid Wu struct rockchip_saradc_data {
31ae6cbe8aSDavid Wu 	int				num_bits;
32ae6cbe8aSDavid Wu 	int				num_channels;
33ae6cbe8aSDavid Wu 	unsigned long			clk_rate;
34ae6cbe8aSDavid Wu };
35ae6cbe8aSDavid Wu 
36ae6cbe8aSDavid Wu struct rockchip_saradc_priv {
37ae6cbe8aSDavid Wu 	struct rockchip_saradc_regs		*regs;
38ae6cbe8aSDavid Wu 	int					active_channel;
39ae6cbe8aSDavid Wu 	const struct rockchip_saradc_data	*data;
40ae6cbe8aSDavid Wu };
41ae6cbe8aSDavid Wu 
rockchip_saradc_channel_data(struct udevice * dev,int channel,unsigned int * data)42ae6cbe8aSDavid Wu int rockchip_saradc_channel_data(struct udevice *dev, int channel,
43ae6cbe8aSDavid Wu 				 unsigned int *data)
44ae6cbe8aSDavid Wu {
45ae6cbe8aSDavid Wu 	struct rockchip_saradc_priv *priv = dev_get_priv(dev);
46ae6cbe8aSDavid Wu 	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
47ae6cbe8aSDavid Wu 
48ae6cbe8aSDavid Wu 	if (channel != priv->active_channel) {
49*90aa625cSMasahiro Yamada 		pr_err("Requested channel is not active!");
50ae6cbe8aSDavid Wu 		return -EINVAL;
51ae6cbe8aSDavid Wu 	}
52ae6cbe8aSDavid Wu 
53ae6cbe8aSDavid Wu 	if ((readl(&priv->regs->ctrl) & SARADC_CTRL_IRQ_STATUS) !=
54ae6cbe8aSDavid Wu 	    SARADC_CTRL_IRQ_STATUS)
55ae6cbe8aSDavid Wu 		return -EBUSY;
56ae6cbe8aSDavid Wu 
57ae6cbe8aSDavid Wu 	/* Read value */
58ae6cbe8aSDavid Wu 	*data = readl(&priv->regs->data);
59ae6cbe8aSDavid Wu 	*data &= uc_pdata->data_mask;
60ae6cbe8aSDavid Wu 
61ae6cbe8aSDavid Wu 	/* Power down adc */
62ae6cbe8aSDavid Wu 	writel(0, &priv->regs->ctrl);
63ae6cbe8aSDavid Wu 
64ae6cbe8aSDavid Wu 	return 0;
65ae6cbe8aSDavid Wu }
66ae6cbe8aSDavid Wu 
rockchip_saradc_start_channel(struct udevice * dev,int channel)67ae6cbe8aSDavid Wu int rockchip_saradc_start_channel(struct udevice *dev, int channel)
68ae6cbe8aSDavid Wu {
69ae6cbe8aSDavid Wu 	struct rockchip_saradc_priv *priv = dev_get_priv(dev);
70ae6cbe8aSDavid Wu 
71ae6cbe8aSDavid Wu 	if (channel < 0 || channel >= priv->data->num_channels) {
72*90aa625cSMasahiro Yamada 		pr_err("Requested channel is invalid!");
73ae6cbe8aSDavid Wu 		return -EINVAL;
74ae6cbe8aSDavid Wu 	}
75ae6cbe8aSDavid Wu 
76ae6cbe8aSDavid Wu 	/* 8 clock periods as delay between power up and start cmd */
77ae6cbe8aSDavid Wu 	writel(8, &priv->regs->dly_pu_soc);
78ae6cbe8aSDavid Wu 
79ae6cbe8aSDavid Wu 	/* Select the channel to be used and trigger conversion */
80ae6cbe8aSDavid Wu 	writel(SARADC_CTRL_POWER_CTRL | (channel & SARADC_CTRL_CHN_MASK) |
81ae6cbe8aSDavid Wu 	       SARADC_CTRL_IRQ_ENABLE, &priv->regs->ctrl);
82ae6cbe8aSDavid Wu 
83ae6cbe8aSDavid Wu 	priv->active_channel = channel;
84ae6cbe8aSDavid Wu 
85ae6cbe8aSDavid Wu 	return 0;
86ae6cbe8aSDavid Wu }
87ae6cbe8aSDavid Wu 
rockchip_saradc_stop(struct udevice * dev)88ae6cbe8aSDavid Wu int rockchip_saradc_stop(struct udevice *dev)
89ae6cbe8aSDavid Wu {
90ae6cbe8aSDavid Wu 	struct rockchip_saradc_priv *priv = dev_get_priv(dev);
91ae6cbe8aSDavid Wu 
92ae6cbe8aSDavid Wu 	/* Power down adc */
93ae6cbe8aSDavid Wu 	writel(0, &priv->regs->ctrl);
94ae6cbe8aSDavid Wu 
95ae6cbe8aSDavid Wu 	priv->active_channel = -1;
96ae6cbe8aSDavid Wu 
97ae6cbe8aSDavid Wu 	return 0;
98ae6cbe8aSDavid Wu }
99ae6cbe8aSDavid Wu 
rockchip_saradc_probe(struct udevice * dev)100ae6cbe8aSDavid Wu int rockchip_saradc_probe(struct udevice *dev)
101ae6cbe8aSDavid Wu {
102ae6cbe8aSDavid Wu 	struct rockchip_saradc_priv *priv = dev_get_priv(dev);
103ae6cbe8aSDavid Wu 	struct clk clk;
104ae6cbe8aSDavid Wu 	int ret;
105ae6cbe8aSDavid Wu 
106ae6cbe8aSDavid Wu 	ret = clk_get_by_index(dev, 0, &clk);
107ae6cbe8aSDavid Wu 	if (ret)
108ae6cbe8aSDavid Wu 		return ret;
109ae6cbe8aSDavid Wu 
110ae6cbe8aSDavid Wu 	ret = clk_set_rate(&clk, priv->data->clk_rate);
111ae6cbe8aSDavid Wu 	if (IS_ERR_VALUE(ret))
112ae6cbe8aSDavid Wu 		return ret;
113ae6cbe8aSDavid Wu 
114ae6cbe8aSDavid Wu 	priv->active_channel = -1;
115ae6cbe8aSDavid Wu 
116ae6cbe8aSDavid Wu 	return 0;
117ae6cbe8aSDavid Wu }
118ae6cbe8aSDavid Wu 
rockchip_saradc_ofdata_to_platdata(struct udevice * dev)119ae6cbe8aSDavid Wu int rockchip_saradc_ofdata_to_platdata(struct udevice *dev)
120ae6cbe8aSDavid Wu {
121ae6cbe8aSDavid Wu 	struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
122ae6cbe8aSDavid Wu 	struct rockchip_saradc_priv *priv = dev_get_priv(dev);
123ae6cbe8aSDavid Wu 	struct rockchip_saradc_data *data;
124ae6cbe8aSDavid Wu 
125ae6cbe8aSDavid Wu 	data = (struct rockchip_saradc_data *)dev_get_driver_data(dev);
126ae6cbe8aSDavid Wu 	priv->regs = (struct rockchip_saradc_regs *)dev_read_addr(dev);
127ae6cbe8aSDavid Wu 	if (priv->regs == (struct rockchip_saradc_regs *)FDT_ADDR_T_NONE) {
128*90aa625cSMasahiro Yamada 		pr_err("Dev: %s - can't get address!", dev->name);
129ae6cbe8aSDavid Wu 		return -ENODATA;
130ae6cbe8aSDavid Wu 	}
131ae6cbe8aSDavid Wu 
132ae6cbe8aSDavid Wu 	priv->data = data;
133ae6cbe8aSDavid Wu 	uc_pdata->data_mask = (1 << priv->data->num_bits) - 1;;
134ae6cbe8aSDavid Wu 	uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
135ae6cbe8aSDavid Wu 	uc_pdata->data_timeout_us = SARADC_TIMEOUT / 5;
136ae6cbe8aSDavid Wu 	uc_pdata->channel_mask = (1 << priv->data->num_channels) - 1;
137ae6cbe8aSDavid Wu 
138ae6cbe8aSDavid Wu 	return 0;
139ae6cbe8aSDavid Wu }
140ae6cbe8aSDavid Wu 
141ae6cbe8aSDavid Wu static const struct adc_ops rockchip_saradc_ops = {
142ae6cbe8aSDavid Wu 	.start_channel = rockchip_saradc_start_channel,
143ae6cbe8aSDavid Wu 	.channel_data = rockchip_saradc_channel_data,
144ae6cbe8aSDavid Wu 	.stop = rockchip_saradc_stop,
145ae6cbe8aSDavid Wu };
146ae6cbe8aSDavid Wu 
147ae6cbe8aSDavid Wu static const struct rockchip_saradc_data saradc_data = {
148ae6cbe8aSDavid Wu 	.num_bits = 10,
149ae6cbe8aSDavid Wu 	.num_channels = 3,
150ae6cbe8aSDavid Wu 	.clk_rate = 1000000,
151ae6cbe8aSDavid Wu };
152ae6cbe8aSDavid Wu 
153ae6cbe8aSDavid Wu static const struct rockchip_saradc_data rk3066_tsadc_data = {
154ae6cbe8aSDavid Wu 	.num_bits = 12,
155ae6cbe8aSDavid Wu 	.num_channels = 2,
156ae6cbe8aSDavid Wu 	.clk_rate = 50000,
157ae6cbe8aSDavid Wu };
158ae6cbe8aSDavid Wu 
159ae6cbe8aSDavid Wu static const struct rockchip_saradc_data rk3399_saradc_data = {
160ae6cbe8aSDavid Wu 	.num_bits = 10,
161ae6cbe8aSDavid Wu 	.num_channels = 6,
162ae6cbe8aSDavid Wu 	.clk_rate = 1000000,
163ae6cbe8aSDavid Wu };
164ae6cbe8aSDavid Wu 
165ae6cbe8aSDavid Wu static const struct udevice_id rockchip_saradc_ids[] = {
166ae6cbe8aSDavid Wu 	{ .compatible = "rockchip,saradc",
167ae6cbe8aSDavid Wu 	  .data = (ulong)&saradc_data },
168ae6cbe8aSDavid Wu 	{ .compatible = "rockchip,rk3066-tsadc",
169ae6cbe8aSDavid Wu 	  .data = (ulong)&rk3066_tsadc_data },
170ae6cbe8aSDavid Wu 	{ .compatible = "rockchip,rk3399-saradc",
171ae6cbe8aSDavid Wu 	  .data = (ulong)&rk3399_saradc_data },
172ae6cbe8aSDavid Wu 	{ }
173ae6cbe8aSDavid Wu };
174ae6cbe8aSDavid Wu 
175ae6cbe8aSDavid Wu U_BOOT_DRIVER(rockchip_saradc) = {
176ae6cbe8aSDavid Wu 	.name		= "rockchip_saradc",
177ae6cbe8aSDavid Wu 	.id		= UCLASS_ADC,
178ae6cbe8aSDavid Wu 	.of_match	= rockchip_saradc_ids,
179ae6cbe8aSDavid Wu 	.ops		= &rockchip_saradc_ops,
180ae6cbe8aSDavid Wu 	.probe		= rockchip_saradc_probe,
181ae6cbe8aSDavid Wu 	.ofdata_to_platdata = rockchip_saradc_ofdata_to_platdata,
182ae6cbe8aSDavid Wu 	.priv_auto_alloc_size = sizeof(struct rockchip_saradc_priv),
183ae6cbe8aSDavid Wu };
184