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