8
8
9
9
#include <linux/bitops.h>
10
10
#include <linux/clk.h>
11
+ #include <linux/module.h>
11
12
#include <linux/of_address.h>
13
+ #include <linux/platform_device.h>
12
14
#include <linux/regmap.h>
13
15
#include <linux/reset.h>
14
16
15
- #include "sun6i_mipi_dsi.h"
17
+ #include <linux/phy/phy.h>
18
+ #include <linux/phy/phy-mipi-dphy.h>
16
19
17
20
#define SUN6I_DPHY_GCTL_REG 0x00
18
21
#define SUN6I_DPHY_GCTL_LANE_NUM (n ) ((((n) - 1) & 3) << 4)
81
84
82
85
#define SUN6I_DPHY_DBG5_REG 0xf4
83
86
84
- int sun6i_dphy_init (struct sun6i_dphy * dphy , unsigned int lanes )
87
+ struct sun6i_dphy {
88
+ struct clk * bus_clk ;
89
+ struct clk * mod_clk ;
90
+ struct regmap * regs ;
91
+ struct reset_control * reset ;
92
+
93
+ struct phy * phy ;
94
+ struct phy_configure_opts_mipi_dphy config ;
95
+ };
96
+
97
+ static int sun6i_dphy_init (struct phy * phy )
85
98
{
99
+ struct sun6i_dphy * dphy = phy_get_drvdata (phy );
100
+
86
101
reset_control_deassert (dphy -> reset );
87
102
clk_prepare_enable (dphy -> mod_clk );
88
103
clk_set_rate_exclusive (dphy -> mod_clk , 150000000 );
89
104
105
+ return 0 ;
106
+ }
107
+
108
+ static int sun6i_dphy_configure (struct phy * phy , union phy_configure_opts * opts )
109
+ {
110
+ struct sun6i_dphy * dphy = phy_get_drvdata (phy );
111
+ int ret ;
112
+
113
+ ret = phy_mipi_dphy_config_validate (& opts -> mipi_dphy );
114
+ if (ret )
115
+ return ret ;
116
+
117
+ memcpy (& dphy -> config , opts , sizeof (dphy -> config ));
118
+
119
+ return 0 ;
120
+ }
121
+
122
+ static int sun6i_dphy_power_on (struct phy * phy )
123
+ {
124
+ struct sun6i_dphy * dphy = phy_get_drvdata (phy );
125
+ u8 lanes_mask = GENMASK (dphy -> config .lanes - 1 , 0 );
126
+
90
127
regmap_write (dphy -> regs , SUN6I_DPHY_TX_CTL_REG ,
91
128
SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT );
92
129
@@ -111,16 +148,9 @@ int sun6i_dphy_init(struct sun6i_dphy *dphy, unsigned int lanes)
111
148
SUN6I_DPHY_TX_TIME4_HS_TX_ANA1 (3 ));
112
149
113
150
regmap_write (dphy -> regs , SUN6I_DPHY_GCTL_REG ,
114
- SUN6I_DPHY_GCTL_LANE_NUM (lanes ) |
151
+ SUN6I_DPHY_GCTL_LANE_NUM (dphy -> config . lanes ) |
115
152
SUN6I_DPHY_GCTL_EN );
116
153
117
- return 0 ;
118
- }
119
-
120
- int sun6i_dphy_power_on (struct sun6i_dphy * dphy , unsigned int lanes )
121
- {
122
- u8 lanes_mask = GENMASK (lanes - 1 , 0 );
123
-
124
154
regmap_write (dphy -> regs , SUN6I_DPHY_ANA0_REG ,
125
155
SUN6I_DPHY_ANA0_REG_PWS |
126
156
SUN6I_DPHY_ANA0_REG_DMPC |
@@ -181,23 +211,36 @@ int sun6i_dphy_power_on(struct sun6i_dphy *dphy, unsigned int lanes)
181
211
return 0 ;
182
212
}
183
213
184
- int sun6i_dphy_power_off (struct sun6i_dphy * dphy )
214
+ static int sun6i_dphy_power_off (struct phy * phy )
185
215
{
216
+ struct sun6i_dphy * dphy = phy_get_drvdata (phy );
217
+
186
218
regmap_update_bits (dphy -> regs , SUN6I_DPHY_ANA1_REG ,
187
219
SUN6I_DPHY_ANA1_REG_VTTMODE , 0 );
188
220
189
221
return 0 ;
190
222
}
191
223
192
- int sun6i_dphy_exit (struct sun6i_dphy * dphy )
224
+ static int sun6i_dphy_exit (struct phy * phy )
193
225
{
226
+ struct sun6i_dphy * dphy = phy_get_drvdata (phy );
227
+
194
228
clk_rate_exclusive_put (dphy -> mod_clk );
195
229
clk_disable_unprepare (dphy -> mod_clk );
196
230
reset_control_assert (dphy -> reset );
197
231
198
232
return 0 ;
199
233
}
200
234
235
+
236
+ static struct phy_ops sun6i_dphy_ops = {
237
+ .configure = sun6i_dphy_configure ,
238
+ .power_on = sun6i_dphy_power_on ,
239
+ .power_off = sun6i_dphy_power_off ,
240
+ .init = sun6i_dphy_init ,
241
+ .exit = sun6i_dphy_exit ,
242
+ };
243
+
201
244
static struct regmap_config sun6i_dphy_regmap_config = {
202
245
.reg_bits = 32 ,
203
246
.val_bits = 32 ,
@@ -206,87 +249,70 @@ static struct regmap_config sun6i_dphy_regmap_config = {
206
249
.name = "mipi-dphy" ,
207
250
};
208
251
209
- static const struct of_device_id sun6i_dphy_of_table [] = {
210
- { .compatible = "allwinner,sun6i-a31-mipi-dphy" },
211
- { }
212
- };
213
-
214
- int sun6i_dphy_probe (struct sun6i_dsi * dsi , struct device_node * node )
252
+ static int sun6i_dphy_probe (struct platform_device * pdev )
215
253
{
254
+ struct phy_provider * phy_provider ;
216
255
struct sun6i_dphy * dphy ;
217
- struct resource res ;
256
+ struct resource * res ;
218
257
void __iomem * regs ;
219
- int ret ;
220
-
221
- if (!of_match_node (sun6i_dphy_of_table , node )) {
222
- dev_err (dsi -> dev , "Incompatible D-PHY\n" );
223
- return - EINVAL ;
224
- }
225
258
226
- dphy = devm_kzalloc (dsi -> dev , sizeof (* dphy ), GFP_KERNEL );
259
+ dphy = devm_kzalloc (& pdev -> dev , sizeof (* dphy ), GFP_KERNEL );
227
260
if (!dphy )
228
261
return - ENOMEM ;
229
262
230
- ret = of_address_to_resource (node , 0 , & res );
231
- if (ret ) {
232
- dev_err (dsi -> dev , "phy: Couldn't get our resources\n" );
233
- return ret ;
234
- }
235
-
236
- regs = devm_ioremap_resource (dsi -> dev , & res );
263
+ res = platform_get_resource (pdev , IORESOURCE_MEM , 0 );
264
+ regs = devm_ioremap_resource (& pdev -> dev , res );
237
265
if (IS_ERR (regs )) {
238
- dev_err (dsi -> dev , "Couldn't map the DPHY encoder registers\n" );
266
+ dev_err (& pdev -> dev , "Couldn't map the DPHY encoder registers\n" );
239
267
return PTR_ERR (regs );
240
268
}
241
269
242
- dphy -> regs = devm_regmap_init_mmio ( dsi -> dev , regs ,
243
- & sun6i_dphy_regmap_config );
270
+ dphy -> regs = devm_regmap_init_mmio_clk ( & pdev -> dev , "bus" ,
271
+ regs , & sun6i_dphy_regmap_config );
244
272
if (IS_ERR (dphy -> regs )) {
245
- dev_err (dsi -> dev , "Couldn't create the DPHY encoder regmap\n" );
273
+ dev_err (& pdev -> dev , "Couldn't create the DPHY encoder regmap\n" );
246
274
return PTR_ERR (dphy -> regs );
247
275
}
248
276
249
- dphy -> reset = of_reset_control_get_shared ( node , NULL );
277
+ dphy -> reset = devm_reset_control_get_shared ( & pdev -> dev , NULL );
250
278
if (IS_ERR (dphy -> reset )) {
251
- dev_err (dsi -> dev , "Couldn't get our reset line\n" );
279
+ dev_err (& pdev -> dev , "Couldn't get our reset line\n" );
252
280
return PTR_ERR (dphy -> reset );
253
281
}
254
282
255
- dphy -> bus_clk = of_clk_get_by_name (node , "bus" );
256
- if (IS_ERR (dphy -> bus_clk )) {
257
- dev_err (dsi -> dev , "Couldn't get the DPHY bus clock\n" );
258
- ret = PTR_ERR (dphy -> bus_clk );
259
- goto err_free_reset ;
260
- }
261
- regmap_mmio_attach_clk (dphy -> regs , dphy -> bus_clk );
262
-
263
- dphy -> mod_clk = of_clk_get_by_name (node , "mod" );
283
+ dphy -> mod_clk = devm_clk_get (& pdev -> dev , "mod" );
264
284
if (IS_ERR (dphy -> mod_clk )) {
265
- dev_err (dsi -> dev , "Couldn't get the DPHY mod clock\n" );
266
- ret = PTR_ERR (dphy -> mod_clk );
267
- goto err_free_bus ;
285
+ dev_err (& pdev -> dev , "Couldn't get the DPHY mod clock\n" );
286
+ return PTR_ERR (dphy -> mod_clk );
268
287
}
269
288
270
- dsi -> dphy = dphy ;
289
+ dphy -> phy = devm_phy_create (& pdev -> dev , NULL , & sun6i_dphy_ops );
290
+ if (IS_ERR (dphy -> phy )) {
291
+ dev_err (& pdev -> dev , "failed to create PHY\n" );
292
+ return PTR_ERR (dphy -> phy );
293
+ }
271
294
272
- return 0 ;
295
+ phy_set_drvdata (dphy -> phy , dphy );
296
+ phy_provider = devm_of_phy_provider_register (& pdev -> dev , of_phy_simple_xlate );
273
297
274
- err_free_bus :
275
- regmap_mmio_detach_clk (dphy -> regs );
276
- clk_put (dphy -> bus_clk );
277
- err_free_reset :
278
- reset_control_put (dphy -> reset );
279
- return ret ;
298
+ return PTR_ERR_OR_ZERO (phy_provider );
280
299
}
281
300
282
- int sun6i_dphy_remove (struct sun6i_dsi * dsi )
283
- {
284
- struct sun6i_dphy * dphy = dsi -> dphy ;
285
-
286
- regmap_mmio_detach_clk (dphy -> regs );
287
- clk_put (dphy -> mod_clk );
288
- clk_put (dphy -> bus_clk );
289
- reset_control_put (dphy -> reset );
301
+ static const struct of_device_id sun6i_dphy_of_table [] = {
302
+ { .compatible = "allwinner,sun6i-a31-mipi-dphy" },
303
+ { }
304
+ };
305
+ MODULE_DEVICE_TABLE (of , sun6i_dphy_of_table );
306
+
307
+ static struct platform_driver sun6i_dphy_platform_driver = {
308
+ .probe = sun6i_dphy_probe ,
309
+ .driver = {
310
+ .name = "sun6i-mipi-dphy" ,
311
+ .of_match_table = sun6i_dphy_of_table ,
312
+ },
313
+ };
314
+ module_platform_driver (sun6i_dphy_platform_driver );
290
315
291
- return 0 ;
292
- }
316
+ MODULE_AUTHOR ("Maxime Ripard <maxime.ripard@bootlin>" );
317
+ MODULE_DESCRIPTION ("Allwinner A31 MIPI D-PHY Driver" );
318
+ MODULE_LICENSE ("GPL" );
0 commit comments