0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/err.h>
0009 #include <linux/i2c.h>
0010 #include <linux/module.h>
0011 #include <linux/regmap.h>
0012 #include <linux/regulator/driver.h>
0013 #include <linux/regulator/of_regulator.h>
0014
0015 #define SY8106A_REG_VOUT1_SEL 0x01
0016 #define SY8106A_REG_VOUT_COM 0x02
0017 #define SY8106A_REG_VOUT1_SEL_MASK 0x7f
0018 #define SY8106A_DISABLE_REG BIT(0)
0019
0020
0021
0022
0023 #define SY8106A_GO_BIT BIT(7)
0024
0025 static const struct regmap_config sy8106a_regmap_config = {
0026 .reg_bits = 8,
0027 .val_bits = 8,
0028 };
0029
0030 static const struct regulator_ops sy8106a_ops = {
0031 .set_voltage_sel = regulator_set_voltage_sel_regmap,
0032 .set_voltage_time_sel = regulator_set_voltage_time_sel,
0033 .get_voltage_sel = regulator_get_voltage_sel_regmap,
0034 .list_voltage = regulator_list_voltage_linear,
0035
0036 };
0037
0038
0039 #define SY8106A_MIN_MV 680
0040 #define SY8106A_MAX_MV 1950
0041 #define SY8106A_STEP_MV 10
0042
0043 static const struct regulator_desc sy8106a_reg = {
0044 .name = "SY8106A",
0045 .id = 0,
0046 .ops = &sy8106a_ops,
0047 .type = REGULATOR_VOLTAGE,
0048 .n_voltages = ((SY8106A_MAX_MV - SY8106A_MIN_MV) / SY8106A_STEP_MV) + 1,
0049 .min_uV = (SY8106A_MIN_MV * 1000),
0050 .uV_step = (SY8106A_STEP_MV * 1000),
0051 .vsel_reg = SY8106A_REG_VOUT1_SEL,
0052 .vsel_mask = SY8106A_REG_VOUT1_SEL_MASK,
0053
0054
0055
0056
0057 .ramp_delay = 200,
0058 .owner = THIS_MODULE,
0059 };
0060
0061
0062
0063
0064 static int sy8106a_i2c_probe(struct i2c_client *i2c)
0065 {
0066 struct device *dev = &i2c->dev;
0067 struct regulator_dev *rdev;
0068 struct regulator_config config = { };
0069 struct regmap *regmap;
0070 unsigned int reg, vsel;
0071 u32 fixed_voltage;
0072 int error;
0073
0074 error = of_property_read_u32(dev->of_node, "silergy,fixed-microvolt",
0075 &fixed_voltage);
0076 if (error)
0077 return error;
0078
0079 if (fixed_voltage < SY8106A_MIN_MV * 1000 ||
0080 fixed_voltage > SY8106A_MAX_MV * 1000)
0081 return -EINVAL;
0082
0083 regmap = devm_regmap_init_i2c(i2c, &sy8106a_regmap_config);
0084 if (IS_ERR(regmap)) {
0085 error = PTR_ERR(regmap);
0086 dev_err(dev, "Failed to allocate register map: %d\n", error);
0087 return error;
0088 }
0089
0090 config.dev = &i2c->dev;
0091 config.regmap = regmap;
0092
0093 config.of_node = dev->of_node;
0094 config.init_data = of_get_regulator_init_data(dev, dev->of_node,
0095 &sy8106a_reg);
0096
0097 if (!config.init_data)
0098 return -ENOMEM;
0099
0100
0101 error = regmap_read(regmap, SY8106A_REG_VOUT1_SEL, ®);
0102 if (error)
0103 return error;
0104
0105 if (!(reg & SY8106A_GO_BIT)) {
0106 vsel = (fixed_voltage / 1000 - SY8106A_MIN_MV) /
0107 SY8106A_STEP_MV;
0108
0109 error = regmap_write(regmap, SY8106A_REG_VOUT1_SEL,
0110 vsel | SY8106A_GO_BIT);
0111 if (error)
0112 return error;
0113 }
0114
0115
0116 rdev = devm_regulator_register(&i2c->dev, &sy8106a_reg, &config);
0117 if (IS_ERR(rdev)) {
0118 error = PTR_ERR(rdev);
0119 dev_err(&i2c->dev, "Failed to register SY8106A regulator: %d\n", error);
0120 return error;
0121 }
0122
0123 return 0;
0124 }
0125
0126 static const struct of_device_id __maybe_unused sy8106a_i2c_of_match[] = {
0127 { .compatible = "silergy,sy8106a" },
0128 { },
0129 };
0130 MODULE_DEVICE_TABLE(of, sy8106a_i2c_of_match);
0131
0132 static const struct i2c_device_id sy8106a_i2c_id[] = {
0133 { "sy8106a", 0 },
0134 { },
0135 };
0136 MODULE_DEVICE_TABLE(i2c, sy8106a_i2c_id);
0137
0138 static struct i2c_driver sy8106a_regulator_driver = {
0139 .driver = {
0140 .name = "sy8106a",
0141 .of_match_table = of_match_ptr(sy8106a_i2c_of_match),
0142 },
0143 .probe_new = sy8106a_i2c_probe,
0144 .id_table = sy8106a_i2c_id,
0145 };
0146
0147 module_i2c_driver(sy8106a_regulator_driver);
0148
0149 MODULE_AUTHOR("Ondřej Jirman <megous@megous.com>");
0150 MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
0151 MODULE_DESCRIPTION("Regulator device driver for Silergy SY8106A");
0152 MODULE_LICENSE("GPL");