1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2020 Rockchip Electronics Co. Ltd.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Author: Wyon Bi <bivvy.bi@rock-chips.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <asm/bitsperlong.h>
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/clk.h>
11*4882a593Smuzhiyun #include <linux/delay.h>
12*4882a593Smuzhiyun #include <linux/init.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/of_device.h>
15*4882a593Smuzhiyun #include <linux/platform_device.h>
16*4882a593Smuzhiyun #include <linux/reset.h>
17*4882a593Smuzhiyun #include <linux/mfd/rk628.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include "rk628_combtxphy.h"
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define REG(x) ((x) + 0x90000)
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #define COMBTXPHY_CON0 REG(0x0000)
24*4882a593Smuzhiyun #define SW_TX_IDLE_MASK GENMASK(29, 20)
25*4882a593Smuzhiyun #define SW_TX_IDLE(x) UPDATE(x, 29, 20)
26*4882a593Smuzhiyun #define SW_TX_PD_MASK GENMASK(17, 8)
27*4882a593Smuzhiyun #define SW_TX_PD(x) UPDATE(x, 17, 8)
28*4882a593Smuzhiyun #define SW_BUS_WIDTH_MASK GENMASK(6, 5)
29*4882a593Smuzhiyun #define SW_BUS_WIDTH_7BIT UPDATE(0x3, 6, 5)
30*4882a593Smuzhiyun #define SW_BUS_WIDTH_8BIT UPDATE(0x2, 6, 5)
31*4882a593Smuzhiyun #define SW_BUS_WIDTH_9BIT UPDATE(0x1, 6, 5)
32*4882a593Smuzhiyun #define SW_BUS_WIDTH_10BIT UPDATE(0x0, 6, 5)
33*4882a593Smuzhiyun #define SW_PD_PLL_MASK BIT(4)
34*4882a593Smuzhiyun #define SW_PD_PLL BIT(4)
35*4882a593Smuzhiyun #define SW_GVI_LVDS_EN_MASK BIT(3)
36*4882a593Smuzhiyun #define SW_GVI_LVDS_EN BIT(3)
37*4882a593Smuzhiyun #define SW_MIPI_DSI_EN_MASK BIT(2)
38*4882a593Smuzhiyun #define SW_MIPI_DSI_EN BIT(2)
39*4882a593Smuzhiyun #define SW_MODULEB_EN_MASK BIT(1)
40*4882a593Smuzhiyun #define SW_MODULEB_EN BIT(1)
41*4882a593Smuzhiyun #define SW_MODULEA_EN_MASK BIT(0)
42*4882a593Smuzhiyun #define SW_MODULEA_EN BIT(0)
43*4882a593Smuzhiyun #define COMBTXPHY_CON1 REG(0x0004)
44*4882a593Smuzhiyun #define COMBTXPHY_CON2 REG(0x0008)
45*4882a593Smuzhiyun #define COMBTXPHY_CON3 REG(0x000c)
46*4882a593Smuzhiyun #define COMBTXPHY_CON4 REG(0x0010)
47*4882a593Smuzhiyun #define COMBTXPHY_CON5 REG(0x0014)
48*4882a593Smuzhiyun #define SW_RATE(x) UPDATE(x, 26, 24)
49*4882a593Smuzhiyun #define SW_REF_DIV(x) UPDATE(x, 20, 16)
50*4882a593Smuzhiyun #define SW_PLL_FB_DIV(x) UPDATE(x, 14, 10)
51*4882a593Smuzhiyun #define SW_PLL_FRAC_DIV(x) UPDATE(x, 9, 0)
52*4882a593Smuzhiyun #define COMBTXPHY_CON6 REG(0x0018)
53*4882a593Smuzhiyun #define COMBTXPHY_CON7 REG(0x001c)
54*4882a593Smuzhiyun #define SW_TX_RTERM_MASK GENMASK(22, 20)
55*4882a593Smuzhiyun #define SW_TX_RTERM(x) UPDATE(x, 22, 20)
56*4882a593Smuzhiyun #define SW_TX_MODE_MASK GENMASK(17, 16)
57*4882a593Smuzhiyun #define SW_TX_MODE(x) UPDATE(x, 17, 16)
58*4882a593Smuzhiyun #define SW_TX_CTL_CON5_MASK BIT(10)
59*4882a593Smuzhiyun #define SW_TX_CTL_CON5(x) UPDATE(x, 10, 10)
60*4882a593Smuzhiyun #define SW_TX_CTL_CON4_MASK GENMASK(9, 8)
61*4882a593Smuzhiyun #define SW_TX_CTL_CON4(x) UPDATE(x, 9, 8)
62*4882a593Smuzhiyun #define BYPASS_095V_LDO_MASK BIT(3)
63*4882a593Smuzhiyun #define BYPASS_095V_LDO(x) UPDATE(x, 3, 3)
64*4882a593Smuzhiyun #define TX_COM_VOLT_ADJ_MASK GENMASK(2, 0)
65*4882a593Smuzhiyun #define TX_COM_VOLT_ADJ(x) UPDATE(x, 2, 0)
66*4882a593Smuzhiyun #define COMBTXPHY_CON8 REG(0x0020)
67*4882a593Smuzhiyun #define COMBTXPHY_CON9 REG(0x0024)
68*4882a593Smuzhiyun #define SW_DSI_FSET_EN_MASK BIT(29)
69*4882a593Smuzhiyun #define SW_DSI_FSET_EN BIT(29)
70*4882a593Smuzhiyun #define SW_DSI_RCAL_EN_MASK BIT(28)
71*4882a593Smuzhiyun #define SW_DSI_RCAL_EN BIT(28)
72*4882a593Smuzhiyun #define COMBTXPHY_CON10 REG(0x0028)
73*4882a593Smuzhiyun #define TX9_CKDRV_EN BIT(9)
74*4882a593Smuzhiyun #define TX8_CKDRV_EN BIT(8)
75*4882a593Smuzhiyun #define TX7_CKDRV_EN BIT(7)
76*4882a593Smuzhiyun #define TX6_CKDRV_EN BIT(6)
77*4882a593Smuzhiyun #define TX5_CKDRV_EN BIT(5)
78*4882a593Smuzhiyun #define TX4_CKDRV_EN BIT(4)
79*4882a593Smuzhiyun #define TX3_CKDRV_EN BIT(3)
80*4882a593Smuzhiyun #define TX2_CKDRV_EN BIT(2)
81*4882a593Smuzhiyun #define TX1_CKDRV_EN BIT(1)
82*4882a593Smuzhiyun #define TX0_CKDRV_EN BIT(0)
83*4882a593Smuzhiyun #define COMBTXPHY_MAX_REGISTER COMBTXPHY_CON10
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun struct rk628_combtxphy {
86*4882a593Smuzhiyun struct device *dev;
87*4882a593Smuzhiyun struct rk628 *parent;
88*4882a593Smuzhiyun struct regmap *grf;
89*4882a593Smuzhiyun struct regmap *regmap;
90*4882a593Smuzhiyun struct clk *pclk;
91*4882a593Smuzhiyun struct clk *ref_clk;
92*4882a593Smuzhiyun struct reset_control *rstc;
93*4882a593Smuzhiyun unsigned int flags;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun u16 frac_div;
96*4882a593Smuzhiyun u8 ref_div;
97*4882a593Smuzhiyun u8 fb_div;
98*4882a593Smuzhiyun u8 rate_div;
99*4882a593Smuzhiyun u8 division_mode;
100*4882a593Smuzhiyun };
101*4882a593Smuzhiyun
rk628_combtxphy_dsi_power_on(struct rk628_combtxphy * combtxphy)102*4882a593Smuzhiyun static int rk628_combtxphy_dsi_power_on(struct rk628_combtxphy *combtxphy)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun u32 val;
105*4882a593Smuzhiyun int ret;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
108*4882a593Smuzhiyun SW_BUS_WIDTH_MASK | SW_GVI_LVDS_EN_MASK |
109*4882a593Smuzhiyun SW_MIPI_DSI_EN_MASK,
110*4882a593Smuzhiyun SW_BUS_WIDTH_8BIT | SW_MIPI_DSI_EN);
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun if (combtxphy->flags & COMBTXPHY_MODULEA_EN)
113*4882a593Smuzhiyun regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
114*4882a593Smuzhiyun SW_MODULEA_EN_MASK, SW_MODULEA_EN);
115*4882a593Smuzhiyun if (combtxphy->flags & COMBTXPHY_MODULEB_EN)
116*4882a593Smuzhiyun regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
117*4882a593Smuzhiyun SW_MODULEB_EN_MASK, SW_MODULEB_EN);
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun regmap_write(combtxphy->regmap, COMBTXPHY_CON5,
120*4882a593Smuzhiyun SW_REF_DIV(combtxphy->ref_div - 1) |
121*4882a593Smuzhiyun SW_PLL_FB_DIV(combtxphy->fb_div) |
122*4882a593Smuzhiyun SW_PLL_FRAC_DIV(combtxphy->frac_div) |
123*4882a593Smuzhiyun SW_RATE(combtxphy->rate_div / 2));
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
126*4882a593Smuzhiyun SW_PD_PLL, 0);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun ret = regmap_read_poll_timeout(combtxphy->grf, GRF_DPHY0_STATUS,
129*4882a593Smuzhiyun val, val & DPHY_PHYLOCK, 0, 1000);
130*4882a593Smuzhiyun if (ret < 0) {
131*4882a593Smuzhiyun dev_err(combtxphy->dev, "phy is not lock\n");
132*4882a593Smuzhiyun return ret;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON9,
136*4882a593Smuzhiyun SW_DSI_FSET_EN_MASK | SW_DSI_RCAL_EN_MASK,
137*4882a593Smuzhiyun SW_DSI_FSET_EN | SW_DSI_RCAL_EN);
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun usleep_range(200, 400);
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun return 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
rk628_combtxphy_lvds_power_on(struct rk628_combtxphy * combtxphy)144*4882a593Smuzhiyun static int rk628_combtxphy_lvds_power_on(struct rk628_combtxphy *combtxphy)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun u32 val;
147*4882a593Smuzhiyun int ret;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun /* Adjust terminal resistance 133 ohm, bypass 0.95v ldo for driver. */
150*4882a593Smuzhiyun regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON7,
151*4882a593Smuzhiyun SW_TX_RTERM_MASK | SW_TX_MODE_MASK |
152*4882a593Smuzhiyun BYPASS_095V_LDO_MASK | TX_COM_VOLT_ADJ_MASK,
153*4882a593Smuzhiyun SW_TX_RTERM(6) | SW_TX_MODE(3) |
154*4882a593Smuzhiyun BYPASS_095V_LDO(1) | TX_COM_VOLT_ADJ(0));
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun regmap_write(combtxphy->regmap, COMBTXPHY_CON10,
157*4882a593Smuzhiyun TX7_CKDRV_EN | TX2_CKDRV_EN);
158*4882a593Smuzhiyun regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
159*4882a593Smuzhiyun SW_BUS_WIDTH_MASK | SW_GVI_LVDS_EN_MASK |
160*4882a593Smuzhiyun SW_MIPI_DSI_EN_MASK,
161*4882a593Smuzhiyun SW_BUS_WIDTH_7BIT | SW_GVI_LVDS_EN);
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun if (combtxphy->flags & COMBTXPHY_MODULEA_EN)
164*4882a593Smuzhiyun regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
165*4882a593Smuzhiyun SW_MODULEA_EN_MASK, SW_MODULEA_EN);
166*4882a593Smuzhiyun if (combtxphy->flags & COMBTXPHY_MODULEB_EN)
167*4882a593Smuzhiyun regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
168*4882a593Smuzhiyun SW_MODULEB_EN_MASK, SW_MODULEB_EN);
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun regmap_write(combtxphy->regmap, COMBTXPHY_CON5,
171*4882a593Smuzhiyun SW_REF_DIV(combtxphy->ref_div - 1) |
172*4882a593Smuzhiyun SW_PLL_FB_DIV(combtxphy->fb_div) |
173*4882a593Smuzhiyun SW_PLL_FRAC_DIV(combtxphy->frac_div) |
174*4882a593Smuzhiyun SW_RATE(combtxphy->rate_div / 2));
175*4882a593Smuzhiyun regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
176*4882a593Smuzhiyun SW_PD_PLL, 0);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun ret = regmap_read_poll_timeout(combtxphy->grf, GRF_DPHY0_STATUS,
179*4882a593Smuzhiyun val, val & DPHY_PHYLOCK, 0, 1000);
180*4882a593Smuzhiyun if (ret < 0) {
181*4882a593Smuzhiyun dev_info(combtxphy->dev, "phy is not lock\n");
182*4882a593Smuzhiyun return ret;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun usleep_range(100, 200);
186*4882a593Smuzhiyun regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
187*4882a593Smuzhiyun SW_TX_IDLE_MASK | SW_TX_PD_MASK, 0);
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun return 0;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
rk628_combtxphy_gvi_power_on(struct rk628_combtxphy * combtxphy)192*4882a593Smuzhiyun static int rk628_combtxphy_gvi_power_on(struct rk628_combtxphy *combtxphy)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun int ref_div = 0;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun if (combtxphy->ref_div % 2) {
197*4882a593Smuzhiyun ref_div = combtxphy->ref_div - 1;
198*4882a593Smuzhiyun } else {
199*4882a593Smuzhiyun ref_div = BIT(4);
200*4882a593Smuzhiyun ref_div |= combtxphy->ref_div / 2 - 1;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun regmap_write(combtxphy->regmap, COMBTXPHY_CON5,
203*4882a593Smuzhiyun SW_REF_DIV(ref_div) |
204*4882a593Smuzhiyun SW_PLL_FB_DIV(combtxphy->fb_div) |
205*4882a593Smuzhiyun SW_PLL_FRAC_DIV(combtxphy->frac_div) |
206*4882a593Smuzhiyun SW_RATE(combtxphy->rate_div / 2));
207*4882a593Smuzhiyun regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
208*4882a593Smuzhiyun SW_BUS_WIDTH_MASK | SW_GVI_LVDS_EN_MASK |
209*4882a593Smuzhiyun SW_MIPI_DSI_EN_MASK |
210*4882a593Smuzhiyun SW_MODULEB_EN_MASK | SW_MODULEA_EN_MASK,
211*4882a593Smuzhiyun SW_BUS_WIDTH_10BIT | SW_GVI_LVDS_EN |
212*4882a593Smuzhiyun SW_MODULEB_EN | SW_MODULEA_EN);
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
215*4882a593Smuzhiyun SW_PD_PLL | SW_TX_PD_MASK, 0);
216*4882a593Smuzhiyun usleep_range(100, 200);
217*4882a593Smuzhiyun regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
218*4882a593Smuzhiyun SW_TX_IDLE_MASK, 0);
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun return 0;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun
rk628_combtxphy_set_gvi_division_mode(struct phy * phy,u8 mode)223*4882a593Smuzhiyun int rk628_combtxphy_set_gvi_division_mode(struct phy *phy, u8 mode)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun struct rk628_combtxphy *combtxphy = phy_get_drvdata(phy);
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun combtxphy->division_mode = mode;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun return 0;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun EXPORT_SYMBOL(rk628_combtxphy_set_gvi_division_mode);
232*4882a593Smuzhiyun
rk628_combtxphy_power_on(struct phy * phy)233*4882a593Smuzhiyun static int rk628_combtxphy_power_on(struct phy *phy)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun struct rk628_combtxphy *combtxphy = phy_get_drvdata(phy);
236*4882a593Smuzhiyun enum phy_mode mode = phy_get_mode(phy);
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun clk_prepare_enable(combtxphy->pclk);
239*4882a593Smuzhiyun reset_control_assert(combtxphy->rstc);
240*4882a593Smuzhiyun udelay(10);
241*4882a593Smuzhiyun reset_control_deassert(combtxphy->rstc);
242*4882a593Smuzhiyun udelay(10);
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun regcache_mark_dirty(combtxphy->regmap);
245*4882a593Smuzhiyun regcache_sync(combtxphy->regmap);
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
248*4882a593Smuzhiyun SW_TX_IDLE_MASK | SW_TX_PD_MASK | SW_PD_PLL_MASK,
249*4882a593Smuzhiyun SW_TX_IDLE(0x3ff) | SW_TX_PD(0x3ff) | SW_PD_PLL);
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun switch (mode) {
252*4882a593Smuzhiyun case PHY_MODE_MIPI_DPHY:
253*4882a593Smuzhiyun regmap_update_bits(combtxphy->grf, GRF_POST_PROC_CON,
254*4882a593Smuzhiyun SW_TXPHY_REFCLK_SEL_MASK,
255*4882a593Smuzhiyun SW_TXPHY_REFCLK_SEL(0));
256*4882a593Smuzhiyun return rk628_combtxphy_dsi_power_on(combtxphy);
257*4882a593Smuzhiyun case PHY_MODE_LVDS:
258*4882a593Smuzhiyun regmap_update_bits(combtxphy->grf, GRF_POST_PROC_CON,
259*4882a593Smuzhiyun SW_TXPHY_REFCLK_SEL_MASK,
260*4882a593Smuzhiyun SW_TXPHY_REFCLK_SEL(1));
261*4882a593Smuzhiyun return rk628_combtxphy_lvds_power_on(combtxphy);
262*4882a593Smuzhiyun default:
263*4882a593Smuzhiyun regmap_update_bits(combtxphy->grf, GRF_POST_PROC_CON,
264*4882a593Smuzhiyun SW_TXPHY_REFCLK_SEL_MASK,
265*4882a593Smuzhiyun SW_TXPHY_REFCLK_SEL(2));
266*4882a593Smuzhiyun return rk628_combtxphy_gvi_power_on(combtxphy);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun return 0;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
rk628_combtxphy_power_off(struct phy * phy)272*4882a593Smuzhiyun static int rk628_combtxphy_power_off(struct phy *phy)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun struct rk628_combtxphy *combtxphy = phy_get_drvdata(phy);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun regmap_update_bits(combtxphy->regmap, COMBTXPHY_CON0,
277*4882a593Smuzhiyun SW_TX_IDLE_MASK | SW_TX_PD_MASK | SW_PD_PLL_MASK |
278*4882a593Smuzhiyun SW_MODULEB_EN_MASK | SW_MODULEA_EN_MASK,
279*4882a593Smuzhiyun SW_TX_IDLE(0x3ff) | SW_TX_PD(0x3ff) | SW_PD_PLL);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun clk_disable_unprepare(combtxphy->pclk);
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun return 0;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
rk628_combtxphy_set_mode(struct phy * phy,enum phy_mode mode,int submode)286*4882a593Smuzhiyun static int rk628_combtxphy_set_mode(struct phy *phy, enum phy_mode mode,
287*4882a593Smuzhiyun int submode)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun struct rk628_combtxphy *combtxphy = phy_get_drvdata(phy);
290*4882a593Smuzhiyun unsigned int bus_width = phy_get_bus_width(phy);
291*4882a593Smuzhiyun unsigned int frac_rate, fin = 24;
292*4882a593Smuzhiyun unsigned long fvco, fpfd;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun switch (mode) {
295*4882a593Smuzhiyun case PHY_MODE_MIPI_DPHY:
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun unsigned int fhsc = bus_width >> 8;
298*4882a593Smuzhiyun unsigned int flags = bus_width & 0xff;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun fhsc = fin * (fhsc / fin);
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun if (fhsc < 80 || fhsc > 1500)
303*4882a593Smuzhiyun return -EINVAL;
304*4882a593Smuzhiyun else if (fhsc < 375)
305*4882a593Smuzhiyun combtxphy->rate_div = 4;
306*4882a593Smuzhiyun else if (fhsc < 750)
307*4882a593Smuzhiyun combtxphy->rate_div = 2;
308*4882a593Smuzhiyun else
309*4882a593Smuzhiyun combtxphy->rate_div = 1;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun combtxphy->flags = flags;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun fvco = fhsc * 2 * combtxphy->rate_div;
314*4882a593Smuzhiyun combtxphy->ref_div = 1;
315*4882a593Smuzhiyun combtxphy->fb_div = fvco / 8 / fin;
316*4882a593Smuzhiyun frac_rate = fvco - (fin * 8 * combtxphy->fb_div);
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun if (frac_rate) {
319*4882a593Smuzhiyun frac_rate <<= 10;
320*4882a593Smuzhiyun frac_rate /= fin * 8;
321*4882a593Smuzhiyun combtxphy->frac_div = frac_rate;
322*4882a593Smuzhiyun } else {
323*4882a593Smuzhiyun combtxphy->frac_div = 0;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun fvco = fin * (1024 * combtxphy->fb_div + combtxphy->frac_div);
327*4882a593Smuzhiyun fvco *= 8;
328*4882a593Smuzhiyun fvco = DIV_ROUND_UP(fvco, 1024 * combtxphy->ref_div);
329*4882a593Smuzhiyun fhsc = fvco / 2 / combtxphy->rate_div;
330*4882a593Smuzhiyun phy_set_bus_width(phy, fhsc);
331*4882a593Smuzhiyun break;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun case PHY_MODE_LVDS:
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun unsigned int flags = bus_width & 0xff;
336*4882a593Smuzhiyun unsigned int rate = (bus_width >> 8) * 7;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun combtxphy->flags = flags;
339*4882a593Smuzhiyun combtxphy->ref_div = 1;
340*4882a593Smuzhiyun combtxphy->fb_div = 14;
341*4882a593Smuzhiyun combtxphy->frac_div = 0;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun if (rate < 500)
344*4882a593Smuzhiyun combtxphy->rate_div = 4;
345*4882a593Smuzhiyun else if (rate < 1000)
346*4882a593Smuzhiyun combtxphy->rate_div = 2;
347*4882a593Smuzhiyun else
348*4882a593Smuzhiyun combtxphy->rate_div = 1;
349*4882a593Smuzhiyun break;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun default:
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun unsigned int i, delta_freq, best_delta_freq, fb_div;
354*4882a593Smuzhiyun unsigned long ref_clk;
355*4882a593Smuzhiyun unsigned long long pre_clk;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun if (bus_width < 500000 || bus_width > 4000000)
358*4882a593Smuzhiyun return -EINVAL;
359*4882a593Smuzhiyun else if (bus_width < 1000000)
360*4882a593Smuzhiyun combtxphy->rate_div = 4;
361*4882a593Smuzhiyun else if (bus_width < 2000000)
362*4882a593Smuzhiyun combtxphy->rate_div = 2;
363*4882a593Smuzhiyun else
364*4882a593Smuzhiyun combtxphy->rate_div = 1;
365*4882a593Smuzhiyun fvco = bus_width * combtxphy->rate_div;
366*4882a593Smuzhiyun ref_clk = clk_get_rate(combtxphy->ref_clk) / 1000; /* khz */
367*4882a593Smuzhiyun if (combtxphy->division_mode)
368*4882a593Smuzhiyun ref_clk /= 2;
369*4882a593Smuzhiyun /*
370*4882a593Smuzhiyun * the reference clock at PFD(FPFD = ref_clk / ref_div) about
371*4882a593Smuzhiyun * 25MHz is recommende, FPFD must range from 16MHz to 35MHz,
372*4882a593Smuzhiyun * here to find the best rev_div.
373*4882a593Smuzhiyun */
374*4882a593Smuzhiyun best_delta_freq = ref_clk;
375*4882a593Smuzhiyun for (i = 1; i <= 32; i++) {
376*4882a593Smuzhiyun fpfd = ref_clk / i;
377*4882a593Smuzhiyun delta_freq = abs(fpfd - 25000);
378*4882a593Smuzhiyun if (delta_freq < best_delta_freq) {
379*4882a593Smuzhiyun best_delta_freq = delta_freq;
380*4882a593Smuzhiyun combtxphy->ref_div = i;
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun /*
385*4882a593Smuzhiyun * ref_clk / ref_div * 8 * fb_div = FVCO
386*4882a593Smuzhiyun */
387*4882a593Smuzhiyun pre_clk = (unsigned long long)fvco / 8 * combtxphy->ref_div * 1024;
388*4882a593Smuzhiyun do_div(pre_clk, ref_clk);
389*4882a593Smuzhiyun fb_div = pre_clk / 1024;
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun /*
392*4882a593Smuzhiyun * get the actually frequence
393*4882a593Smuzhiyun */
394*4882a593Smuzhiyun bus_width = ref_clk / combtxphy->ref_div * 8;
395*4882a593Smuzhiyun bus_width *= fb_div;
396*4882a593Smuzhiyun bus_width /= combtxphy->rate_div;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun combtxphy->frac_div = 0;
399*4882a593Smuzhiyun combtxphy->fb_div = fb_div;
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun phy_set_bus_width(phy, bus_width);
402*4882a593Smuzhiyun break;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun return 0;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun static const struct phy_ops rk628_combtxphy_ops = {
410*4882a593Smuzhiyun .set_mode = rk628_combtxphy_set_mode,
411*4882a593Smuzhiyun .power_on = rk628_combtxphy_power_on,
412*4882a593Smuzhiyun .power_off = rk628_combtxphy_power_off,
413*4882a593Smuzhiyun .owner = THIS_MODULE,
414*4882a593Smuzhiyun };
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun static const struct regmap_range rk628_combtxphy_readable_ranges[] = {
417*4882a593Smuzhiyun regmap_reg_range(COMBTXPHY_CON0, COMBTXPHY_CON10),
418*4882a593Smuzhiyun };
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun static const struct regmap_access_table rk628_combtxphy_readable_table = {
421*4882a593Smuzhiyun .yes_ranges = rk628_combtxphy_readable_ranges,
422*4882a593Smuzhiyun .n_yes_ranges = ARRAY_SIZE(rk628_combtxphy_readable_ranges),
423*4882a593Smuzhiyun };
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun static const struct regmap_config rk628_combtxphy_regmap_cfg = {
426*4882a593Smuzhiyun .name = "combtxphy",
427*4882a593Smuzhiyun .reg_bits = 32,
428*4882a593Smuzhiyun .val_bits = 32,
429*4882a593Smuzhiyun .reg_stride = 4,
430*4882a593Smuzhiyun .cache_type = REGCACHE_RBTREE,
431*4882a593Smuzhiyun .max_register = COMBTXPHY_MAX_REGISTER,
432*4882a593Smuzhiyun .reg_format_endian = REGMAP_ENDIAN_LITTLE,
433*4882a593Smuzhiyun .val_format_endian = REGMAP_ENDIAN_LITTLE,
434*4882a593Smuzhiyun .rd_table = &rk628_combtxphy_readable_table,
435*4882a593Smuzhiyun };
436*4882a593Smuzhiyun
rk628_combtxphy_probe(struct platform_device * pdev)437*4882a593Smuzhiyun static int rk628_combtxphy_probe(struct platform_device *pdev)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun struct rk628 *rk628 = dev_get_drvdata(pdev->dev.parent);
440*4882a593Smuzhiyun struct device *dev = &pdev->dev;
441*4882a593Smuzhiyun struct rk628_combtxphy *combtxphy;
442*4882a593Smuzhiyun struct phy_provider *phy_provider;
443*4882a593Smuzhiyun struct phy *phy;
444*4882a593Smuzhiyun int ret;
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun combtxphy = devm_kzalloc(dev, sizeof(*combtxphy), GFP_KERNEL);
447*4882a593Smuzhiyun if (!combtxphy)
448*4882a593Smuzhiyun return -ENOMEM;
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun combtxphy->dev = dev;
451*4882a593Smuzhiyun combtxphy->parent = rk628;
452*4882a593Smuzhiyun combtxphy->grf = rk628->grf;
453*4882a593Smuzhiyun platform_set_drvdata(pdev, combtxphy);
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun combtxphy->pclk = devm_clk_get(dev, "pclk");
456*4882a593Smuzhiyun if (IS_ERR(combtxphy->pclk))
457*4882a593Smuzhiyun return PTR_ERR(combtxphy->pclk);
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun combtxphy->ref_clk = devm_clk_get(dev, "ref_clk");
460*4882a593Smuzhiyun if (IS_ERR(combtxphy->ref_clk)) {
461*4882a593Smuzhiyun dev_err(dev, "fail to get ref clk\n");
462*4882a593Smuzhiyun return PTR_ERR(combtxphy->ref_clk);
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun combtxphy->rstc = of_reset_control_get(dev->of_node, NULL);
466*4882a593Smuzhiyun if (IS_ERR(combtxphy->rstc)) {
467*4882a593Smuzhiyun ret = PTR_ERR(combtxphy->rstc);
468*4882a593Smuzhiyun dev_err(dev, "failed to get reset control: %d\n", ret);
469*4882a593Smuzhiyun return ret;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun combtxphy->regmap = devm_regmap_init_i2c(rk628->client,
473*4882a593Smuzhiyun &rk628_combtxphy_regmap_cfg);
474*4882a593Smuzhiyun if (IS_ERR(combtxphy->regmap)) {
475*4882a593Smuzhiyun ret = PTR_ERR(combtxphy->regmap);
476*4882a593Smuzhiyun dev_err(dev, "failed to allocate register map: %d\n", ret);
477*4882a593Smuzhiyun return ret;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun phy = devm_phy_create(dev, NULL, &rk628_combtxphy_ops);
481*4882a593Smuzhiyun if (IS_ERR(phy)) {
482*4882a593Smuzhiyun ret = PTR_ERR(phy);
483*4882a593Smuzhiyun dev_err(dev, "failed to create phy: %d\n", ret);
484*4882a593Smuzhiyun return ret;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun phy_set_drvdata(phy, combtxphy);
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
490*4882a593Smuzhiyun if (IS_ERR(phy_provider)) {
491*4882a593Smuzhiyun ret = PTR_ERR(phy_provider);
492*4882a593Smuzhiyun dev_err(dev, "failed to register phy provider: %d\n", ret);
493*4882a593Smuzhiyun return ret;
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun return 0;
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun static const struct of_device_id rk628_combtxphy_of_match[] = {
500*4882a593Smuzhiyun { .compatible = "rockchip,rk628-combtxphy", },
501*4882a593Smuzhiyun {}
502*4882a593Smuzhiyun };
503*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, rk628_combtxphy_of_match);
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun static struct platform_driver rk628_combtxphy_driver = {
506*4882a593Smuzhiyun .driver = {
507*4882a593Smuzhiyun .name = "rk628-combtxphy",
508*4882a593Smuzhiyun .of_match_table = of_match_ptr(rk628_combtxphy_of_match),
509*4882a593Smuzhiyun },
510*4882a593Smuzhiyun .probe = rk628_combtxphy_probe,
511*4882a593Smuzhiyun };
512*4882a593Smuzhiyun module_platform_driver(rk628_combtxphy_driver);
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun MODULE_AUTHOR("Wyon Bi <bivvy.bi@rock-chips.com>");
515*4882a593Smuzhiyun MODULE_DESCRIPTION("Rockchip RK628 GVI/LVDS/MIPI Combo TX PHY driver");
516*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
517