Loading Documentation/devicetree/bindings/regulator/fan53555.txt +2 −2 Original line number Diff line number Diff line Binding for Fairchild FAN53555 regulators Required properties: - compatible: one of "fcs,fan53555", "silergy,syr827", "silergy,syr828" or "halo,hl7509" - compatible: one of "fcs,fan53555", "silergy,syr827", "silergy,syr828", "halo,hl7509" or "halo,hl7503" - reg: I2C address Optional properties: Loading drivers/regulator/fan53555.c +181 −12 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ * published by the Free Software Foundation. * */ #include <linux/debugfs.h> #include <linux/module.h> #include <linux/param.h> #include <linux/err.h> Loading @@ -20,6 +21,7 @@ #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> #include <linux/of_device.h> #include <linux/of_gpio.h> #include <linux/i2c.h> #include <linux/slab.h> #include <linux/regmap.h> Loading @@ -40,7 +42,10 @@ /* VSEL bit definitions */ #define VSEL_BUCK_EN (1 << 7) #define VSEL_MODE (1 << 6) #define HL7503_VSEL0_MODE BIT(0) #define HL7503_VSEL1_MODE BIT(1) #define VSEL_NSEL_MASK 0x3F #define HL7503_VSEL_NSEL_MASK 0x7F /* Chip ID and Verison */ #define DIE_ID 0x0F /* ID1 */ #define DIE_REV 0x0F /* ID2 */ Loading @@ -51,11 +56,13 @@ #define CTL_RESET (1 << 2) #define FAN53555_NVOLTAGES 64 /* Numbers of voltages */ #define HL7503_NVOLTAGES 128 enum fan53555_vendor { FAN53555_VENDOR_FAIRCHILD = 0, FAN53555_VENDOR_SILERGY, HALO_HL7509, HALO_HL7503, }; /* IC Type */ Loading Loading @@ -99,13 +106,16 @@ struct fan53555_device_info { unsigned int slew_rate; /* Sleep voltage cache */ unsigned int sleep_vol_cache; unsigned int peek_poke_address; /* Disable suspend */ bool disable_suspend; struct dentry *debug_root; }; static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); u8 vsel_mask; int ret; if (di->disable_suspend) Loading @@ -115,8 +125,10 @@ static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) ret = regulator_map_voltage_linear(rdev, uV, uV); if (ret < 0) return ret; ret = regmap_update_bits(di->regmap, di->sleep_reg, VSEL_NSEL_MASK, ret); vsel_mask = (di->vendor == HALO_HL7503) ? HL7503_VSEL_NSEL_MASK : VSEL_NSEL_MASK; ret = regmap_update_bits(di->regmap, di->sleep_reg, vsel_mask, ret); if (ret < 0) return ret; /* Cache the sleep voltage setting. Loading @@ -130,6 +142,9 @@ static int fan53555_set_suspend_enable(struct regulator_dev *rdev) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); if (di->disable_suspend) return 0; return regmap_update_bits(di->regmap, di->sleep_reg, VSEL_BUCK_EN, VSEL_BUCK_EN); } Loading @@ -138,6 +153,9 @@ static int fan53555_set_suspend_disable(struct regulator_dev *rdev) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); if (di->disable_suspend) return 0; return regmap_update_bits(di->regmap, di->sleep_reg, VSEL_BUCK_EN, 0); } Loading @@ -145,14 +163,23 @@ static int fan53555_set_suspend_disable(struct regulator_dev *rdev) static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); unsigned int reg, mask; reg = di->vol_reg; mask = VSEL_MODE; if (di->vendor == HALO_HL7503) { /* uses control register for mode control */ reg = FAN53555_CONTROL; mask = (di->vol_reg = FAN53555_VSEL0) ? HL7503_VSEL0_MODE : HL7503_VSEL1_MODE; } switch (mode) { case REGULATOR_MODE_FAST: regmap_update_bits(di->regmap, di->vol_reg, VSEL_MODE, VSEL_MODE); regmap_update_bits(di->regmap, reg, mask, mask); break; case REGULATOR_MODE_NORMAL: regmap_update_bits(di->regmap, di->vol_reg, VSEL_MODE, 0); regmap_update_bits(di->regmap, reg, mask, 0); break; default: return -EINVAL; Loading @@ -163,13 +190,22 @@ static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode) static unsigned int fan53555_get_mode(struct regulator_dev *rdev) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); unsigned int val; unsigned int val, reg, mask; int ret = 0; ret = regmap_read(di->regmap, di->vol_reg, &val); reg = di->vol_reg; mask = VSEL_MODE; if (di->vendor == HALO_HL7503) { /* uses control register for mode control */ reg = FAN53555_CONTROL; mask = (di->vol_reg = FAN53555_VSEL0) ? HL7503_VSEL0_MODE : HL7503_VSEL1_MODE; } ret = regmap_read(di->regmap, reg, &val); if (ret < 0) return ret; if (val & VSEL_MODE) if (val & mask) return REGULATOR_MODE_FAST; else return REGULATOR_MODE_NORMAL; Loading Loading @@ -282,6 +318,23 @@ static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di) return 0; } static int hl7503_voltages_setup_halo(struct fan53555_device_info *di) { /* Init voltage range and step */ switch (di->chip_id) { case FAN53555_CHIP_ID_08: di->vsel_min = 600000; di->vsel_step = 6250; break; default: dev_err(di->dev, "Chip ID %d not supported!\n", di->chip_id); return -EINVAL; } return 0; } /* For 00,01,03,05 options: * VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V. * For 04 option: Loading Loading @@ -317,6 +370,9 @@ static int fan53555_device_setup(struct fan53555_device_info *di, case HALO_HL7509: ret = fan53555_voltages_setup_fairchild(di); break; case HALO_HL7503: ret = hl7503_voltages_setup_halo(di); break; default: dev_err(di->dev, "vendor %d not supported!\n", di->vendor); return -EINVAL; Loading @@ -334,15 +390,21 @@ static int fan53555_regulator_register(struct fan53555_device_info *di, rdesc->supply_name = "vin"; rdesc->ops = &fan53555_regulator_ops; rdesc->type = REGULATOR_VOLTAGE; rdesc->n_voltages = FAN53555_NVOLTAGES; rdesc->enable_reg = di->vol_reg; rdesc->enable_mask = VSEL_BUCK_EN; rdesc->min_uV = di->vsel_min; rdesc->uV_step = di->vsel_step; rdesc->vsel_reg = di->vol_reg; rdesc->vsel_mask = VSEL_NSEL_MASK; rdesc->owner = THIS_MODULE; if (di->vendor == HALO_HL7503) { rdesc->n_voltages = HL7503_NVOLTAGES; rdesc->vsel_mask = HL7503_VSEL_NSEL_MASK; } else { rdesc->n_voltages = FAN53555_NVOLTAGES; rdesc->vsel_mask = VSEL_NSEL_MASK; } di->rdev = devm_regulator_register(di->dev, &di->desc, config); return PTR_ERR_OR_ZERO(di->rdev); } Loading @@ -350,8 +412,54 @@ static int fan53555_regulator_register(struct fan53555_device_info *di, static const struct regmap_config fan53555_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 0x05, }; static int fan53555_parse_vsel_gpio(struct fan53555_device_info *di) { struct device_node *np = di->dev->of_node; unsigned int val; int ret = 0, gpio; enum of_gpio_flags flags; if (!of_find_property(np, "fcs,vsel-gpio", NULL)) return ret; ret = regmap_read(di->regmap, di->sleep_reg, &val); if (ret < 0) return ret; ret = regmap_write(di->regmap, di->vol_reg, val); if (ret < 0) return ret; /* Get GPIO connected to vsel and set its output */ gpio = of_get_named_gpio_flags(np, "fcs,vsel-gpio", 0, &flags); if (!gpio_is_valid(gpio)) { if (gpio != -EPROBE_DEFER) dev_err(di->dev, "Could not get vsel, ret = %d\n", gpio); return gpio; } ret = devm_gpio_request(di->dev, gpio, "fan53555_vsel"); if (ret) { dev_err(di->dev, "Failed to obtain gpio %d ret = %d\n", gpio, ret); return ret; } ret = gpio_direction_output(gpio, flags & OF_GPIO_ACTIVE_LOW ? 0 : 1); if (ret) { dev_err(di->dev, "Failed to set GPIO %d to: %s, ret = %d", gpio, flags & OF_GPIO_ACTIVE_LOW ? "GPIO_LOW" : "GPIO_HIGH", ret); return ret; } return ret; } static int fan53555_parse_dt(struct fan53555_device_info *di, struct fan53555_platform_data *pdata, const struct regulator_desc *desc) Loading Loading @@ -390,11 +498,46 @@ static const struct of_device_id fan53555_dt_ids[] = { }, { .compatible = "halo,hl7509", .data = (void *)HALO_HL7509, }, { .compatible = "halo,hl7503", .data = (void *)HALO_HL7503, }, { } }; MODULE_DEVICE_TABLE(of, fan53555_dt_ids); static int get_reg(void *data, u64 *val) { struct fan53555_device_info *di = data; int rc; unsigned int temp = 0; rc = regmap_read(di->regmap, di->peek_poke_address, &temp); if (rc < 0) dev_err(di->dev, "Couldn't read reg %x rc = %d\n", di->peek_poke_address, rc); else *val = temp; return rc; } static int set_reg(void *data, u64 val) { struct fan53555_device_info *di = data; int rc; unsigned int temp = 0; temp = (unsigned int) val; rc = regmap_write(di->regmap, di->peek_poke_address, temp); if (rc < 0) dev_err(di->dev, "Couldn't write 0x%02x to 0x%02x rc= %d\n", di->peek_poke_address, temp, rc); return rc; } DEFINE_SIMPLE_ATTRIBUTE(poke_poke_debug_ops, get_reg, set_reg, "0x%02llx\n"); static int fan53555_regulator_probe(struct i2c_client *client, const struct i2c_device_id *id) { Loading Loading @@ -466,6 +609,13 @@ static int fan53555_regulator_probe(struct i2c_client *client, dev_err(&client->dev, "Failed to setup device!\n"); return ret; } ret = fan53555_parse_vsel_gpio(di); if (ret < 0) { dev_err(&client->dev, "Failed to parse gpio!\n"); return ret; } /* Register regulator */ config.dev = di->dev; config.init_data = di->regulator; Loading @@ -476,8 +626,27 @@ static int fan53555_regulator_probe(struct i2c_client *client, ret = fan53555_regulator_register(di, &config); if (ret < 0) dev_err(&client->dev, "Failed to register regulator!\n"); return ret; di->debug_root = debugfs_create_dir("fan53555", NULL); if (!di->debug_root) dev_err(&client->dev, "Couldn't create debug dir\n"); if (di->debug_root) { struct dentry *ent; ent = debugfs_create_x32("address", S_IFREG | 0644, di->debug_root, &(di->peek_poke_address)); if (!ent) dev_err(&client->dev, "Couldn't create address debug file\n"); ent = debugfs_create_file("data", S_IFREG | 0644, di->debug_root, di, &poke_poke_debug_ops); if (!ent) dev_err(&client->dev, "Couldn't create data debug file\n"); } return ret; } static const struct i2c_device_id fan53555_id[] = { Loading Loading
Documentation/devicetree/bindings/regulator/fan53555.txt +2 −2 Original line number Diff line number Diff line Binding for Fairchild FAN53555 regulators Required properties: - compatible: one of "fcs,fan53555", "silergy,syr827", "silergy,syr828" or "halo,hl7509" - compatible: one of "fcs,fan53555", "silergy,syr827", "silergy,syr828", "halo,hl7509" or "halo,hl7503" - reg: I2C address Optional properties: Loading
drivers/regulator/fan53555.c +181 −12 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ * published by the Free Software Foundation. * */ #include <linux/debugfs.h> #include <linux/module.h> #include <linux/param.h> #include <linux/err.h> Loading @@ -20,6 +21,7 @@ #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> #include <linux/of_device.h> #include <linux/of_gpio.h> #include <linux/i2c.h> #include <linux/slab.h> #include <linux/regmap.h> Loading @@ -40,7 +42,10 @@ /* VSEL bit definitions */ #define VSEL_BUCK_EN (1 << 7) #define VSEL_MODE (1 << 6) #define HL7503_VSEL0_MODE BIT(0) #define HL7503_VSEL1_MODE BIT(1) #define VSEL_NSEL_MASK 0x3F #define HL7503_VSEL_NSEL_MASK 0x7F /* Chip ID and Verison */ #define DIE_ID 0x0F /* ID1 */ #define DIE_REV 0x0F /* ID2 */ Loading @@ -51,11 +56,13 @@ #define CTL_RESET (1 << 2) #define FAN53555_NVOLTAGES 64 /* Numbers of voltages */ #define HL7503_NVOLTAGES 128 enum fan53555_vendor { FAN53555_VENDOR_FAIRCHILD = 0, FAN53555_VENDOR_SILERGY, HALO_HL7509, HALO_HL7503, }; /* IC Type */ Loading Loading @@ -99,13 +106,16 @@ struct fan53555_device_info { unsigned int slew_rate; /* Sleep voltage cache */ unsigned int sleep_vol_cache; unsigned int peek_poke_address; /* Disable suspend */ bool disable_suspend; struct dentry *debug_root; }; static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); u8 vsel_mask; int ret; if (di->disable_suspend) Loading @@ -115,8 +125,10 @@ static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) ret = regulator_map_voltage_linear(rdev, uV, uV); if (ret < 0) return ret; ret = regmap_update_bits(di->regmap, di->sleep_reg, VSEL_NSEL_MASK, ret); vsel_mask = (di->vendor == HALO_HL7503) ? HL7503_VSEL_NSEL_MASK : VSEL_NSEL_MASK; ret = regmap_update_bits(di->regmap, di->sleep_reg, vsel_mask, ret); if (ret < 0) return ret; /* Cache the sleep voltage setting. Loading @@ -130,6 +142,9 @@ static int fan53555_set_suspend_enable(struct regulator_dev *rdev) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); if (di->disable_suspend) return 0; return regmap_update_bits(di->regmap, di->sleep_reg, VSEL_BUCK_EN, VSEL_BUCK_EN); } Loading @@ -138,6 +153,9 @@ static int fan53555_set_suspend_disable(struct regulator_dev *rdev) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); if (di->disable_suspend) return 0; return regmap_update_bits(di->regmap, di->sleep_reg, VSEL_BUCK_EN, 0); } Loading @@ -145,14 +163,23 @@ static int fan53555_set_suspend_disable(struct regulator_dev *rdev) static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); unsigned int reg, mask; reg = di->vol_reg; mask = VSEL_MODE; if (di->vendor == HALO_HL7503) { /* uses control register for mode control */ reg = FAN53555_CONTROL; mask = (di->vol_reg = FAN53555_VSEL0) ? HL7503_VSEL0_MODE : HL7503_VSEL1_MODE; } switch (mode) { case REGULATOR_MODE_FAST: regmap_update_bits(di->regmap, di->vol_reg, VSEL_MODE, VSEL_MODE); regmap_update_bits(di->regmap, reg, mask, mask); break; case REGULATOR_MODE_NORMAL: regmap_update_bits(di->regmap, di->vol_reg, VSEL_MODE, 0); regmap_update_bits(di->regmap, reg, mask, 0); break; default: return -EINVAL; Loading @@ -163,13 +190,22 @@ static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode) static unsigned int fan53555_get_mode(struct regulator_dev *rdev) { struct fan53555_device_info *di = rdev_get_drvdata(rdev); unsigned int val; unsigned int val, reg, mask; int ret = 0; ret = regmap_read(di->regmap, di->vol_reg, &val); reg = di->vol_reg; mask = VSEL_MODE; if (di->vendor == HALO_HL7503) { /* uses control register for mode control */ reg = FAN53555_CONTROL; mask = (di->vol_reg = FAN53555_VSEL0) ? HL7503_VSEL0_MODE : HL7503_VSEL1_MODE; } ret = regmap_read(di->regmap, reg, &val); if (ret < 0) return ret; if (val & VSEL_MODE) if (val & mask) return REGULATOR_MODE_FAST; else return REGULATOR_MODE_NORMAL; Loading Loading @@ -282,6 +318,23 @@ static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di) return 0; } static int hl7503_voltages_setup_halo(struct fan53555_device_info *di) { /* Init voltage range and step */ switch (di->chip_id) { case FAN53555_CHIP_ID_08: di->vsel_min = 600000; di->vsel_step = 6250; break; default: dev_err(di->dev, "Chip ID %d not supported!\n", di->chip_id); return -EINVAL; } return 0; } /* For 00,01,03,05 options: * VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V. * For 04 option: Loading Loading @@ -317,6 +370,9 @@ static int fan53555_device_setup(struct fan53555_device_info *di, case HALO_HL7509: ret = fan53555_voltages_setup_fairchild(di); break; case HALO_HL7503: ret = hl7503_voltages_setup_halo(di); break; default: dev_err(di->dev, "vendor %d not supported!\n", di->vendor); return -EINVAL; Loading @@ -334,15 +390,21 @@ static int fan53555_regulator_register(struct fan53555_device_info *di, rdesc->supply_name = "vin"; rdesc->ops = &fan53555_regulator_ops; rdesc->type = REGULATOR_VOLTAGE; rdesc->n_voltages = FAN53555_NVOLTAGES; rdesc->enable_reg = di->vol_reg; rdesc->enable_mask = VSEL_BUCK_EN; rdesc->min_uV = di->vsel_min; rdesc->uV_step = di->vsel_step; rdesc->vsel_reg = di->vol_reg; rdesc->vsel_mask = VSEL_NSEL_MASK; rdesc->owner = THIS_MODULE; if (di->vendor == HALO_HL7503) { rdesc->n_voltages = HL7503_NVOLTAGES; rdesc->vsel_mask = HL7503_VSEL_NSEL_MASK; } else { rdesc->n_voltages = FAN53555_NVOLTAGES; rdesc->vsel_mask = VSEL_NSEL_MASK; } di->rdev = devm_regulator_register(di->dev, &di->desc, config); return PTR_ERR_OR_ZERO(di->rdev); } Loading @@ -350,8 +412,54 @@ static int fan53555_regulator_register(struct fan53555_device_info *di, static const struct regmap_config fan53555_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 0x05, }; static int fan53555_parse_vsel_gpio(struct fan53555_device_info *di) { struct device_node *np = di->dev->of_node; unsigned int val; int ret = 0, gpio; enum of_gpio_flags flags; if (!of_find_property(np, "fcs,vsel-gpio", NULL)) return ret; ret = regmap_read(di->regmap, di->sleep_reg, &val); if (ret < 0) return ret; ret = regmap_write(di->regmap, di->vol_reg, val); if (ret < 0) return ret; /* Get GPIO connected to vsel and set its output */ gpio = of_get_named_gpio_flags(np, "fcs,vsel-gpio", 0, &flags); if (!gpio_is_valid(gpio)) { if (gpio != -EPROBE_DEFER) dev_err(di->dev, "Could not get vsel, ret = %d\n", gpio); return gpio; } ret = devm_gpio_request(di->dev, gpio, "fan53555_vsel"); if (ret) { dev_err(di->dev, "Failed to obtain gpio %d ret = %d\n", gpio, ret); return ret; } ret = gpio_direction_output(gpio, flags & OF_GPIO_ACTIVE_LOW ? 0 : 1); if (ret) { dev_err(di->dev, "Failed to set GPIO %d to: %s, ret = %d", gpio, flags & OF_GPIO_ACTIVE_LOW ? "GPIO_LOW" : "GPIO_HIGH", ret); return ret; } return ret; } static int fan53555_parse_dt(struct fan53555_device_info *di, struct fan53555_platform_data *pdata, const struct regulator_desc *desc) Loading Loading @@ -390,11 +498,46 @@ static const struct of_device_id fan53555_dt_ids[] = { }, { .compatible = "halo,hl7509", .data = (void *)HALO_HL7509, }, { .compatible = "halo,hl7503", .data = (void *)HALO_HL7503, }, { } }; MODULE_DEVICE_TABLE(of, fan53555_dt_ids); static int get_reg(void *data, u64 *val) { struct fan53555_device_info *di = data; int rc; unsigned int temp = 0; rc = regmap_read(di->regmap, di->peek_poke_address, &temp); if (rc < 0) dev_err(di->dev, "Couldn't read reg %x rc = %d\n", di->peek_poke_address, rc); else *val = temp; return rc; } static int set_reg(void *data, u64 val) { struct fan53555_device_info *di = data; int rc; unsigned int temp = 0; temp = (unsigned int) val; rc = regmap_write(di->regmap, di->peek_poke_address, temp); if (rc < 0) dev_err(di->dev, "Couldn't write 0x%02x to 0x%02x rc= %d\n", di->peek_poke_address, temp, rc); return rc; } DEFINE_SIMPLE_ATTRIBUTE(poke_poke_debug_ops, get_reg, set_reg, "0x%02llx\n"); static int fan53555_regulator_probe(struct i2c_client *client, const struct i2c_device_id *id) { Loading Loading @@ -466,6 +609,13 @@ static int fan53555_regulator_probe(struct i2c_client *client, dev_err(&client->dev, "Failed to setup device!\n"); return ret; } ret = fan53555_parse_vsel_gpio(di); if (ret < 0) { dev_err(&client->dev, "Failed to parse gpio!\n"); return ret; } /* Register regulator */ config.dev = di->dev; config.init_data = di->regulator; Loading @@ -476,8 +626,27 @@ static int fan53555_regulator_probe(struct i2c_client *client, ret = fan53555_regulator_register(di, &config); if (ret < 0) dev_err(&client->dev, "Failed to register regulator!\n"); return ret; di->debug_root = debugfs_create_dir("fan53555", NULL); if (!di->debug_root) dev_err(&client->dev, "Couldn't create debug dir\n"); if (di->debug_root) { struct dentry *ent; ent = debugfs_create_x32("address", S_IFREG | 0644, di->debug_root, &(di->peek_poke_address)); if (!ent) dev_err(&client->dev, "Couldn't create address debug file\n"); ent = debugfs_create_file("data", S_IFREG | 0644, di->debug_root, di, &poke_poke_debug_ops); if (!ent) dev_err(&client->dev, "Couldn't create data debug file\n"); } return ret; } static const struct i2c_device_id fan53555_id[] = { Loading