1 // SPDX-License-Identifier: GPL-2.0+
3 // sy8106a-regulator.c - Regulator device driver for SY8106A
5 // Copyright (C) 2016 Ondřej Jirman <megous@megous.com>
6 // Copyright (c) 2017-2018 Icenowy Zheng <icenowy@aosc.io>
10 #include <linux/module.h>
11 #include <linux/regmap.h>
12 #include <linux/regulator/driver.h>
13 #include <linux/regulator/of_regulator.h>
15 #define SY8106A_REG_VOUT1_SEL 0x01
16 #define SY8106A_REG_VOUT_COM 0x02
17 #define SY8106A_REG_VOUT1_SEL_MASK 0x7f
18 #define SY8106A_DISABLE_REG BIT(0)
20 * The I2C controlled voltage will only work when this bit is set; otherwise
21 * it will behave like a fixed regulator.
23 #define SY8106A_GO_BIT BIT(7)
25 static const struct regmap_config sy8106a_regmap_config
= {
30 static const struct regulator_ops sy8106a_ops
= {
31 .set_voltage_sel
= regulator_set_voltage_sel_regmap
,
32 .set_voltage_time_sel
= regulator_set_voltage_time_sel
,
33 .get_voltage_sel
= regulator_get_voltage_sel_regmap
,
34 .list_voltage
= regulator_list_voltage_linear
,
35 /* Enabling/disabling the regulator is not yet implemented */
38 /* Default limits measured in millivolts */
39 #define SY8106A_MIN_MV 680
40 #define SY8106A_MAX_MV 1950
41 #define SY8106A_STEP_MV 10
43 static const struct regulator_desc sy8106a_reg
= {
47 .type
= REGULATOR_VOLTAGE
,
48 .n_voltages
= ((SY8106A_MAX_MV
- SY8106A_MIN_MV
) / SY8106A_STEP_MV
) + 1,
49 .min_uV
= (SY8106A_MIN_MV
* 1000),
50 .uV_step
= (SY8106A_STEP_MV
* 1000),
51 .vsel_reg
= SY8106A_REG_VOUT1_SEL
,
52 .vsel_mask
= SY8106A_REG_VOUT1_SEL_MASK
,
54 * This ramp_delay is a conservative default value which works on
55 * H3/H5 boards VDD-CPUX situations.
62 * I2C driver interface functions
64 static int sy8106a_i2c_probe(struct i2c_client
*i2c
)
66 struct device
*dev
= &i2c
->dev
;
67 struct regulator_dev
*rdev
;
68 struct regulator_config config
= { };
69 struct regmap
*regmap
;
70 unsigned int reg
, vsel
;
74 error
= of_property_read_u32(dev
->of_node
, "silergy,fixed-microvolt",
79 if (fixed_voltage
< SY8106A_MIN_MV
* 1000 ||
80 fixed_voltage
> SY8106A_MAX_MV
* 1000)
83 regmap
= devm_regmap_init_i2c(i2c
, &sy8106a_regmap_config
);
85 error
= PTR_ERR(regmap
);
86 dev_err(dev
, "Failed to allocate register map: %d\n", error
);
90 config
.dev
= &i2c
->dev
;
91 config
.regmap
= regmap
;
93 config
.of_node
= dev
->of_node
;
94 config
.init_data
= of_get_regulator_init_data(dev
, dev
->of_node
,
97 if (!config
.init_data
)
100 /* Ensure GO_BIT is enabled when probing */
101 error
= regmap_read(regmap
, SY8106A_REG_VOUT1_SEL
, ®
);
105 if (!(reg
& SY8106A_GO_BIT
)) {
106 vsel
= (fixed_voltage
/ 1000 - SY8106A_MIN_MV
) /
109 error
= regmap_write(regmap
, SY8106A_REG_VOUT1_SEL
,
110 vsel
| SY8106A_GO_BIT
);
115 /* Probe regulator */
116 rdev
= devm_regulator_register(&i2c
->dev
, &sy8106a_reg
, &config
);
118 error
= PTR_ERR(rdev
);
119 dev_err(&i2c
->dev
, "Failed to register SY8106A regulator: %d\n", error
);
126 static const struct of_device_id sy8106a_i2c_of_match
[] = {
127 { .compatible
= "silergy,sy8106a" },
130 MODULE_DEVICE_TABLE(of
, sy8106a_i2c_of_match
);
132 static const struct i2c_device_id sy8106a_i2c_id
[] = {
136 MODULE_DEVICE_TABLE(i2c
, sy8106a_i2c_id
);
138 static struct i2c_driver sy8106a_regulator_driver
= {
141 .of_match_table
= of_match_ptr(sy8106a_i2c_of_match
),
143 .probe_new
= sy8106a_i2c_probe
,
144 .id_table
= sy8106a_i2c_id
,
147 module_i2c_driver(sy8106a_regulator_driver
);
149 MODULE_AUTHOR("Ondřej Jirman <megous@megous.com>");
150 MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
151 MODULE_DESCRIPTION("Regulator device driver for Silergy SY8106A");
152 MODULE_LICENSE("GPL");