1 // SPDX-License-Identifier: GPL-2.0
3 // Regulator controller driver for UniPhier SoC
4 // Copyright 2018 Socionext Inc.
5 // Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
9 #include <linux/module.h>
10 #include <linux/of_device.h>
11 #include <linux/platform_device.h>
12 #include <linux/regmap.h>
13 #include <linux/regulator/driver.h>
14 #include <linux/regulator/of_regulator.h>
15 #include <linux/reset.h>
20 struct uniphier_regulator_soc_data
{
22 const char * const *clock_names
;
24 const char * const *reset_names
;
25 const struct regulator_desc
*desc
;
26 const struct regmap_config
*regconf
;
29 struct uniphier_regulator_priv
{
30 struct clk_bulk_data clk
[MAX_CLKS
];
31 struct reset_control
*rst
[MAX_RSTS
];
32 const struct uniphier_regulator_soc_data
*data
;
35 static const struct regulator_ops uniphier_regulator_ops
= {
36 .enable
= regulator_enable_regmap
,
37 .disable
= regulator_disable_regmap
,
38 .is_enabled
= regulator_is_enabled_regmap
,
41 static int uniphier_regulator_probe(struct platform_device
*pdev
)
43 struct device
*dev
= &pdev
->dev
;
44 struct uniphier_regulator_priv
*priv
;
45 struct regulator_config config
= { };
46 struct regulator_dev
*rdev
;
47 struct regmap
*regmap
;
52 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
56 priv
->data
= of_device_get_match_data(dev
);
57 if (WARN_ON(!priv
->data
))
60 base
= devm_platform_ioremap_resource(pdev
, 0);
64 for (i
= 0; i
< priv
->data
->nclks
; i
++)
65 priv
->clk
[i
].id
= priv
->data
->clock_names
[i
];
66 ret
= devm_clk_bulk_get(dev
, priv
->data
->nclks
, priv
->clk
);
70 for (i
= 0; i
< priv
->data
->nrsts
; i
++) {
71 name
= priv
->data
->reset_names
[i
];
72 priv
->rst
[i
] = devm_reset_control_get_shared(dev
, name
);
73 if (IS_ERR(priv
->rst
[i
]))
74 return PTR_ERR(priv
->rst
[i
]);
77 ret
= clk_bulk_prepare_enable(priv
->data
->nclks
, priv
->clk
);
81 for (nr
= 0; nr
< priv
->data
->nrsts
; nr
++) {
82 ret
= reset_control_deassert(priv
->rst
[nr
]);
87 regmap
= devm_regmap_init_mmio(dev
, base
, priv
->data
->regconf
);
89 ret
= PTR_ERR(regmap
);
94 config
.driver_data
= priv
;
95 config
.of_node
= dev
->of_node
;
96 config
.regmap
= regmap
;
97 config
.init_data
= of_get_regulator_init_data(dev
, dev
->of_node
,
99 rdev
= devm_regulator_register(dev
, priv
->data
->desc
, &config
);
105 platform_set_drvdata(pdev
, priv
);
111 reset_control_assert(priv
->rst
[nr
]);
113 clk_bulk_disable_unprepare(priv
->data
->nclks
, priv
->clk
);
118 static int uniphier_regulator_remove(struct platform_device
*pdev
)
120 struct uniphier_regulator_priv
*priv
= platform_get_drvdata(pdev
);
123 for (i
= 0; i
< priv
->data
->nrsts
; i
++)
124 reset_control_assert(priv
->rst
[i
]);
126 clk_bulk_disable_unprepare(priv
->data
->nclks
, priv
->clk
);
131 /* USB3 controller data */
132 #define USB3VBUS_OFFSET 0x0
133 #define USB3VBUS_REG BIT(4)
134 #define USB3VBUS_REG_EN BIT(3)
135 static const struct regulator_desc uniphier_usb3_regulator_desc
= {
137 .of_match
= of_match_ptr("vbus"),
138 .ops
= &uniphier_regulator_ops
,
139 .type
= REGULATOR_VOLTAGE
,
140 .owner
= THIS_MODULE
,
141 .enable_reg
= USB3VBUS_OFFSET
,
142 .enable_mask
= USB3VBUS_REG_EN
| USB3VBUS_REG
,
143 .enable_val
= USB3VBUS_REG_EN
| USB3VBUS_REG
,
144 .disable_val
= USB3VBUS_REG_EN
,
147 static const struct regmap_config uniphier_usb3_regulator_regconf
= {
154 static const char * const uniphier_pro4_clock_reset_names
[] = {
158 static const struct uniphier_regulator_soc_data uniphier_pro4_usb3_data
= {
159 .nclks
= ARRAY_SIZE(uniphier_pro4_clock_reset_names
),
160 .clock_names
= uniphier_pro4_clock_reset_names
,
161 .nrsts
= ARRAY_SIZE(uniphier_pro4_clock_reset_names
),
162 .reset_names
= uniphier_pro4_clock_reset_names
,
163 .desc
= &uniphier_usb3_regulator_desc
,
164 .regconf
= &uniphier_usb3_regulator_regconf
,
167 static const char * const uniphier_pxs2_clock_reset_names
[] = {
171 static const struct uniphier_regulator_soc_data uniphier_pxs2_usb3_data
= {
172 .nclks
= ARRAY_SIZE(uniphier_pxs2_clock_reset_names
),
173 .clock_names
= uniphier_pxs2_clock_reset_names
,
174 .nrsts
= ARRAY_SIZE(uniphier_pxs2_clock_reset_names
),
175 .reset_names
= uniphier_pxs2_clock_reset_names
,
176 .desc
= &uniphier_usb3_regulator_desc
,
177 .regconf
= &uniphier_usb3_regulator_regconf
,
180 static const struct of_device_id uniphier_regulator_match
[] = {
183 .compatible
= "socionext,uniphier-pro4-usb3-regulator",
184 .data
= &uniphier_pro4_usb3_data
,
187 .compatible
= "socionext,uniphier-pro5-usb3-regulator",
188 .data
= &uniphier_pro4_usb3_data
,
191 .compatible
= "socionext,uniphier-pxs2-usb3-regulator",
192 .data
= &uniphier_pxs2_usb3_data
,
195 .compatible
= "socionext,uniphier-ld20-usb3-regulator",
196 .data
= &uniphier_pxs2_usb3_data
,
199 .compatible
= "socionext,uniphier-pxs3-usb3-regulator",
200 .data
= &uniphier_pxs2_usb3_data
,
205 static struct platform_driver uniphier_regulator_driver
= {
206 .probe
= uniphier_regulator_probe
,
207 .remove
= uniphier_regulator_remove
,
209 .name
= "uniphier-regulator",
210 .of_match_table
= uniphier_regulator_match
,
213 module_platform_driver(uniphier_regulator_driver
);
215 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
216 MODULE_DESCRIPTION("UniPhier Regulator Controller Driver");
217 MODULE_LICENSE("GPL");