1 // SPDX-License-Identifier: GPL-2.0
3 // SY8824C/SY8824E regulator driver
5 // Copyright (C) 2019 Synaptics Incorporated
7 // Author: Jisheng Zhang <jszhang@kernel.org>
9 #include <linux/module.h>
10 #include <linux/i2c.h>
12 #include <linux/regmap.h>
13 #include <linux/regulator/driver.h>
14 #include <linux/regulator/of_regulator.h>
16 #define SY8824C_BUCK_EN (1 << 7)
17 #define SY8824C_MODE (1 << 6)
19 struct sy8824_config
{
22 unsigned int mode_reg
;
23 unsigned int enable_reg
;
24 /* Voltage range and step(linear) */
25 unsigned int vsel_min
;
26 unsigned int vsel_step
;
27 unsigned int vsel_count
;
28 const struct regmap_config
*config
;
31 struct sy8824_device_info
{
33 struct regulator_desc desc
;
34 struct regulator_init_data
*regulator
;
35 const struct sy8824_config
*cfg
;
38 static int sy8824_set_mode(struct regulator_dev
*rdev
, unsigned int mode
)
40 struct sy8824_device_info
*di
= rdev_get_drvdata(rdev
);
41 const struct sy8824_config
*cfg
= di
->cfg
;
44 case REGULATOR_MODE_FAST
:
45 regmap_update_bits(rdev
->regmap
, cfg
->mode_reg
,
46 SY8824C_MODE
, SY8824C_MODE
);
48 case REGULATOR_MODE_NORMAL
:
49 regmap_update_bits(rdev
->regmap
, cfg
->mode_reg
,
58 static unsigned int sy8824_get_mode(struct regulator_dev
*rdev
)
60 struct sy8824_device_info
*di
= rdev_get_drvdata(rdev
);
61 const struct sy8824_config
*cfg
= di
->cfg
;
65 ret
= regmap_read(rdev
->regmap
, cfg
->mode_reg
, &val
);
68 if (val
& SY8824C_MODE
)
69 return REGULATOR_MODE_FAST
;
71 return REGULATOR_MODE_NORMAL
;
74 static const struct regulator_ops sy8824_regulator_ops
= {
75 .set_voltage_sel
= regulator_set_voltage_sel_regmap
,
76 .get_voltage_sel
= regulator_get_voltage_sel_regmap
,
77 .set_voltage_time_sel
= regulator_set_voltage_time_sel
,
78 .map_voltage
= regulator_map_voltage_linear
,
79 .list_voltage
= regulator_list_voltage_linear
,
80 .enable
= regulator_enable_regmap
,
81 .disable
= regulator_disable_regmap
,
82 .is_enabled
= regulator_is_enabled_regmap
,
83 .set_mode
= sy8824_set_mode
,
84 .get_mode
= sy8824_get_mode
,
87 static int sy8824_regulator_register(struct sy8824_device_info
*di
,
88 struct regulator_config
*config
)
90 struct regulator_desc
*rdesc
= &di
->desc
;
91 const struct sy8824_config
*cfg
= di
->cfg
;
92 struct regulator_dev
*rdev
;
94 rdesc
->name
= "sy8824-reg";
95 rdesc
->supply_name
= "vin";
96 rdesc
->ops
= &sy8824_regulator_ops
;
97 rdesc
->type
= REGULATOR_VOLTAGE
;
98 rdesc
->n_voltages
= cfg
->vsel_count
;
99 rdesc
->enable_reg
= cfg
->enable_reg
;
100 rdesc
->enable_mask
= SY8824C_BUCK_EN
;
101 rdesc
->min_uV
= cfg
->vsel_min
;
102 rdesc
->uV_step
= cfg
->vsel_step
;
103 rdesc
->vsel_reg
= cfg
->vol_reg
;
104 rdesc
->vsel_mask
= cfg
->vsel_count
- 1;
105 rdesc
->owner
= THIS_MODULE
;
107 rdev
= devm_regulator_register(di
->dev
, &di
->desc
, config
);
108 return PTR_ERR_OR_ZERO(rdev
);
111 static const struct regmap_config sy8824_regmap_config
= {
114 .num_reg_defaults_raw
= 1,
115 .cache_type
= REGCACHE_FLAT
,
118 static const struct regmap_config sy20276_regmap_config
= {
121 .num_reg_defaults_raw
= 2,
122 .cache_type
= REGCACHE_FLAT
,
125 static int sy8824_i2c_probe(struct i2c_client
*client
)
127 struct device
*dev
= &client
->dev
;
128 struct device_node
*np
= dev
->of_node
;
129 struct sy8824_device_info
*di
;
130 struct regulator_config config
= { };
131 struct regmap
*regmap
;
134 di
= devm_kzalloc(dev
, sizeof(struct sy8824_device_info
), GFP_KERNEL
);
138 di
->regulator
= of_get_regulator_init_data(dev
, np
, &di
->desc
);
139 if (!di
->regulator
) {
140 dev_err(dev
, "Platform data not found!\n");
145 di
->cfg
= i2c_get_match_data(client
);
147 regmap
= devm_regmap_init_i2c(client
, di
->cfg
->config
);
148 if (IS_ERR(regmap
)) {
149 dev_err(dev
, "Failed to allocate regmap!\n");
150 return PTR_ERR(regmap
);
152 i2c_set_clientdata(client
, di
);
154 config
.dev
= di
->dev
;
155 config
.init_data
= di
->regulator
;
156 config
.regmap
= regmap
;
157 config
.driver_data
= di
;
160 ret
= sy8824_regulator_register(di
, &config
);
162 dev_err(dev
, "Failed to register regulator!\n");
166 static const struct sy8824_config sy8824c_cfg
= {
173 .config
= &sy8824_regmap_config
,
176 static const struct sy8824_config sy8824e_cfg
= {
183 .config
= &sy8824_regmap_config
,
186 static const struct sy8824_config sy20276_cfg
= {
193 .config
= &sy20276_regmap_config
,
196 static const struct sy8824_config sy20278_cfg
= {
203 .config
= &sy20276_regmap_config
,
206 static const struct of_device_id sy8824_dt_ids
[] = {
207 { .compatible
= "silergy,sy8824c", .data
= &sy8824c_cfg
},
208 { .compatible
= "silergy,sy8824e", .data
= &sy8824e_cfg
},
209 { .compatible
= "silergy,sy20276", .data
= &sy20276_cfg
},
210 { .compatible
= "silergy,sy20278", .data
= &sy20278_cfg
},
213 MODULE_DEVICE_TABLE(of
, sy8824_dt_ids
);
215 static const struct i2c_device_id sy8824_id
[] = {
216 { "sy8824", (kernel_ulong_t
)&sy8824c_cfg
},
219 MODULE_DEVICE_TABLE(i2c
, sy8824_id
);
221 static struct i2c_driver sy8824_regulator_driver
= {
223 .name
= "sy8824-regulator",
224 .probe_type
= PROBE_PREFER_ASYNCHRONOUS
,
225 .of_match_table
= sy8824_dt_ids
,
227 .probe
= sy8824_i2c_probe
,
228 .id_table
= sy8824_id
,
230 module_i2c_driver(sy8824_regulator_driver
);
232 MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
233 MODULE_DESCRIPTION("SY8824C/SY8824E regulator driver");
234 MODULE_LICENSE("GPL v2");