1 // SPDX-License-Identifier: GPL-2.0
3 // AWINIC AW37503 Regulator Driver
5 // Copyright (C) 2023 awinic. All Rights Reserved
7 // Author: <like@awinic.com>
10 #include <linux/gpio/consumer.h>
11 #include <linux/i2c.h>
12 #include <linux/module.h>
13 #include <linux/regmap.h>
14 #include <linux/regulator/driver.h>
15 #include <linux/regulator/machine.h>
17 #define AW37503_REG_VPOS 0x00
18 #define AW37503_REG_VNEG 0x01
19 #define AW37503_REG_APPS 0x03
20 #define AW37503_REG_CONTROL 0x04
21 #define AW37503_REG_WPRTEN 0x21
23 #define AW37503_VOUT_MASK 0x1F
24 #define AW37503_VOUT_N_VOLTAGE 0x15
25 #define AW37503_VOUT_VMIN 4000000
26 #define AW37503_VOUT_VMAX 6000000
27 #define AW37503_VOUT_STEP 100000
29 #define AW37503_REG_APPS_DIS_VPOS BIT(1)
30 #define AW37503_REG_APPS_DIS_VNEG BIT(0)
32 #define AW37503_REGULATOR_ID_VPOS 0
33 #define AW37503_REGULATOR_ID_VNEG 1
34 #define AW37503_MAX_REGULATORS 2
36 struct aw37503_reg_pdata
{
37 struct gpio_desc
*en_gpiod
;
41 struct aw37503_regulator
{
43 struct aw37503_reg_pdata reg_pdata
[AW37503_MAX_REGULATORS
];
46 static int aw37503_regulator_enable(struct regulator_dev
*rdev
)
48 struct aw37503_regulator
*chip
= rdev_get_drvdata(rdev
);
49 int id
= rdev_get_id(rdev
);
50 struct aw37503_reg_pdata
*rpdata
= &chip
->reg_pdata
[id
];
53 if (!IS_ERR(rpdata
->en_gpiod
)) {
54 gpiod_set_value_cansleep(rpdata
->en_gpiod
, 1);
55 rpdata
->ena_gpio_state
= 1;
58 /* Hardware automatically enable discharge bit in enable */
59 if (rdev
->constraints
->active_discharge
==
60 REGULATOR_ACTIVE_DISCHARGE_DISABLE
) {
61 ret
= regulator_set_active_discharge_regmap(rdev
, false);
63 dev_err(chip
->dev
, "Failed to disable active discharge: %d\n",
72 static int aw37503_regulator_disable(struct regulator_dev
*rdev
)
74 struct aw37503_regulator
*chip
= rdev_get_drvdata(rdev
);
75 int id
= rdev_get_id(rdev
);
76 struct aw37503_reg_pdata
*rpdata
= &chip
->reg_pdata
[id
];
78 if (!IS_ERR(rpdata
->en_gpiod
)) {
79 gpiod_set_value_cansleep(rpdata
->en_gpiod
, 0);
80 rpdata
->ena_gpio_state
= 0;
86 static int aw37503_regulator_is_enabled(struct regulator_dev
*rdev
)
88 struct aw37503_regulator
*chip
= rdev_get_drvdata(rdev
);
89 int id
= rdev_get_id(rdev
);
90 struct aw37503_reg_pdata
*rpdata
= &chip
->reg_pdata
[id
];
92 if (!IS_ERR(rpdata
->en_gpiod
))
93 return rpdata
->ena_gpio_state
;
98 static const struct regulator_ops aw37503_regulator_ops
= {
99 .enable
= aw37503_regulator_enable
,
100 .disable
= aw37503_regulator_disable
,
101 .is_enabled
= aw37503_regulator_is_enabled
,
102 .list_voltage
= regulator_list_voltage_linear
,
103 .map_voltage
= regulator_map_voltage_linear
,
104 .get_voltage_sel
= regulator_get_voltage_sel_regmap
,
105 .set_voltage_sel
= regulator_set_voltage_sel_regmap
,
106 .set_active_discharge
= regulator_set_active_discharge_regmap
,
109 static int aw37503_of_parse_cb(struct device_node
*np
,
110 const struct regulator_desc
*desc
,
111 struct regulator_config
*config
)
113 struct aw37503_regulator
*chip
= config
->driver_data
;
114 struct aw37503_reg_pdata
*rpdata
= &chip
->reg_pdata
[desc
->id
];
117 rpdata
->en_gpiod
= devm_fwnode_gpiod_get(chip
->dev
, of_fwnode_handle(np
),
118 "enable", GPIOD_OUT_LOW
,
121 if (IS_ERR(rpdata
->en_gpiod
)) {
122 ret
= PTR_ERR(rpdata
->en_gpiod
);
124 /* Ignore the error other than probe defer */
125 if (ret
== -EPROBE_DEFER
)
133 #define AW37503_REGULATOR_DESC(_id, _name) \
134 [AW37503_REGULATOR_ID_##_id] = { \
135 .name = "aw37503-"#_name, \
136 .supply_name = "vin", \
137 .id = AW37503_REGULATOR_ID_##_id, \
138 .of_match = of_match_ptr(#_name), \
139 .of_parse_cb = aw37503_of_parse_cb, \
140 .ops = &aw37503_regulator_ops, \
141 .n_voltages = AW37503_VOUT_N_VOLTAGE, \
142 .min_uV = AW37503_VOUT_VMIN, \
143 .uV_step = AW37503_VOUT_STEP, \
144 .enable_time = 500, \
145 .vsel_mask = AW37503_VOUT_MASK, \
146 .vsel_reg = AW37503_REG_##_id, \
147 .active_discharge_off = 0, \
148 .active_discharge_on = AW37503_REG_APPS_DIS_##_id, \
149 .active_discharge_mask = AW37503_REG_APPS_DIS_##_id, \
150 .active_discharge_reg = AW37503_REG_APPS, \
151 .type = REGULATOR_VOLTAGE, \
152 .owner = THIS_MODULE, \
155 static const struct regulator_desc aw_regs_desc
[AW37503_MAX_REGULATORS
] = {
156 AW37503_REGULATOR_DESC(VPOS
, outp
),
157 AW37503_REGULATOR_DESC(VNEG
, outn
),
160 static const struct regmap_range aw37503_no_reg_ranges
[] = {
161 regmap_reg_range(AW37503_REG_CONTROL
+ 1,
162 AW37503_REG_WPRTEN
- 1),
165 static const struct regmap_access_table aw37503_no_reg_table
= {
166 .no_ranges
= aw37503_no_reg_ranges
,
167 .n_no_ranges
= ARRAY_SIZE(aw37503_no_reg_ranges
),
170 static const struct regmap_config aw37503_regmap_config
= {
173 .max_register
= AW37503_REG_WPRTEN
,
174 .rd_table
= &aw37503_no_reg_table
,
175 .wr_table
= &aw37503_no_reg_table
,
178 static int aw37503_probe(struct i2c_client
*client
)
180 struct device
*dev
= &client
->dev
;
181 struct aw37503_regulator
*chip
;
182 struct regulator_dev
*rdev
;
183 struct regmap
*regmap
;
184 struct regulator_config config
= { };
187 chip
= devm_kzalloc(dev
, sizeof(*chip
), GFP_KERNEL
);
191 regmap
= devm_regmap_init_i2c(client
, &aw37503_regmap_config
);
193 return dev_err_probe(dev
, PTR_ERR(regmap
),
194 "Failed to init regmap\n");
196 i2c_set_clientdata(client
, chip
);
199 config
.regmap
= regmap
;
201 config
.driver_data
= chip
;
203 for (id
= 0; id
< AW37503_MAX_REGULATORS
; ++id
) {
204 rdev
= devm_regulator_register(dev
, &aw_regs_desc
[id
],
207 return dev_err_probe(dev
, PTR_ERR(rdev
),
208 "Failed to register regulator %s\n",
209 aw_regs_desc
[id
].name
);
214 static const struct i2c_device_id aw37503_id
[] = {
215 {.name
= "aw37503",},
218 MODULE_DEVICE_TABLE(i2c
, aw37503_id
);
220 static const struct of_device_id aw37503_of_match
[] = {
221 {.compatible
= "awinic,aw37503",},
225 MODULE_DEVICE_TABLE(of
, aw37503_of_match
);
227 static struct i2c_driver aw37503_i2c_driver
= {
230 .of_match_table
= aw37503_of_match
,
232 .probe
= aw37503_probe
,
233 .id_table
= aw37503_id
,
236 module_i2c_driver(aw37503_i2c_driver
);
238 MODULE_DESCRIPTION("aw37503 regulator driver");
239 MODULE_AUTHOR("Alec Li <like@awinic.com>");
240 MODULE_LICENSE("GPL");