1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2020-2022 Bootlin
4  * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
5  */
6 
7 #include <linux/phy/phy.h>
8 #include <linux/regmap.h>
9 
10 #include "sun8i_a83t_dphy.h"
11 #include "sun8i_a83t_mipi_csi2.h"
12 
sun8i_a83t_dphy_configure(struct phy * dphy,union phy_configure_opts * opts)13 static int sun8i_a83t_dphy_configure(struct phy *dphy,
14 				     union phy_configure_opts *opts)
15 {
16 	return phy_mipi_dphy_config_validate(&opts->mipi_dphy);
17 }
18 
sun8i_a83t_dphy_power_on(struct phy * dphy)19 static int sun8i_a83t_dphy_power_on(struct phy *dphy)
20 {
21 	struct sun8i_a83t_mipi_csi2_device *csi2_dev = phy_get_drvdata(dphy);
22 	struct regmap *regmap = csi2_dev->regmap;
23 
24 	regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG,
25 		     SUN8I_A83T_DPHY_CTRL_RESET_N |
26 		     SUN8I_A83T_DPHY_CTRL_SHUTDOWN_N);
27 
28 	regmap_write(regmap, SUN8I_A83T_DPHY_ANA0_REG,
29 		     SUN8I_A83T_DPHY_ANA0_REXT_EN |
30 		     SUN8I_A83T_DPHY_ANA0_RINT(2) |
31 		     SUN8I_A83T_DPHY_ANA0_SNK(2));
32 
33 	return 0;
34 };
35 
sun8i_a83t_dphy_power_off(struct phy * dphy)36 static int sun8i_a83t_dphy_power_off(struct phy *dphy)
37 {
38 	struct sun8i_a83t_mipi_csi2_device *csi2_dev = phy_get_drvdata(dphy);
39 	struct regmap *regmap = csi2_dev->regmap;
40 
41 	regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG, 0);
42 
43 	return 0;
44 };
45 
46 static const struct phy_ops sun8i_a83t_dphy_ops = {
47 	.configure	= sun8i_a83t_dphy_configure,
48 	.power_on	= sun8i_a83t_dphy_power_on,
49 	.power_off	= sun8i_a83t_dphy_power_off,
50 };
51 
sun8i_a83t_dphy_register(struct sun8i_a83t_mipi_csi2_device * csi2_dev)52 int sun8i_a83t_dphy_register(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
53 {
54 	struct device *dev = csi2_dev->dev;
55 	struct phy_provider *phy_provider;
56 
57 	csi2_dev->dphy = devm_phy_create(dev, NULL, &sun8i_a83t_dphy_ops);
58 	if (IS_ERR(csi2_dev->dphy)) {
59 		dev_err(dev, "failed to create D-PHY\n");
60 		return PTR_ERR(csi2_dev->dphy);
61 	}
62 
63 	phy_set_drvdata(csi2_dev->dphy, csi2_dev);
64 
65 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
66 	if (IS_ERR(phy_provider)) {
67 		dev_err(dev, "failed to register D-PHY provider\n");
68 		return PTR_ERR(phy_provider);
69 	}
70 
71 	return 0;
72 }
73