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
;
53 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
57 priv
->data
= of_device_get_match_data(dev
);
58 if (WARN_ON(!priv
->data
))
61 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
62 base
= devm_ioremap_resource(dev
, res
);
66 for (i
= 0; i
< priv
->data
->nclks
; i
++)
67 priv
->clk
[i
].id
= priv
->data
->clock_names
[i
];
68 ret
= devm_clk_bulk_get(dev
, priv
->data
->nclks
, priv
->clk
);
72 for (i
= 0; i
< priv
->data
->nrsts
; i
++) {
73 name
= priv
->data
->reset_names
[i
];
74 priv
->rst
[i
] = devm_reset_control_get_shared(dev
, name
);
75 if (IS_ERR(priv
->rst
[i
]))
76 return PTR_ERR(priv
->rst
[i
]);
79 ret
= clk_bulk_prepare_enable(priv
->data
->nclks
, priv
->clk
);
83 for (nr
= 0; nr
< priv
->data
->nrsts
; nr
++) {
84 ret
= reset_control_deassert(priv
->rst
[nr
]);
89 regmap
= devm_regmap_init_mmio(dev
, base
, priv
->data
->regconf
);
91 ret
= PTR_ERR(regmap
);
96 config
.driver_data
= priv
;
97 config
.of_node
= dev
->of_node
;
98 config
.regmap
= regmap
;
99 config
.init_data
= of_get_regulator_init_data(dev
, dev
->of_node
,
101 rdev
= devm_regulator_register(dev
, priv
->data
->desc
, &config
);
107 platform_set_drvdata(pdev
, priv
);
113 reset_control_assert(priv
->rst
[nr
]);
115 clk_bulk_disable_unprepare(priv
->data
->nclks
, priv
->clk
);
120 static int uniphier_regulator_remove(struct platform_device
*pdev
)
122 struct uniphier_regulator_priv
*priv
= platform_get_drvdata(pdev
);
125 for (i
= 0; i
< priv
->data
->nrsts
; i
++)
126 reset_control_assert(priv
->rst
[i
]);
128 clk_bulk_disable_unprepare(priv
->data
->nclks
, priv
->clk
);
133 /* USB3 controller data */
134 #define USB3VBUS_OFFSET 0x0
135 #define USB3VBUS_REG BIT(4)
136 #define USB3VBUS_REG_EN BIT(3)
137 static const struct regulator_desc uniphier_usb3_regulator_desc
= {
139 .of_match
= of_match_ptr("vbus"),
140 .ops
= &uniphier_regulator_ops
,
141 .type
= REGULATOR_VOLTAGE
,
142 .owner
= THIS_MODULE
,
143 .enable_reg
= USB3VBUS_OFFSET
,
144 .enable_mask
= USB3VBUS_REG_EN
| USB3VBUS_REG
,
145 .enable_val
= USB3VBUS_REG_EN
| USB3VBUS_REG
,
146 .disable_val
= USB3VBUS_REG_EN
,
149 static const struct regmap_config uniphier_usb3_regulator_regconf
= {
156 static const char * const uniphier_pro4_clock_reset_names
[] = {
160 static const struct uniphier_regulator_soc_data uniphier_pro4_usb3_data
= {
161 .nclks
= ARRAY_SIZE(uniphier_pro4_clock_reset_names
),
162 .clock_names
= uniphier_pro4_clock_reset_names
,
163 .nrsts
= ARRAY_SIZE(uniphier_pro4_clock_reset_names
),
164 .reset_names
= uniphier_pro4_clock_reset_names
,
165 .desc
= &uniphier_usb3_regulator_desc
,
166 .regconf
= &uniphier_usb3_regulator_regconf
,
169 static const char * const uniphier_pxs2_clock_reset_names
[] = {
173 static const struct uniphier_regulator_soc_data uniphier_pxs2_usb3_data
= {
174 .nclks
= ARRAY_SIZE(uniphier_pxs2_clock_reset_names
),
175 .clock_names
= uniphier_pxs2_clock_reset_names
,
176 .nrsts
= ARRAY_SIZE(uniphier_pxs2_clock_reset_names
),
177 .reset_names
= uniphier_pxs2_clock_reset_names
,
178 .desc
= &uniphier_usb3_regulator_desc
,
179 .regconf
= &uniphier_usb3_regulator_regconf
,
182 static const struct of_device_id uniphier_regulator_match
[] = {
185 .compatible
= "socionext,uniphier-pro4-usb3-regulator",
186 .data
= &uniphier_pro4_usb3_data
,
189 .compatible
= "socionext,uniphier-pxs2-usb3-regulator",
190 .data
= &uniphier_pxs2_usb3_data
,
193 .compatible
= "socionext,uniphier-ld20-usb3-regulator",
194 .data
= &uniphier_pxs2_usb3_data
,
197 .compatible
= "socionext,uniphier-pxs3-usb3-regulator",
198 .data
= &uniphier_pxs2_usb3_data
,
203 static struct platform_driver uniphier_regulator_driver
= {
204 .probe
= uniphier_regulator_probe
,
205 .remove
= uniphier_regulator_remove
,
207 .name
= "uniphier-regulator",
208 .of_match_table
= uniphier_regulator_match
,
211 module_platform_driver(uniphier_regulator_driver
);
213 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
214 MODULE_DESCRIPTION("UniPhier Regulator Controller Driver");
215 MODULE_LICENSE("GPL");