1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2020 Rockchip Electronics Co. Ltd.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Author: Algea Cao <algea.cao@rock-chips.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/i2c.h>
9*4882a593Smuzhiyun #include <linux/init.h>
10*4882a593Smuzhiyun #include <linux/interrupt.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/regmap.h>
13*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
14*4882a593Smuzhiyun #include <linux/mfd/rk630.h>
15*4882a593Smuzhiyun
rk630_macphy_enable(struct rk630 * rk630)16*4882a593Smuzhiyun static int rk630_macphy_enable(struct rk630 *rk630)
17*4882a593Smuzhiyun {
18*4882a593Smuzhiyun u32 val;
19*4882a593Smuzhiyun int ret;
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun /* IOMUX */
22*4882a593Smuzhiyun val = 0xfffc5554;
23*4882a593Smuzhiyun ret = regmap_write(rk630->grf, GRF_REG(0x8), val);
24*4882a593Smuzhiyun if (ret != 0) {
25*4882a593Smuzhiyun dev_err(rk630->dev, "Could not write to GRF: %d\n", ret);
26*4882a593Smuzhiyun return ret;
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun /* IOMUX */
30*4882a593Smuzhiyun val = 0x00330021;
31*4882a593Smuzhiyun ret = regmap_write(rk630->grf, GRF_REG(0x10), val);
32*4882a593Smuzhiyun if (ret != 0) {
33*4882a593Smuzhiyun dev_err(rk630->dev, "Could not write to GRF: %d\n", ret);
34*4882a593Smuzhiyun return ret;
35*4882a593Smuzhiyun }
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun /* reset */
38*4882a593Smuzhiyun val = BIT(12 + 16) | BIT(12);
39*4882a593Smuzhiyun ret = regmap_write(rk630->cru, CRU_REG(0x50), val);
40*4882a593Smuzhiyun if (ret != 0) {
41*4882a593Smuzhiyun dev_err(rk630->dev, "Could not write to CRU: %d\n", ret);
42*4882a593Smuzhiyun return ret;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun udelay(20);
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun val = BIT(12 + 16);
47*4882a593Smuzhiyun ret = regmap_write(rk630->cru, CRU_REG(0x50), val);
48*4882a593Smuzhiyun if (ret != 0) {
49*4882a593Smuzhiyun dev_err(rk630->dev, "Could not write to CRU: %d\n", ret);
50*4882a593Smuzhiyun return ret;
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun udelay(20);
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun /* power up && led*/
55*4882a593Smuzhiyun val = BIT(1 + 16) | BIT(1) | BIT(2 + 16);
56*4882a593Smuzhiyun ret = regmap_write(rk630->grf, GRF_REG(0x408), val);
57*4882a593Smuzhiyun if (ret != 0) {
58*4882a593Smuzhiyun dev_err(rk630->dev, "Could not write to GRF: %d\n", ret);
59*4882a593Smuzhiyun return ret;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun usleep_range(20000, 50000);
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun /* mdio_sel: mdio */
64*4882a593Smuzhiyun val = BIT(8 + 16) | BIT(8);
65*4882a593Smuzhiyun ret = regmap_write(rk630->grf, GRF_REG(0x400), val);
66*4882a593Smuzhiyun if (ret != 0) {
67*4882a593Smuzhiyun dev_err(rk630->dev, "Could not write to GRF: %d\n", ret);
68*4882a593Smuzhiyun return ret;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun /* mode sel: RMII && clock sel: 24M && BGS value: OTP && id */
72*4882a593Smuzhiyun val = (2 << 14) | (0 << 12) | (0x1 << 8) | (6 << 5) | 1;
73*4882a593Smuzhiyun ret = regmap_write(rk630->grf, GRF_REG(0x404), val | 0xffff0000);
74*4882a593Smuzhiyun if (ret != 0) {
75*4882a593Smuzhiyun dev_err(rk630->dev, "Could not write to GRF: %d\n", ret);
76*4882a593Smuzhiyun return ret;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun usleep_range(100, 150);
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun return 0;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
rk630_macphy_disable(struct rk630 * rk630)83*4882a593Smuzhiyun static int rk630_macphy_disable(struct rk630 *rk630)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun u32 val;
86*4882a593Smuzhiyun int ret;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /* GRF_SOC_CON2_CFG */
89*4882a593Smuzhiyun val = BIT(2) | BIT(16 + 2);
90*4882a593Smuzhiyun ret = regmap_write(rk630->grf, GRF_REG(0x408), val);
91*4882a593Smuzhiyun if (ret != 0) {
92*4882a593Smuzhiyun dev_err(rk630->dev, "Could not write to GRF: %d\n", ret);
93*4882a593Smuzhiyun return ret;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun return 0;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun static const struct mfd_cell rk630_devs[] = {
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun .name = "rk630-tve",
102*4882a593Smuzhiyun .of_compatible = "rockchip,rk630-tve",
103*4882a593Smuzhiyun },
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun .name = "rk630-macphy",
106*4882a593Smuzhiyun .of_compatible = "rockchip,rk630-macphy",
107*4882a593Smuzhiyun },
108*4882a593Smuzhiyun };
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun static const struct regmap_range rk630_grf_readable_ranges[] = {
111*4882a593Smuzhiyun regmap_reg_range(PLUMAGE_GRF_GPIO0A_IOMUX, PLUMAGE_GRF_GPIO0A_IOMUX),
112*4882a593Smuzhiyun regmap_reg_range(PLUMAGE_GRF_GPIO0B_IOMUX, PLUMAGE_GRF_GPIO0B_IOMUX),
113*4882a593Smuzhiyun regmap_reg_range(PLUMAGE_GRF_GPIO0C_IOMUX, PLUMAGE_GRF_GPIO0C_IOMUX),
114*4882a593Smuzhiyun regmap_reg_range(PLUMAGE_GRF_GPIO0D_IOMUX, PLUMAGE_GRF_GPIO0D_IOMUX),
115*4882a593Smuzhiyun regmap_reg_range(PLUMAGE_GRF_GPIO1A_IOMUX, PLUMAGE_GRF_GPIO1A_IOMUX),
116*4882a593Smuzhiyun regmap_reg_range(PLUMAGE_GRF_GPIO1B_IOMUX, PLUMAGE_GRF_GPIO1B_IOMUX),
117*4882a593Smuzhiyun regmap_reg_range(PLUMAGE_GRF_GPIO0A_P, PLUMAGE_GRF_GPIO1B_P),
118*4882a593Smuzhiyun regmap_reg_range(PLUMAGE_GRF_GPIO1B_SR, PLUMAGE_GRF_GPIO1B_SR),
119*4882a593Smuzhiyun regmap_reg_range(PLUMAGE_GRF_GPIO1B_E, PLUMAGE_GRF_GPIO1B_E),
120*4882a593Smuzhiyun regmap_reg_range(PLUMAGE_GRF_SOC_CON0, PLUMAGE_GRF_SOC_CON4),
121*4882a593Smuzhiyun regmap_reg_range(PLUMAGE_GRF_SOC_STATUS, PLUMAGE_GRF_SOC_STATUS),
122*4882a593Smuzhiyun regmap_reg_range(PLUMAGE_GRF_GPIO0_REN0, PLUMAGE_GRF_GPIO1_REN0),
123*4882a593Smuzhiyun };
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun static const struct regmap_access_table rk630_grf_readable_table = {
126*4882a593Smuzhiyun .yes_ranges = rk630_grf_readable_ranges,
127*4882a593Smuzhiyun .n_yes_ranges = ARRAY_SIZE(rk630_grf_readable_ranges),
128*4882a593Smuzhiyun };
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun const struct regmap_config rk630_grf_regmap_config = {
131*4882a593Smuzhiyun .name = "grf",
132*4882a593Smuzhiyun .reg_bits = 32,
133*4882a593Smuzhiyun .val_bits = 32,
134*4882a593Smuzhiyun .reg_stride = 4,
135*4882a593Smuzhiyun .max_register = GRF_MAX_REGISTER,
136*4882a593Smuzhiyun .reg_format_endian = REGMAP_ENDIAN_NATIVE,
137*4882a593Smuzhiyun .val_format_endian = REGMAP_ENDIAN_NATIVE,
138*4882a593Smuzhiyun .rd_table = &rk630_grf_readable_table,
139*4882a593Smuzhiyun };
140*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rk630_grf_regmap_config);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun static const struct regmap_range rk630_cru_readable_ranges[] = {
143*4882a593Smuzhiyun regmap_reg_range(CRU_SPLL_CON0, CRU_SPLL_CON2),
144*4882a593Smuzhiyun regmap_reg_range(CRU_MODE_CON, CRU_MODE_CON),
145*4882a593Smuzhiyun regmap_reg_range(CRU_CLKSEL_CON0, CRU_CLKSEL_CON3),
146*4882a593Smuzhiyun regmap_reg_range(CRU_GATE_CON0, CRU_GATE_CON0),
147*4882a593Smuzhiyun regmap_reg_range(CRU_SOFTRST_CON0, CRU_SOFTRST_CON0),
148*4882a593Smuzhiyun };
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun static const struct regmap_access_table rk630_cru_readable_table = {
151*4882a593Smuzhiyun .yes_ranges = rk630_cru_readable_ranges,
152*4882a593Smuzhiyun .n_yes_ranges = ARRAY_SIZE(rk630_cru_readable_ranges),
153*4882a593Smuzhiyun };
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun const struct regmap_config rk630_cru_regmap_config = {
156*4882a593Smuzhiyun .name = "cru",
157*4882a593Smuzhiyun .reg_bits = 32,
158*4882a593Smuzhiyun .val_bits = 32,
159*4882a593Smuzhiyun .reg_stride = 4,
160*4882a593Smuzhiyun .max_register = CRU_MAX_REGISTER,
161*4882a593Smuzhiyun .reg_format_endian = REGMAP_ENDIAN_NATIVE,
162*4882a593Smuzhiyun .val_format_endian = REGMAP_ENDIAN_NATIVE,
163*4882a593Smuzhiyun .rd_table = &rk630_cru_readable_table,
164*4882a593Smuzhiyun };
165*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rk630_cru_regmap_config);
166*4882a593Smuzhiyun
rk630_core_probe(struct rk630 * rk630)167*4882a593Smuzhiyun int rk630_core_probe(struct rk630 *rk630)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun bool macphy_enabled = false;
170*4882a593Smuzhiyun struct device_node *np;
171*4882a593Smuzhiyun int ret;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun rk630->reset_gpio = devm_gpiod_get(rk630->dev, "reset", 0);
174*4882a593Smuzhiyun if (IS_ERR(rk630->reset_gpio)) {
175*4882a593Smuzhiyun ret = PTR_ERR(rk630->reset_gpio);
176*4882a593Smuzhiyun dev_err(rk630->dev, "failed to request reset GPIO: %d\n", ret);
177*4882a593Smuzhiyun return ret;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun gpiod_direction_output(rk630->reset_gpio, 0);
181*4882a593Smuzhiyun usleep_range(2000, 4000);
182*4882a593Smuzhiyun gpiod_direction_output(rk630->reset_gpio, 1);
183*4882a593Smuzhiyun usleep_range(50000, 60000);
184*4882a593Smuzhiyun gpiod_direction_output(rk630->reset_gpio, 0);
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun ret = devm_mfd_add_devices(rk630->dev, PLATFORM_DEVID_NONE,
187*4882a593Smuzhiyun rk630_devs, ARRAY_SIZE(rk630_devs),
188*4882a593Smuzhiyun NULL, 0, NULL);
189*4882a593Smuzhiyun if (ret) {
190*4882a593Smuzhiyun dev_err(rk630->dev, "failed to add MFD children: %d\n", ret);
191*4882a593Smuzhiyun return ret;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun for_each_child_of_node(rk630->dev->of_node, np) {
195*4882a593Smuzhiyun if (!of_device_is_compatible(np, "rockchip,rk630-macphy"))
196*4882a593Smuzhiyun continue;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun if (!of_device_is_available(np)) {
199*4882a593Smuzhiyun continue;
200*4882a593Smuzhiyun } else {
201*4882a593Smuzhiyun macphy_enabled = true;
202*4882a593Smuzhiyun break;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun if (macphy_enabled)
207*4882a593Smuzhiyun rk630_macphy_enable(rk630);
208*4882a593Smuzhiyun else
209*4882a593Smuzhiyun rk630_macphy_disable(rk630);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun return 0;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rk630_core_probe);
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun MODULE_AUTHOR("Algea Cao <Algea.cao@rock-chips.com>");
216*4882a593Smuzhiyun MODULE_DESCRIPTION("Rockchip rk630 MFD Core driver");
217*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
218