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