Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 //
0003 // sy8106a-regulator.c - Regulator device driver for SY8106A
0004 //
0005 // Copyright (C) 2016 Ondřej Jirman <megous@megous.com>
0006 // Copyright (c) 2017-2018 Icenowy Zheng <icenowy@aosc.io>
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  * The I2C controlled voltage will only work when this bit is set; otherwise
0021  * it will behave like a fixed regulator.
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     /* Enabling/disabling the regulator is not yet implemented */
0036 };
0037 
0038 /* Default limits measured in millivolts */
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      * This ramp_delay is a conservative default value which works on
0055      * H3/H5 boards VDD-CPUX situations.
0056      */
0057     .ramp_delay = 200,
0058     .owner = THIS_MODULE,
0059 };
0060 
0061 /*
0062  * I2C driver interface functions
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     /* Ensure GO_BIT is enabled when probing */
0101     error = regmap_read(regmap, SY8106A_REG_VOUT1_SEL, &reg);
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     /* Probe regulator */
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");