diff options
Diffstat (limited to 'drivers/regulator')
89 files changed, 7718 insertions, 2865 deletions
diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c index 3459f60dcfd..7a721d67e6a 100644 --- a/drivers/regulator/88pm800.c +++ b/drivers/regulator/88pm800.c @@ -141,18 +141,14 @@ struct pm800_regulators {  /* Ranges are sorted in ascending order. */  static const struct regulator_linear_range buck1_volt_range[] = { -	{ .min_uV = 600000, .max_uV = 1587500, .min_sel = 0, .max_sel = 0x4f, -	  .uV_step = 12500 }, -	{ .min_uV = 1600000, .max_uV = 1800000, .min_sel = 0x50, -	  .max_sel = 0x54, .uV_step = 50000 }, +	REGULATOR_LINEAR_RANGE(600000, 0, 0x4f, 12500), +	REGULATOR_LINEAR_RANGE(1600000, 0x50, 0x54, 50000),  };  /* BUCK 2~5 have same ranges. */  static const struct regulator_linear_range buck2_5_volt_range[] = { -	{ .min_uV = 600000, .max_uV = 1587500,	.min_sel = 0, .max_sel = 0x4f, -	  .uV_step = 12500 }, -	{ .min_uV = 1600000, .max_uV = 3300000, .min_sel = 0x50, -	  .max_sel = 0x72, .uV_step = 50000 }, +	REGULATOR_LINEAR_RANGE(600000, 0, 0x4f, 12500), +	REGULATOR_LINEAR_RANGE(1600000, 0x50, 0x72, 50000),  };  static const unsigned int ldo1_volt_table[] = { @@ -314,10 +310,8 @@ static int pm800_regulator_probe(struct platform_device *pdev)  	pm800_data = devm_kzalloc(&pdev->dev, sizeof(*pm800_data),  					GFP_KERNEL); -	if (!pm800_data) { -		dev_err(&pdev->dev, "Failed to allocate pm800_regualtors"); +	if (!pm800_data)  		return -ENOMEM; -	}  	pm800_data->map = chip->subchip->regmap_power;  	pm800_data->chip = chip; diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 70230974468..337634ad056 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -2,7 +2,7 @@   * Regulators driver for Marvell 88PM8607   *   * Copyright (C) 2009 Marvell International Ltd. - * 	Haojian Zhuang <haojian.zhuang@marvell.com> + *	Haojian Zhuang <haojian.zhuang@marvell.com>   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License version 2 as @@ -78,7 +78,7 @@ static const unsigned int BUCK2_suspend_table[] = {  };  static const unsigned int BUCK3_table[] = { -              0,   25000,   50000,   75000,  100000,  125000,  150000,  175000, +	      0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,  	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,  	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,  	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000, @@ -89,7 +89,7 @@ static const unsigned int BUCK3_table[] = {  };  static const unsigned int BUCK3_suspend_table[] = { -              0,   25000,   50000,   75000,  100000,  125000,  150000,  175000, +	      0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,  	 200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,  	 400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,  	 600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000, @@ -322,7 +322,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev,  	nproot = of_node_get(pdev->dev.parent->of_node);  	if (!nproot)  		return -ENODEV; -	nproot = of_find_node_by_name(nproot, "regulators"); +	nproot = of_get_child_by_name(nproot, "regulators");  	if (!nproot) {  		dev_err(&pdev->dev, "failed to find regulators node\n");  		return -ENODEV; @@ -391,7 +391,8 @@ static int pm8607_regulator_probe(struct platform_device *pdev)  	else  		config.regmap = chip->regmap_companion; -	info->regulator = regulator_register(&info->desc, &config); +	info->regulator = devm_regulator_register(&pdev->dev, &info->desc, +						  &config);  	if (IS_ERR(info->regulator)) {  		dev_err(&pdev->dev, "failed to register regulator %s\n",  			info->desc.name); @@ -402,14 +403,6 @@ static int pm8607_regulator_probe(struct platform_device *pdev)  	return 0;  } -static int pm8607_regulator_remove(struct platform_device *pdev) -{ -	struct pm8607_regulator_info *info = platform_get_drvdata(pdev); - -	regulator_unregister(info->regulator); -	return 0; -} -  static struct platform_device_id pm8607_regulator_driver_ids[] = {  	{  		.name	= "88pm860x-regulator", @@ -428,7 +421,6 @@ static struct platform_driver pm8607_regulator_driver = {  		.owner	= THIS_MODULE,  	},  	.probe		= pm8607_regulator_probe, -	.remove		= pm8607_regulator_remove,  	.id_table	= pm8607_regulator_driver_ids,  }; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index dfe58096b37..789eb46090e 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -28,16 +28,6 @@ config REGULATOR_DEBUG  	help  	  Say yes here to enable debugging support. -config REGULATOR_DUMMY -	bool "Provide a dummy regulator if regulator lookups fail" -	help -	  If this option is enabled then when a regulator lookup fails -	  and the board has not specified that it has provided full -	  constraints the regulator core will provide an always -	  enabled dummy regulator, allowing consumer drivers to continue. - -	  A warning will be generated when this substitution is done. -  config REGULATOR_FIXED_VOLTAGE  	tristate "Fixed voltage regulator support"  	help @@ -80,6 +70,14 @@ config REGULATOR_88PM8607  	help  	  This driver supports 88PM8607 voltage regulator chips. +config REGULATOR_ACT8865 +	tristate "Active-semi act8865 voltage regulator" +	depends on I2C +	select REGMAP_I2C +	help +	  This driver controls a active-semi act8865 voltage output +	  regulator via I2C bus. +  config REGULATOR_AD5398  	tristate "Analog Devices AD5398/AD5821 regulators"  	depends on I2C @@ -133,6 +131,29 @@ config REGULATOR_AS3711  	  This driver provides support for the voltage regulators on the  	  AS3711 PMIC +config REGULATOR_AS3722 +	tristate "AMS AS3722 PMIC Regulators" +	depends on MFD_AS3722 +	help +	  This driver provides support for the voltage regulators on the +	  AS3722 PMIC. This will enable support for all the software +	  controllable DCDC/LDO regulators. + +config REGULATOR_AXP20X +	tristate "X-POWERS AXP20X PMIC Regulators" +	depends on MFD_AXP20X +	help +	  This driver provides support for the voltage regulators on the +	  AXP20X PMIC. + +config REGULATOR_BCM590XX +	tristate "Broadcom BCM590xx PMU Regulators" +	depends on MFD_BCM590XX +	help +	  This driver provides support for the voltage regulators on the +	  BCM590xx PMUs. This will enable support for the software +	  controllable LDO/Switching regulators. +  config REGULATOR_DA903X  	tristate "Dialog Semiconductor DA9030/DA9034 regulators"  	depends on PMIC_DA903X @@ -251,6 +272,22 @@ config REGULATOR_LP8788  	help  	  This driver supports LP8788 voltage regulator chip. +config REGULATOR_LTC3589 +	tristate "LTC3589 8-output voltage regulator" +	depends on I2C +	select REGMAP_I2C +	help +	  This enables support for the LTC3589, LTC3589-1, and LTC3589-2 +	  8-output regulators controlled via I2C. + +config REGULATOR_MAX14577 +	tristate "Maxim 14577/77836 regulator" +	depends on MFD_MAX14577 +	help +	  This driver controls a Maxim MAX14577/77836 regulator via I2C bus. +	  The MAX14577 regulators include safeout LDO and charger current +	  regulator. The MAX77836 has two additional LDOs. +  config REGULATOR_MAX1586  	tristate "Maxim 1586/1587 voltage regulator"  	depends on I2C @@ -345,7 +382,7 @@ config REGULATOR_MC13XXX_CORE  config REGULATOR_MC13783  	tristate "Freescale MC13783 regulator driver" -	depends on MFD_MC13783 +	depends on MFD_MC13XXX  	select REGULATOR_MC13XXX_CORE  	help  	  Say y here to support the regulators found on the Freescale MC13783 @@ -371,6 +408,15 @@ config REGULATOR_PALMAS  	  on the muxing. This is handled automatically in the driver by  	  reading the mux info from OTP. +config REGULATOR_PBIAS +	tristate "PBIAS OMAP regulator driver" +	depends on (ARCH_OMAP || COMPILE_TEST) && MFD_SYSCON +	help +	 Say y here to support pbias regulator for mmc1:SD card i/o +	 on OMAP SoCs. +	 This driver provides support for OMAP pbias modelled +	 regulators. +  config REGULATOR_PCAP  	tristate "Motorola PCAP2 regulator driver"  	depends on EZX_PCAP @@ -386,12 +432,12 @@ config REGULATOR_PCF50633  	 on PCF50633  config REGULATOR_PFUZE100 -	tristate "Support regulators on Freescale PFUZE100 PMIC" +	tristate "Freescale PFUZE100/PFUZE200 regulator driver"  	depends on I2C  	select REGMAP_I2C  	help -	  Say y here to support the regulators found on the Freescale PFUZE100 -	  PMIC. +	  Say y here to support the regulators found on the Freescale +	  PFUZE100/PFUZE200 PMIC.  config REGULATOR_RC5T583  	tristate "RICOH RC5T583 Power regulators" @@ -403,13 +449,21 @@ config REGULATOR_RC5T583  	  through regulator interface. The device supports multiple DCDC/LDO  	  outputs which can be controlled by i2c communication. +config REGULATOR_S2MPA01 +	tristate "Samsung S2MPA01 voltage regulator" +	depends on MFD_SEC_CORE +	help +	 This driver controls Samsung S2MPA01 voltage output regulator +	 via I2C bus. S2MPA01 has 10 Bucks and 26 LDO outputs. +  config REGULATOR_S2MPS11 -	tristate "Samsung S2MPS11 voltage regulator" +	tristate "Samsung S2MPS11/S2MPS14 voltage regulator"  	depends on MFD_SEC_CORE  	help -	 This driver supports a Samsung S2MPS11 voltage output regulator -	 via I2C bus. S2MPS11 is comprised of high efficient Buck converters -	 including Dual-Phase Buck converter, Buck-Boost converter, various LDOs. +	 This driver supports a Samsung S2MPS11/S2MPS14 voltage output +	 regulator via I2C bus. The chip is comprised of high efficient Buck +	 converters including Dual-Phase Buck converter, Buck-Boost converter, +	 various LDOs.  config REGULATOR_S5M8767  	tristate "Samsung S5M8767A voltage regulator" @@ -419,6 +473,12 @@ config REGULATOR_S5M8767  	 via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and  	 supports DVS mode with 8bits of output voltage control. +config REGULATOR_ST_PWM +	tristate "STMicroelectronics PWM voltage regulator" +	depends on ARCH_STI +	help +	 This driver supports ST's PWM controlled voltage regulators. +  config REGULATOR_TI_ABB  	tristate "TI Adaptive Body Bias on-chip LDO"  	depends on ARCH_OMAP @@ -429,6 +489,14 @@ config REGULATOR_TI_ABB  	  on TI SoCs may be unstable without enabling this as it provides  	  device specific optimized bias to allow/optimize functionality. +config REGULATOR_STW481X_VMMC +	bool "ST Microelectronics STW481X VMMC regulator" +	depends on MFD_STW481X +	default y if MFD_STW481X +	help +	  This driver supports the internal VMMC regulator in the STw481x +	  PMIC chips. +  config REGULATOR_TPS51632  	tristate "TI TPS51632 Power Regulator"  	depends on I2C @@ -492,6 +560,15 @@ config REGULATOR_TPS65217  	  voltage regulators. It supports software based voltage control  	  for different voltage domains +config REGULATOR_TPS65218 +	tristate "TI TPS65218 Power regulators" +	depends on MFD_TPS65218 && OF +	help +	  This driver supports TPS65218 voltage regulator chips. TPS65218 +	  provides six step-down converters and one general-purpose LDO +	  voltage regulators. It supports software based voltage control +	  for different voltage domains +  config REGULATOR_TPS6524X  	tristate "TI TPS6524X Power regulators"  	depends on SPI diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 185cce24602..d461110f446 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -3,7 +3,7 @@  # -obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o +obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o  obj-$(CONFIG_OF) += of_regulator.o  obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o  obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o @@ -14,10 +14,14 @@ obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o  obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o  obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o  obj-$(CONFIG_REGULATOR_AB8500)	+= ab8500-ext.o ab8500.o +obj-$(CONFIG_REGULATOR_ACT8865) += act8865-regulator.o  obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o  obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o  obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o  obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o +obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o +obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o +obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o  obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o  obj-$(CONFIG_REGULATOR_DA9052)	+= da9052-regulator.o  obj-$(CONFIG_REGULATOR_DA9055)	+= da9055-regulator.o @@ -34,6 +38,8 @@ obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o  obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o  obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o  obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o +obj-$(CONFIG_REGULATOR_LTC3589) += ltc3589.o +obj-$(CONFIG_REGULATOR_MAX14577) += max14577.o  obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o  obj-$(CONFIG_REGULATOR_MAX8649)	+= max8649.o  obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o @@ -51,11 +57,15 @@ obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o  obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o  obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o  obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o +obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o  obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o  obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o  obj-$(CONFIG_REGULATOR_RC5T583)  += rc5t583-regulator.o +obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o  obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o  obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o +obj-$(CONFIG_REGULATOR_ST_PWM) += st-pwm.o +obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o  obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o  obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o  obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o @@ -63,6 +73,7 @@ obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o  obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o  obj-$(CONFIG_REGULATOR_TPS65090) += tps65090-regulator.o  obj-$(CONFIG_REGULATOR_TPS65217) += tps65217-regulator.o +obj-$(CONFIG_REGULATOR_TPS65218) += tps65218-regulator.o  obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o  obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o  obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c index 881159dfcb5..c873ee0082c 100644 --- a/drivers/regulator/aat2870-regulator.c +++ b/drivers/regulator/aat2870-regulator.c @@ -99,6 +99,7 @@ static int aat2870_ldo_is_enabled(struct regulator_dev *rdev)  static struct regulator_ops aat2870_ldo_ops = {  	.list_voltage = regulator_list_voltage_table, +	.map_voltage = regulator_map_voltage_ascend,  	.set_voltage_sel = aat2870_ldo_set_voltage_sel,  	.get_voltage_sel = aat2870_ldo_get_voltage_sel,  	.enable = aat2870_ldo_enable, @@ -176,7 +177,7 @@ static int aat2870_regulator_probe(struct platform_device *pdev)  	config.driver_data = ri;  	config.init_data = dev_get_platdata(&pdev->dev); -	rdev = regulator_register(&ri->desc, &config); +	rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config);  	if (IS_ERR(rdev)) {  		dev_err(&pdev->dev, "Failed to register regulator %s\n",  			ri->desc.name); @@ -187,21 +188,12 @@ static int aat2870_regulator_probe(struct platform_device *pdev)  	return 0;  } -static int aat2870_regulator_remove(struct platform_device *pdev) -{ -	struct regulator_dev *rdev = platform_get_drvdata(pdev); - -	regulator_unregister(rdev); -	return 0; -} -  static struct platform_driver aat2870_regulator_driver = {  	.driver = {  		.name	= "aat2870-regulator",  		.owner	= THIS_MODULE,  	},  	.probe	= aat2870_regulator_probe, -	.remove	= aat2870_regulator_remove,  };  static int __init aat2870_regulator_init(void) diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index 7d5eaa874b2..e10febe9ec3 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -498,7 +498,7 @@ static int ab3100_regulator_register(struct platform_device *pdev,  				     struct ab3100_platform_data *plfdata,  				     struct regulator_init_data *init_data,  				     struct device_node *np, -				     int id) +				     unsigned long id)  {  	struct regulator_desc *desc;  	struct ab3100_regulator *reg; @@ -535,7 +535,7 @@ static int ab3100_regulator_register(struct platform_device *pdev,  	config.dev = &pdev->dev;  	config.driver_data = reg; -	rdev = regulator_register(desc, &config); +	rdev = devm_regulator_register(&pdev->dev, desc, &config);  	if (IS_ERR(rdev)) {  		err = PTR_ERR(rdev);  		dev_err(&pdev->dev, @@ -616,7 +616,6 @@ static int ab3100_regulators_remove(struct platform_device *pdev)  	for (i = 0; i < AB3100_NUM_REGULATORS; i++) {  		struct ab3100_regulator *reg = &ab3100_regulators[i]; -		regulator_unregister(reg->rdev);  		reg->rdev = NULL;  	}  	return 0; @@ -647,7 +646,7 @@ ab3100_regulator_of_probe(struct platform_device *pdev, struct device_node *np)  		err = ab3100_regulator_register(  			pdev, NULL, ab3100_regulator_matches[i].init_data,  			ab3100_regulator_matches[i].of_node, -			(int) ab3100_regulator_matches[i].driver_data); +			(unsigned long)ab3100_regulator_matches[i].driver_data);  		if (err) {  			ab3100_regulators_remove(pdev);  			return err; diff --git a/drivers/regulator/ab8500-ext.c b/drivers/regulator/ab8500-ext.c index 02ff691cdb8..29c0faaf8eb 100644 --- a/drivers/regulator/ab8500-ext.c +++ b/drivers/regulator/ab8500-ext.c @@ -413,16 +413,12 @@ static int ab8500_ext_regulator_probe(struct platform_device *pdev)  			&pdata->ext_regulator[i];  		/* register regulator with framework */ -		info->rdev = regulator_register(&info->desc, &config); +		info->rdev = devm_regulator_register(&pdev->dev, &info->desc, +						     &config);  		if (IS_ERR(info->rdev)) {  			err = PTR_ERR(info->rdev);  			dev_err(&pdev->dev, "failed to register regulator %s\n",  					info->desc.name); -			/* when we fail, un-register all earlier regulators */ -			while (--i >= 0) { -				info = &ab8500_ext_regulator_info[i]; -				regulator_unregister(info->rdev); -			}  			return err;  		} @@ -433,26 +429,8 @@ static int ab8500_ext_regulator_probe(struct platform_device *pdev)  	return 0;  } -static int ab8500_ext_regulator_remove(struct platform_device *pdev) -{ -	int i; - -	for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) { -		struct ab8500_ext_regulator_info *info = NULL; -		info = &ab8500_ext_regulator_info[i]; - -		dev_vdbg(rdev_get_dev(info->rdev), -			"%s-remove\n", info->desc.name); - -		regulator_unregister(info->rdev); -	} - -	return 0; -} -  static struct platform_driver ab8500_ext_regulator_driver = {  	.probe = ab8500_ext_regulator_probe, -	.remove = ab8500_ext_regulator_remove,  	.driver         = {  		.name   = "ab8500-ext-regulator",  		.owner  = THIS_MODULE, diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 603f192e84f..c625468c7f2 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -2998,37 +2998,6 @@ static void abx500_get_regulator_info(struct ab8500 *ab8500)  	}  } -static int ab8500_regulator_init_registers(struct platform_device *pdev, -					   int id, int mask, int value) -{ -	struct ab8500_reg_init *reg_init = abx500_regulator.init; -	int err; - -	BUG_ON(value & ~mask); -	BUG_ON(mask & ~reg_init[id].mask); - -	/* initialize register */ -	err = abx500_mask_and_set_register_interruptible( -		&pdev->dev, -		reg_init[id].bank, -		reg_init[id].addr, -		mask, value); -	if (err < 0) { -		dev_err(&pdev->dev, -			"Failed to initialize 0x%02x, 0x%02x.\n", -			reg_init[id].bank, -			reg_init[id].addr); -		return err; -	} -	dev_vdbg(&pdev->dev, -		 "  init: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", -		 reg_init[id].bank, -		 reg_init[id].addr, -		 mask, value); - -	return 0; -} -  static int ab8500_regulator_register(struct platform_device *pdev,  				     struct regulator_init_data *init_data,  				     int id, struct device_node *np) @@ -3036,7 +3005,6 @@ static int ab8500_regulator_register(struct platform_device *pdev,  	struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);  	struct ab8500_regulator_info *info = NULL;  	struct regulator_config config = { }; -	int err;  	/* assign per-regulator data */  	info = &abx500_regulator.info[id]; @@ -3058,17 +3026,12 @@ static int ab8500_regulator_register(struct platform_device *pdev,  	}  	/* register regulator with framework */ -	info->regulator = regulator_register(&info->desc, &config); +	info->regulator = devm_regulator_register(&pdev->dev, &info->desc, +						&config);  	if (IS_ERR(info->regulator)) { -		err = PTR_ERR(info->regulator);  		dev_err(&pdev->dev, "failed to register regulator %s\n",  			info->desc.name); -		/* when we fail, un-register all earlier regulators */ -		while (--id >= 0) { -			info = &abx500_regulator.info[id]; -			regulator_unregister(info->regulator); -		} -		return err; +		return PTR_ERR(info->regulator);  	}  	return 0; @@ -3095,9 +3058,7 @@ static int ab8500_regulator_probe(struct platform_device *pdev)  {  	struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);  	struct device_node *np = pdev->dev.of_node; -	struct ab8500_platform_data *ppdata; -	struct ab8500_regulator_platform_data *pdata; -	int i, err; +	int err;  	if (!ab8500) {  		dev_err(&pdev->dev, "null mfd parent\n"); @@ -3106,83 +3067,20 @@ static int ab8500_regulator_probe(struct platform_device *pdev)  	abx500_get_regulator_info(ab8500); -	if (np) { -		err = of_regulator_match(&pdev->dev, np, -					 abx500_regulator.match, -					 abx500_regulator.match_size); -		if (err < 0) { -			dev_err(&pdev->dev, -				"Error parsing regulator init data: %d\n", err); -			return err; -		} - -		err = ab8500_regulator_of_probe(pdev, np); -		return err; -	} - -	ppdata = dev_get_platdata(ab8500->dev); -	if (!ppdata) { -		dev_err(&pdev->dev, "null parent pdata\n"); -		return -EINVAL; -	} - -	pdata = ppdata->regulator; -	if (!pdata) { -		dev_err(&pdev->dev, "null pdata\n"); -		return -EINVAL; -	} - -	/* make sure the platform data has the correct size */ -	if (pdata->num_regulator != abx500_regulator.info_size) { -		dev_err(&pdev->dev, "Configuration error: size mismatch.\n"); -		return -EINVAL; -	} - -	/* initialize debug (initial state is recorded with this call) */ -	err = ab8500_regulator_debug_init(pdev); -	if (err) +	err = of_regulator_match(&pdev->dev, np, +				 abx500_regulator.match, +				 abx500_regulator.match_size); +	if (err < 0) { +		dev_err(&pdev->dev, +			"Error parsing regulator init data: %d\n", err);  		return err; - -	/* initialize registers */ -	for (i = 0; i < pdata->num_reg_init; i++) { -		int id, mask, value; - -		id = pdata->reg_init[i].id; -		mask = pdata->reg_init[i].mask; -		value = pdata->reg_init[i].value; - -		/* check for configuration errors */ -		BUG_ON(id >= abx500_regulator.init_size); - -		err = ab8500_regulator_init_registers(pdev, id, mask, value); -		if (err < 0) -			return err;  	} - -	/* register all regulators */ -	for (i = 0; i < abx500_regulator.info_size; i++) { -		err = ab8500_regulator_register(pdev, &pdata->regulator[i], -						i, NULL); -		if (err < 0) -			return err; -	} - -	return 0; +	return ab8500_regulator_of_probe(pdev, np);  }  static int ab8500_regulator_remove(struct platform_device *pdev)  { -	int i, err; - -	for (i = 0; i < abx500_regulator.info_size; i++) { -		struct ab8500_regulator_info *info = NULL; -		info = &abx500_regulator.info[i]; - -		dev_vdbg(rdev_get_dev(info->regulator), -			"%s-remove\n", info->desc.name); - -		regulator_unregister(info->regulator); -	} +	int err;  	/* remove regulator debug */  	err = ab8500_regulator_debug_exit(pdev); diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c new file mode 100644 index 00000000000..b92d7dd01a1 --- /dev/null +++ b/drivers/regulator/act8865-regulator.c @@ -0,0 +1,344 @@ +/* + * act8865-regulator.c - Voltage regulation for the active-semi ACT8865 + * http://www.active-semi.com/sheets/ACT8865_Datasheet.pdf + * + * Copyright (C) 2013 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/act8865.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/regulator/of_regulator.h> +#include <linux/regmap.h> + +/* + * ACT8865 Global Register Map. + */ +#define	ACT8865_SYS_MODE	0x00 +#define	ACT8865_SYS_CTRL	0x01 +#define	ACT8865_DCDC1_VSET1	0x20 +#define	ACT8865_DCDC1_VSET2	0x21 +#define	ACT8865_DCDC1_CTRL	0x22 +#define	ACT8865_DCDC2_VSET1	0x30 +#define	ACT8865_DCDC2_VSET2	0x31 +#define	ACT8865_DCDC2_CTRL	0x32 +#define	ACT8865_DCDC3_VSET1	0x40 +#define	ACT8865_DCDC3_VSET2	0x41 +#define	ACT8865_DCDC3_CTRL	0x42 +#define	ACT8865_LDO1_VSET	0x50 +#define	ACT8865_LDO1_CTRL	0x51 +#define	ACT8865_LDO2_VSET	0x54 +#define	ACT8865_LDO2_CTRL	0x55 +#define	ACT8865_LDO3_VSET	0x60 +#define	ACT8865_LDO3_CTRL	0x61 +#define	ACT8865_LDO4_VSET	0x64 +#define	ACT8865_LDO4_CTRL	0x65 + +/* + * Field Definitions. + */ +#define	ACT8865_ENA		0x80	/* ON - [7] */ +#define	ACT8865_VSEL_MASK	0x3F	/* VSET - [5:0] */ + +/* + * ACT8865 voltage number + */ +#define	ACT8865_VOLTAGE_NUM	64 + +struct act8865 { +	struct regmap *regmap; +}; + +static const struct regmap_config act8865_regmap_config = { +	.reg_bits = 8, +	.val_bits = 8, +}; + +static const struct regulator_linear_range act8865_volatge_ranges[] = { +	REGULATOR_LINEAR_RANGE(600000, 0, 23, 25000), +	REGULATOR_LINEAR_RANGE(1200000, 24, 47, 50000), +	REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000), +}; + +static struct regulator_ops act8865_ops = { +	.list_voltage		= regulator_list_voltage_linear_range, +	.map_voltage		= regulator_map_voltage_linear_range, +	.get_voltage_sel	= regulator_get_voltage_sel_regmap, +	.set_voltage_sel	= regulator_set_voltage_sel_regmap, +	.enable			= regulator_enable_regmap, +	.disable		= regulator_disable_regmap, +	.is_enabled		= regulator_is_enabled_regmap, +}; + +static const struct regulator_desc act8865_reg[] = { +	{ +		.name = "DCDC_REG1", +		.id = ACT8865_ID_DCDC1, +		.ops = &act8865_ops, +		.type = REGULATOR_VOLTAGE, +		.n_voltages = ACT8865_VOLTAGE_NUM, +		.linear_ranges = act8865_volatge_ranges, +		.n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), +		.vsel_reg = ACT8865_DCDC1_VSET1, +		.vsel_mask = ACT8865_VSEL_MASK, +		.enable_reg = ACT8865_DCDC1_CTRL, +		.enable_mask = ACT8865_ENA, +		.owner = THIS_MODULE, +	}, +	{ +		.name = "DCDC_REG2", +		.id = ACT8865_ID_DCDC2, +		.ops = &act8865_ops, +		.type = REGULATOR_VOLTAGE, +		.n_voltages = ACT8865_VOLTAGE_NUM, +		.linear_ranges = act8865_volatge_ranges, +		.n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), +		.vsel_reg = ACT8865_DCDC2_VSET1, +		.vsel_mask = ACT8865_VSEL_MASK, +		.enable_reg = ACT8865_DCDC2_CTRL, +		.enable_mask = ACT8865_ENA, +		.owner = THIS_MODULE, +	}, +	{ +		.name = "DCDC_REG3", +		.id = ACT8865_ID_DCDC3, +		.ops = &act8865_ops, +		.type = REGULATOR_VOLTAGE, +		.n_voltages = ACT8865_VOLTAGE_NUM, +		.linear_ranges = act8865_volatge_ranges, +		.n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), +		.vsel_reg = ACT8865_DCDC3_VSET1, +		.vsel_mask = ACT8865_VSEL_MASK, +		.enable_reg = ACT8865_DCDC3_CTRL, +		.enable_mask = ACT8865_ENA, +		.owner = THIS_MODULE, +	}, +	{ +		.name = "LDO_REG1", +		.id = ACT8865_ID_LDO1, +		.ops = &act8865_ops, +		.type = REGULATOR_VOLTAGE, +		.n_voltages = ACT8865_VOLTAGE_NUM, +		.linear_ranges = act8865_volatge_ranges, +		.n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), +		.vsel_reg = ACT8865_LDO1_VSET, +		.vsel_mask = ACT8865_VSEL_MASK, +		.enable_reg = ACT8865_LDO1_CTRL, +		.enable_mask = ACT8865_ENA, +		.owner = THIS_MODULE, +	}, +	{ +		.name = "LDO_REG2", +		.id = ACT8865_ID_LDO2, +		.ops = &act8865_ops, +		.type = REGULATOR_VOLTAGE, +		.n_voltages = ACT8865_VOLTAGE_NUM, +		.linear_ranges = act8865_volatge_ranges, +		.n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), +		.vsel_reg = ACT8865_LDO2_VSET, +		.vsel_mask = ACT8865_VSEL_MASK, +		.enable_reg = ACT8865_LDO2_CTRL, +		.enable_mask = ACT8865_ENA, +		.owner = THIS_MODULE, +	}, +	{ +		.name = "LDO_REG3", +		.id = ACT8865_ID_LDO3, +		.ops = &act8865_ops, +		.type = REGULATOR_VOLTAGE, +		.n_voltages = ACT8865_VOLTAGE_NUM, +		.linear_ranges = act8865_volatge_ranges, +		.n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), +		.vsel_reg = ACT8865_LDO3_VSET, +		.vsel_mask = ACT8865_VSEL_MASK, +		.enable_reg = ACT8865_LDO3_CTRL, +		.enable_mask = ACT8865_ENA, +		.owner = THIS_MODULE, +	}, +	{ +		.name = "LDO_REG4", +		.id = ACT8865_ID_LDO4, +		.ops = &act8865_ops, +		.type = REGULATOR_VOLTAGE, +		.n_voltages = ACT8865_VOLTAGE_NUM, +		.linear_ranges = act8865_volatge_ranges, +		.n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), +		.vsel_reg = ACT8865_LDO4_VSET, +		.vsel_mask = ACT8865_VSEL_MASK, +		.enable_reg = ACT8865_LDO4_CTRL, +		.enable_mask = ACT8865_ENA, +		.owner = THIS_MODULE, +	}, +}; + +#ifdef CONFIG_OF +static const struct of_device_id act8865_dt_ids[] = { +	{ .compatible = "active-semi,act8865" }, +	{ } +}; +MODULE_DEVICE_TABLE(of, act8865_dt_ids); + +static struct of_regulator_match act8865_matches[] = { +	[ACT8865_ID_DCDC1]	= { .name = "DCDC_REG1"}, +	[ACT8865_ID_DCDC2]	= { .name = "DCDC_REG2"}, +	[ACT8865_ID_DCDC3]	= { .name = "DCDC_REG3"}, +	[ACT8865_ID_LDO1]	= { .name = "LDO_REG1"}, +	[ACT8865_ID_LDO2]	= { .name = "LDO_REG2"}, +	[ACT8865_ID_LDO3]	= { .name = "LDO_REG3"}, +	[ACT8865_ID_LDO4]	= { .name = "LDO_REG4"}, +}; + +static int act8865_pdata_from_dt(struct device *dev, +				 struct device_node **of_node, +				 struct act8865_platform_data *pdata) +{ +	int matched, i; +	struct device_node *np; +	struct act8865_regulator_data *regulator; + +	np = of_get_child_by_name(dev->of_node, "regulators"); +	if (!np) { +		dev_err(dev, "missing 'regulators' subnode in DT\n"); +		return -EINVAL; +	} + +	matched = of_regulator_match(dev, np, +				act8865_matches, ARRAY_SIZE(act8865_matches)); +	of_node_put(np); +	if (matched <= 0) +		return matched; + +	pdata->regulators = devm_kzalloc(dev, +				sizeof(struct act8865_regulator_data) * +				ARRAY_SIZE(act8865_matches), GFP_KERNEL); +	if (!pdata->regulators) +		return -ENOMEM; + +	pdata->num_regulators = matched; +	regulator = pdata->regulators; + +	for (i = 0; i < ARRAY_SIZE(act8865_matches); i++) { +		regulator->id = i; +		regulator->name = act8865_matches[i].name; +		regulator->platform_data = act8865_matches[i].init_data; +		of_node[i] = act8865_matches[i].of_node; +		regulator++; +	} + +	return 0; +} +#else +static inline int act8865_pdata_from_dt(struct device *dev, +					struct device_node **of_node, +					struct act8865_platform_data *pdata) +{ +	return 0; +} +#endif + +static int act8865_pmic_probe(struct i2c_client *client, +			   const struct i2c_device_id *i2c_id) +{ +	struct regulator_dev *rdev; +	struct device *dev = &client->dev; +	struct act8865_platform_data *pdata = dev_get_platdata(dev); +	struct regulator_config config = { }; +	struct act8865 *act8865; +	struct device_node *of_node[ACT8865_REG_NUM]; +	int i, id; +	int ret = -EINVAL; +	int error; + +	if (dev->of_node && !pdata) { +		const struct of_device_id *id; +		struct act8865_platform_data pdata_of; + +		id = of_match_device(of_match_ptr(act8865_dt_ids), dev); +		if (!id) +			return -ENODEV; + +		ret = act8865_pdata_from_dt(dev, of_node, &pdata_of); +		if (ret < 0) +			return ret; + +		pdata = &pdata_of; +	} + +	if (pdata->num_regulators > ACT8865_REG_NUM) { +		dev_err(dev, "Too many regulators found!\n"); +		return -EINVAL; +	} + +	act8865 = devm_kzalloc(dev, sizeof(struct act8865), GFP_KERNEL); +	if (!act8865) +		return -ENOMEM; + +	act8865->regmap = devm_regmap_init_i2c(client, &act8865_regmap_config); +	if (IS_ERR(act8865->regmap)) { +		error = PTR_ERR(act8865->regmap); +		dev_err(&client->dev, "Failed to allocate register map: %d\n", +			error); +		return error; +	} + +	/* Finally register devices */ +	for (i = 0; i < ACT8865_REG_NUM; i++) { + +		id = pdata->regulators[i].id; + +		config.dev = dev; +		config.init_data = pdata->regulators[i].platform_data; +		config.of_node = of_node[i]; +		config.driver_data = act8865; +		config.regmap = act8865->regmap; + +		rdev = devm_regulator_register(&client->dev, &act8865_reg[i], +					       &config); +		if (IS_ERR(rdev)) { +			dev_err(dev, "failed to register %s\n", +				act8865_reg[id].name); +			return PTR_ERR(rdev); +		} +	} + +	i2c_set_clientdata(client, act8865); + +	return 0; +} + +static const struct i2c_device_id act8865_ids[] = { +	{ "act8865", 0 }, +	{ }, +}; +MODULE_DEVICE_TABLE(i2c, act8865_ids); + +static struct i2c_driver act8865_pmic_driver = { +	.driver	= { +		.name	= "act8865", +		.owner	= THIS_MODULE, +	}, +	.probe		= act8865_pmic_probe, +	.id_table	= act8865_ids, +}; + +module_i2c_driver(act8865_pmic_driver); + +MODULE_DESCRIPTION("active-semi act8865 voltage regulator driver"); +MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c index b2b203cb6b2..48016a050d5 100644 --- a/drivers/regulator/ad5398.c +++ b/drivers/regulator/ad5398.c @@ -219,7 +219,6 @@ static int ad5398_probe(struct i2c_client *client,  	struct ad5398_chip_info *chip;  	const struct ad5398_current_data_format *df =  			(struct ad5398_current_data_format *)id->driver_data; -	int ret;  	if (!init_data)  		return -EINVAL; @@ -240,33 +239,21 @@ static int ad5398_probe(struct i2c_client *client,  	chip->current_offset = df->current_offset;  	chip->current_mask = (chip->current_level - 1) << chip->current_offset; -	chip->rdev = regulator_register(&ad5398_reg, &config); +	chip->rdev = devm_regulator_register(&client->dev, &ad5398_reg, +					     &config);  	if (IS_ERR(chip->rdev)) { -		ret = PTR_ERR(chip->rdev);  		dev_err(&client->dev, "failed to register %s %s\n",  			id->name, ad5398_reg.name); -		goto err; +		return PTR_ERR(chip->rdev);  	}  	i2c_set_clientdata(client, chip);  	dev_dbg(&client->dev, "%s regulator driver is registered.\n", id->name);  	return 0; - -err: -	return ret; -} - -static int ad5398_remove(struct i2c_client *client) -{ -	struct ad5398_chip_info *chip = i2c_get_clientdata(client); - -	regulator_unregister(chip->rdev); -	return 0;  }  static struct i2c_driver ad5398_driver = {  	.probe = ad5398_probe, -	.remove = ad5398_remove,  	.driver		= {  		.name	= "ad5398",  	}, diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 0d4a8ccbb53..4f730af70e7 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -34,6 +34,9 @@  #define LDO_RAMP_UP_UNIT_IN_CYCLES      64 /* 64 cycles per step */  #define LDO_RAMP_UP_FREQ_IN_MHZ         24 /* cycle based on 24M OSC */ +#define LDO_POWER_GATE			0x00 +#define LDO_FET_FULL_ON			0x1f +  struct anatop_regulator {  	const char *name;  	u32 control_reg; @@ -48,19 +51,10 @@ struct anatop_regulator {  	int max_voltage;  	struct regulator_desc rdesc;  	struct regulator_init_data *initdata; +	bool bypass; +	int sel;  }; -static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg, -					unsigned selector) -{ -	struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); - -	if (!anatop_reg->control_reg) -		return -ENOTSUPP; - -	return regulator_set_voltage_sel_regmap(reg, selector); -} -  static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,  	unsigned int old_sel,  	unsigned int new_sel) @@ -87,22 +81,99 @@ static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,  	return ret;  } -static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg) +static int anatop_regmap_enable(struct regulator_dev *reg)  {  	struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); +	int sel; -	if (!anatop_reg->control_reg) -		return -ENOTSUPP; +	sel = anatop_reg->bypass ? LDO_FET_FULL_ON : anatop_reg->sel; +	return regulator_set_voltage_sel_regmap(reg, sel); +} + +static int anatop_regmap_disable(struct regulator_dev *reg) +{ +	return regulator_set_voltage_sel_regmap(reg, LDO_POWER_GATE); +} + +static int anatop_regmap_is_enabled(struct regulator_dev *reg) +{ +	return regulator_get_voltage_sel_regmap(reg) != LDO_POWER_GATE; +} + +static int anatop_regmap_core_set_voltage_sel(struct regulator_dev *reg, +					      unsigned selector) +{ +	struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); +	int ret; + +	if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg)) { +		anatop_reg->sel = selector; +		return 0; +	} + +	ret = regulator_set_voltage_sel_regmap(reg, selector); +	if (!ret) +		anatop_reg->sel = selector; +	return ret; +} + +static int anatop_regmap_core_get_voltage_sel(struct regulator_dev *reg) +{ +	struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); + +	if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg)) +		return anatop_reg->sel;  	return regulator_get_voltage_sel_regmap(reg);  } +static int anatop_regmap_get_bypass(struct regulator_dev *reg, bool *enable) +{ +	struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); +	int sel; + +	sel = regulator_get_voltage_sel_regmap(reg); +	if (sel == LDO_FET_FULL_ON) +		WARN_ON(!anatop_reg->bypass); +	else if (sel != LDO_POWER_GATE) +		WARN_ON(anatop_reg->bypass); + +	*enable = anatop_reg->bypass; +	return 0; +} + +static int anatop_regmap_set_bypass(struct regulator_dev *reg, bool enable) +{ +	struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); +	int sel; + +	if (enable == anatop_reg->bypass) +		return 0; + +	sel = enable ? LDO_FET_FULL_ON : anatop_reg->sel; +	anatop_reg->bypass = enable; + +	return regulator_set_voltage_sel_regmap(reg, sel); +} +  static struct regulator_ops anatop_rops = { -	.set_voltage_sel = anatop_regmap_set_voltage_sel, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.list_voltage = regulator_list_voltage_linear, +	.map_voltage = regulator_map_voltage_linear, +}; + +static struct regulator_ops anatop_core_rops = { +	.enable = anatop_regmap_enable, +	.disable = anatop_regmap_disable, +	.is_enabled = anatop_regmap_is_enabled, +	.set_voltage_sel = anatop_regmap_core_set_voltage_sel,  	.set_voltage_time_sel = anatop_regmap_set_voltage_time_sel, -	.get_voltage_sel = anatop_regmap_get_voltage_sel, +	.get_voltage_sel = anatop_regmap_core_get_voltage_sel,  	.list_voltage = regulator_list_voltage_linear,  	.map_voltage = regulator_map_voltage_linear, +	.get_bypass = anatop_regmap_get_bypass, +	.set_bypass = anatop_regmap_set_bypass,  };  static int anatop_regulator_probe(struct platform_device *pdev) @@ -116,18 +187,16 @@ static int anatop_regulator_probe(struct platform_device *pdev)  	struct regulator_init_data *initdata;  	struct regulator_config config = { };  	int ret = 0; +	u32 val;  	initdata = of_get_regulator_init_data(dev, np);  	sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL);  	if (!sreg)  		return -ENOMEM;  	sreg->initdata = initdata; -	sreg->name = kstrdup(of_get_property(np, "regulator-name", NULL), -			     GFP_KERNEL); +	sreg->name = of_get_property(np, "regulator-name", NULL);  	rdesc = &sreg->rdesc; -	memset(rdesc, 0, sizeof(*rdesc));  	rdesc->name = sreg->name; -	rdesc->ops = &anatop_rops;  	rdesc->type = REGULATOR_VOLTAGE;  	rdesc->owner = THIS_MODULE; @@ -143,37 +212,37 @@ static int anatop_regulator_probe(struct platform_device *pdev)  				   &sreg->control_reg);  	if (ret) {  		dev_err(dev, "no anatop-reg-offset property set\n"); -		goto anatop_probe_end; +		return ret;  	}  	ret = of_property_read_u32(np, "anatop-vol-bit-width",  				   &sreg->vol_bit_width);  	if (ret) {  		dev_err(dev, "no anatop-vol-bit-width property set\n"); -		goto anatop_probe_end; +		return ret;  	}  	ret = of_property_read_u32(np, "anatop-vol-bit-shift",  				   &sreg->vol_bit_shift);  	if (ret) {  		dev_err(dev, "no anatop-vol-bit-shift property set\n"); -		goto anatop_probe_end; +		return ret;  	}  	ret = of_property_read_u32(np, "anatop-min-bit-val",  				   &sreg->min_bit_val);  	if (ret) {  		dev_err(dev, "no anatop-min-bit-val property set\n"); -		goto anatop_probe_end; +		return ret;  	}  	ret = of_property_read_u32(np, "anatop-min-voltage",  				   &sreg->min_voltage);  	if (ret) {  		dev_err(dev, "no anatop-min-voltage property set\n"); -		goto anatop_probe_end; +		return ret;  	}  	ret = of_property_read_u32(np, "anatop-max-voltage",  				   &sreg->max_voltage);  	if (ret) {  		dev_err(dev, "no anatop-max-voltage property set\n"); -		goto anatop_probe_end; +		return ret;  	}  	/* read LDO ramp up setting, only for core reg */ @@ -199,37 +268,39 @@ static int anatop_regulator_probe(struct platform_device *pdev)  	config.of_node = pdev->dev.of_node;  	config.regmap = sreg->anatop; +	/* Only core regulators have the ramp up delay configuration. */ +	if (sreg->control_reg && sreg->delay_bit_width) { +		rdesc->ops = &anatop_core_rops; + +		ret = regmap_read(config.regmap, rdesc->vsel_reg, &val); +		if (ret) { +			dev_err(dev, "failed to read initial state\n"); +			return ret; +		} + +		sreg->sel = (val & rdesc->vsel_mask) >> sreg->vol_bit_shift; +		if (sreg->sel == LDO_FET_FULL_ON) { +			sreg->sel = 0; +			sreg->bypass = true; +		} +	} else { +		rdesc->ops = &anatop_rops; +	} +  	/* register regulator */ -	rdev = regulator_register(rdesc, &config); +	rdev = devm_regulator_register(dev, rdesc, &config);  	if (IS_ERR(rdev)) {  		dev_err(dev, "failed to register %s\n",  			rdesc->name); -		ret = PTR_ERR(rdev); -		goto anatop_probe_end; +		return PTR_ERR(rdev);  	}  	platform_set_drvdata(pdev, rdev); -anatop_probe_end: -	if (ret) -		kfree(sreg->name); - -	return ret; -} - -static int anatop_regulator_remove(struct platform_device *pdev) -{ -	struct regulator_dev *rdev = platform_get_drvdata(pdev); -	struct anatop_regulator *sreg = rdev_get_drvdata(rdev); -	const char *name = sreg->name; - -	regulator_unregister(rdev); -	kfree(name); -  	return 0;  } -static struct of_device_id of_anatop_regulator_match_tbl[] = { +static const struct of_device_id of_anatop_regulator_match_tbl[] = {  	{ .compatible = "fsl,anatop-regulator", },  	{ /* end */ }  }; @@ -241,7 +312,6 @@ static struct platform_driver anatop_regulator_driver = {  		.of_match_table = of_anatop_regulator_match_tbl,  	},  	.probe	= anatop_regulator_probe, -	.remove	= anatop_regulator_remove,  };  static int __init anatop_regulator_init(void) @@ -256,7 +326,8 @@ static void __exit anatop_regulator_exit(void)  }  module_exit(anatop_regulator_exit); -MODULE_AUTHOR("Nancy Chen <Nancy.Chen@freescale.com>, " -	      "Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>"); +MODULE_AUTHOR("Nancy Chen <Nancy.Chen@freescale.com>"); +MODULE_AUTHOR("Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>");  MODULE_DESCRIPTION("ANATOP Regulator driver");  MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:anatop_regulator"); diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index 81d8681c319..04f262a836b 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -16,9 +16,11 @@  #include <linux/init.h>  #include <linux/bitops.h>  #include <linux/err.h> +#include <linux/of.h>  #include <linux/platform_device.h>  #include <linux/regulator/driver.h>  #include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h>  #include <linux/gpio.h>  #include <linux/slab.h> @@ -153,11 +155,9 @@ static const struct regulator_desc arizona_ldo1 = {  	.vsel_reg = ARIZONA_LDO1_CONTROL_1,  	.vsel_mask = ARIZONA_LDO1_VSEL_MASK, -	.bypass_reg = ARIZONA_LDO1_CONTROL_1, -	.bypass_mask = ARIZONA_LDO1_BYPASS,  	.min_uV = 900000, -	.uV_step = 50000, -	.n_voltages = 7, +	.uV_step = 25000, +	.n_voltages = 13,  	.enable_time = 500,  	.owner = THIS_MODULE, @@ -180,6 +180,42 @@ static const struct regulator_init_data arizona_ldo1_default = {  	.num_consumer_supplies = 1,  }; +static int arizona_ldo1_of_get_pdata(struct arizona *arizona, +				     struct regulator_config *config) +{ +	struct arizona_pdata *pdata = &arizona->pdata; +	struct arizona_ldo1 *ldo1 = config->driver_data; +	struct device_node *init_node, *dcvdd_node; +	struct regulator_init_data *init_data; + +	pdata->ldoena = arizona_of_get_named_gpio(arizona, "wlf,ldoena", true); + +	init_node = of_get_child_by_name(arizona->dev->of_node, "ldo1"); +	dcvdd_node = of_parse_phandle(arizona->dev->of_node, "DCVDD-supply", 0); + +	if (init_node) { +		config->of_node = init_node; + +		init_data = of_get_regulator_init_data(arizona->dev, init_node); + +		if (init_data) { +			init_data->consumer_supplies = &ldo1->supply; +			init_data->num_consumer_supplies = 1; + +			if (dcvdd_node && dcvdd_node != init_node) +				arizona->external_dcvdd = true; + +			pdata->ldo1 = init_data; +		} +	} else if (dcvdd_node) { +		arizona->external_dcvdd = true; +	} + +	of_node_put(dcvdd_node); + +	return 0; +} +  static int arizona_ldo1_probe(struct platform_device *pdev)  {  	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); @@ -188,11 +224,11 @@ static int arizona_ldo1_probe(struct platform_device *pdev)  	struct arizona_ldo1 *ldo1;  	int ret; +	arizona->external_dcvdd = false; +  	ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL); -	if (ldo1 == NULL) { -		dev_err(&pdev->dev, "Unable to allocate private data\n"); +	if (!ldo1)  		return -ENOMEM; -	}  	ldo1->arizona = arizona; @@ -203,6 +239,7 @@ static int arizona_ldo1_probe(struct platform_device *pdev)  	 */  	switch (arizona->type) {  	case WM5102: +	case WM8997:  		desc = &arizona_ldo1_hc;  		ldo1->init_data = arizona_ldo1_dvfs;  		break; @@ -219,6 +256,15 @@ static int arizona_ldo1_probe(struct platform_device *pdev)  	config.dev = arizona->dev;  	config.driver_data = ldo1;  	config.regmap = arizona->regmap; + +	if (IS_ENABLED(CONFIG_OF)) { +		if (!dev_get_platdata(arizona->dev)) { +			ret = arizona_ldo1_of_get_pdata(arizona, &config); +			if (ret < 0) +				return ret; +		} +	} +  	config.ena_gpio = arizona->pdata.ldoena;  	if (arizona->pdata.ldo1) @@ -226,7 +272,14 @@ static int arizona_ldo1_probe(struct platform_device *pdev)  	else  		config.init_data = &ldo1->init_data; -	ldo1->regulator = regulator_register(desc, &config); +	/* +	 * LDO1 can only be used to supply DCVDD so if it has no +	 * consumers then DCVDD is supplied externally. +	 */ +	if (config.init_data->num_consumer_supplies == 0) +		arizona->external_dcvdd = true; + +	ldo1->regulator = devm_regulator_register(&pdev->dev, desc, &config);  	if (IS_ERR(ldo1->regulator)) {  		ret = PTR_ERR(ldo1->regulator);  		dev_err(arizona->dev, "Failed to register LDO1 supply: %d\n", @@ -234,23 +287,15 @@ static int arizona_ldo1_probe(struct platform_device *pdev)  		return ret;  	} -	platform_set_drvdata(pdev, ldo1); - -	return 0; -} - -static int arizona_ldo1_remove(struct platform_device *pdev) -{ -	struct arizona_ldo1 *ldo1 = platform_get_drvdata(pdev); +	of_node_put(config.of_node); -	regulator_unregister(ldo1->regulator); +	platform_set_drvdata(pdev, ldo1);  	return 0;  }  static struct platform_driver arizona_ldo1_driver = {  	.probe = arizona_ldo1_probe, -	.remove = arizona_ldo1_remove,  	.driver		= {  		.name	= "arizona-ldo1",  		.owner	= THIS_MODULE, diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index e87536bf0be..ce9aca5f8ee 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c @@ -16,9 +16,11 @@  #include <linux/init.h>  #include <linux/bitops.h>  #include <linux/err.h> +#include <linux/of.h>  #include <linux/platform_device.h>  #include <linux/regulator/driver.h>  #include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h>  #include <linux/gpio.h>  #include <linux/slab.h>  #include <linux/workqueue.h> @@ -28,8 +30,6 @@  #include <linux/mfd/arizona/pdata.h>  #include <linux/mfd/arizona/registers.h> -#define ARIZONA_MICSUPP_MAX_SELECTOR 0x1f -  struct arizona_micsupp {  	struct regulator_dev *regulator;  	struct arizona *arizona; @@ -40,42 +40,6 @@ struct arizona_micsupp {  	struct work_struct check_cp_work;  }; -static int arizona_micsupp_list_voltage(struct regulator_dev *rdev, -					unsigned int selector) -{ -	if (selector > ARIZONA_MICSUPP_MAX_SELECTOR) -		return -EINVAL; - -	if (selector == ARIZONA_MICSUPP_MAX_SELECTOR) -		return 3300000; -	else -		return (selector * 50000) + 1700000; -} - -static int arizona_micsupp_map_voltage(struct regulator_dev *rdev, -				       int min_uV, int max_uV) -{ -	unsigned int voltage; -	int selector; - -	if (min_uV < 1700000) -		min_uV = 1700000; - -	if (min_uV > 3200000) -		selector = ARIZONA_MICSUPP_MAX_SELECTOR; -	else -		selector = DIV_ROUND_UP(min_uV - 1700000, 50000); - -	if (selector < 0) -		return -EINVAL; - -	voltage = arizona_micsupp_list_voltage(rdev, selector); -	if (voltage < min_uV || voltage > max_uV) -		return -EINVAL; - -	return selector; -} -  static void arizona_micsupp_check_cp(struct work_struct *work)  {  	struct arizona_micsupp *micsupp = @@ -145,8 +109,8 @@ static struct regulator_ops arizona_micsupp_ops = {  	.disable = arizona_micsupp_disable,  	.is_enabled = regulator_is_enabled_regmap, -	.list_voltage = arizona_micsupp_list_voltage, -	.map_voltage = arizona_micsupp_map_voltage, +	.list_voltage = regulator_list_voltage_linear_range, +	.map_voltage = regulator_map_voltage_linear_range,  	.get_voltage_sel = regulator_get_voltage_sel_regmap,  	.set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -155,11 +119,16 @@ static struct regulator_ops arizona_micsupp_ops = {  	.set_bypass = arizona_micsupp_set_bypass,  }; +static const struct regulator_linear_range arizona_micsupp_ranges[] = { +	REGULATOR_LINEAR_RANGE(1700000, 0,    0x1e, 50000), +	REGULATOR_LINEAR_RANGE(3300000, 0x1f, 0x1f, 0), +}; +  static const struct regulator_desc arizona_micsupp = {  	.name = "MICVDD",  	.supply_name = "CPVDD",  	.type = REGULATOR_VOLTAGE, -	.n_voltages = ARIZONA_MICSUPP_MAX_SELECTOR + 1, +	.n_voltages = 32,  	.ops = &arizona_micsupp_ops,  	.vsel_reg = ARIZONA_LDO2_CONTROL_1, @@ -169,6 +138,36 @@ static const struct regulator_desc arizona_micsupp = {  	.bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1,  	.bypass_mask = ARIZONA_CPMIC_BYPASS, +	.linear_ranges = arizona_micsupp_ranges, +	.n_linear_ranges = ARRAY_SIZE(arizona_micsupp_ranges), + +	.enable_time = 3000, + +	.owner = THIS_MODULE, +}; + +static const struct regulator_linear_range arizona_micsupp_ext_ranges[] = { +	REGULATOR_LINEAR_RANGE(900000,  0,    0x14, 25000), +	REGULATOR_LINEAR_RANGE(1500000, 0x15, 0x27, 100000), +}; + +static const struct regulator_desc arizona_micsupp_ext = { +	.name = "MICVDD", +	.supply_name = "CPVDD", +	.type = REGULATOR_VOLTAGE, +	.n_voltages = 40, +	.ops = &arizona_micsupp_ops, + +	.vsel_reg = ARIZONA_LDO2_CONTROL_1, +	.vsel_mask = ARIZONA_LDO2_VSEL_MASK, +	.enable_reg = ARIZONA_MIC_CHARGE_PUMP_1, +	.enable_mask = ARIZONA_CPMIC_ENA, +	.bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1, +	.bypass_mask = ARIZONA_CPMIC_BYPASS, + +	.linear_ranges = arizona_micsupp_ext_ranges, +	.n_linear_ranges = ARRAY_SIZE(arizona_micsupp_ext_ranges), +  	.enable_time = 3000,  	.owner = THIS_MODULE, @@ -186,18 +185,55 @@ static const struct regulator_init_data arizona_micsupp_default = {  	.num_consumer_supplies = 1,  }; +static const struct regulator_init_data arizona_micsupp_ext_default = { +	.constraints = { +		.valid_ops_mask = REGULATOR_CHANGE_STATUS | +				REGULATOR_CHANGE_VOLTAGE | +				REGULATOR_CHANGE_BYPASS, +		.min_uV = 900000, +		.max_uV = 3300000, +	}, + +	.num_consumer_supplies = 1, +}; + +static int arizona_micsupp_of_get_pdata(struct arizona *arizona, +					struct regulator_config *config) +{ +	struct arizona_pdata *pdata = &arizona->pdata; +	struct arizona_micsupp *micsupp = config->driver_data; +	struct device_node *np; +	struct regulator_init_data *init_data; + +	np = of_get_child_by_name(arizona->dev->of_node, "micvdd"); + +	if (np) { +		config->of_node = np; + +		init_data = of_get_regulator_init_data(arizona->dev, np); + +		if (init_data) { +			init_data->consumer_supplies = &micsupp->supply; +			init_data->num_consumer_supplies = 1; + +			pdata->micvdd = init_data; +		} +	} + +	return 0; +} +  static int arizona_micsupp_probe(struct platform_device *pdev)  {  	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); +	const struct regulator_desc *desc;  	struct regulator_config config = { };  	struct arizona_micsupp *micsupp;  	int ret;  	micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL); -	if (micsupp == NULL) { -		dev_err(&pdev->dev, "Unable to allocate private data\n"); +	if (!micsupp)  		return -ENOMEM; -	}  	micsupp->arizona = arizona;  	INIT_WORK(&micsupp->check_cp_work, arizona_micsupp_check_cp); @@ -207,7 +243,17 @@ static int arizona_micsupp_probe(struct platform_device *pdev)  	 * default init_data for it.  This will be overridden with  	 * platform data if provided.  	 */ -	micsupp->init_data = arizona_micsupp_default; +	switch (arizona->type) { +	case WM5110: +		desc = &arizona_micsupp_ext; +		micsupp->init_data = arizona_micsupp_ext_default; +		break; +	default: +		desc = &arizona_micsupp; +		micsupp->init_data = arizona_micsupp_default; +		break; +	} +  	micsupp->init_data.consumer_supplies = &micsupp->supply;  	micsupp->supply.supply = "MICVDD";  	micsupp->supply.dev_name = dev_name(arizona->dev); @@ -216,6 +262,14 @@ static int arizona_micsupp_probe(struct platform_device *pdev)  	config.driver_data = micsupp;  	config.regmap = arizona->regmap; +	if (IS_ENABLED(CONFIG_OF)) { +		if (!dev_get_platdata(arizona->dev)) { +			ret = arizona_micsupp_of_get_pdata(arizona, &config); +			if (ret < 0) +				return ret; +		} +	} +  	if (arizona->pdata.micvdd)  		config.init_data = arizona->pdata.micvdd;  	else @@ -225,7 +279,9 @@ static int arizona_micsupp_probe(struct platform_device *pdev)  	regmap_update_bits(arizona->regmap, ARIZONA_MIC_CHARGE_PUMP_1,  			   ARIZONA_CPMIC_BYPASS, 0); -	micsupp->regulator = regulator_register(&arizona_micsupp, &config); +	micsupp->regulator = devm_regulator_register(&pdev->dev, +						     desc, +						     &config);  	if (IS_ERR(micsupp->regulator)) {  		ret = PTR_ERR(micsupp->regulator);  		dev_err(arizona->dev, "Failed to register mic supply: %d\n", @@ -233,23 +289,15 @@ static int arizona_micsupp_probe(struct platform_device *pdev)  		return ret;  	} -	platform_set_drvdata(pdev, micsupp); - -	return 0; -} - -static int arizona_micsupp_remove(struct platform_device *pdev) -{ -	struct arizona_micsupp *micsupp = platform_get_drvdata(pdev); +	of_node_put(config.of_node); -	regulator_unregister(micsupp->regulator); +	platform_set_drvdata(pdev, micsupp);  	return 0;  }  static struct platform_driver arizona_micsupp_driver = {  	.probe = arizona_micsupp_probe, -	.remove = arizona_micsupp_remove,  	.driver		= {  		.name	= "arizona-micsupp",  		.owner	= THIS_MODULE, diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c index 8406cd745da..b47283f91e2 100644 --- a/drivers/regulator/as3711-regulator.c +++ b/drivers/regulator/as3711-regulator.c @@ -117,26 +117,19 @@ static struct regulator_ops as3711_dldo_ops = {  };  static const struct regulator_linear_range as3711_sd_ranges[] = { -	{ .min_uV = 612500, .max_uV = 1400000, -	  .min_sel = 0x1, .max_sel = 0x40, .uV_step = 12500 }, -	{ .min_uV = 1425000, .max_uV = 2600000, -	  .min_sel = 0x41, .max_sel = 0x70, .uV_step = 25000 }, -	{ .min_uV = 2650000, .max_uV = 3350000, -	  .min_sel = 0x71, .max_sel = 0x7f, .uV_step = 50000 }, +	REGULATOR_LINEAR_RANGE(612500, 0x1, 0x40, 12500), +	REGULATOR_LINEAR_RANGE(1425000, 0x41, 0x70, 25000), +	REGULATOR_LINEAR_RANGE(2650000, 0x71, 0x7f, 50000),  };  static const struct regulator_linear_range as3711_aldo_ranges[] = { -	{ .min_uV = 1200000, .max_uV = 1950000, -	  .min_sel = 0, .max_sel = 0xf, .uV_step = 50000 }, -	{ .min_uV = 1800000, .max_uV = 3300000, -	  .min_sel = 0x10, .max_sel = 0x1f, .uV_step = 100000 }, +	REGULATOR_LINEAR_RANGE(1200000, 0, 0xf, 50000), +	REGULATOR_LINEAR_RANGE(1800000, 0x10, 0x1f, 100000),  };  static const struct regulator_linear_range as3711_dldo_ranges[] = { -	{ .min_uV = 900000, .max_uV = 1700000, -	  .min_sel = 0, .max_sel = 0x10, .uV_step = 50000 }, -	{ .min_uV = 1750000, .max_uV = 3300000, -	  .min_sel = 0x20, .max_sel = 0x3f, .uV_step = 50000 }, +	REGULATOR_LINEAR_RANGE(900000, 0, 0x10, 50000), +	REGULATOR_LINEAR_RANGE(1750000, 0x20, 0x3f, 50000),  };  #define AS3711_REG(_id, _en_reg, _en_bit, _vmask, _vshift, _min_uV, _max_uV, _sfx)	\ @@ -198,7 +191,7 @@ static int as3711_regulator_parse_dt(struct device *dev,  {  	struct as3711_regulator_pdata *pdata = dev_get_platdata(dev);  	struct device_node *regulators = -		of_find_node_by_name(dev->parent->of_node, "regulators"); +		of_get_child_by_name(dev->parent->of_node, "regulators");  	struct of_regulator_match *match;  	int ret, i; @@ -228,7 +221,6 @@ static int as3711_regulator_probe(struct platform_device *pdev)  {  	struct as3711_regulator_pdata *pdata = dev_get_platdata(&pdev->dev);  	struct as3711 *as3711 = dev_get_drvdata(pdev->dev.parent); -	struct regulator_init_data *reg_data;  	struct regulator_config config = {.dev = &pdev->dev,};  	struct as3711_regulator *reg = NULL;  	struct as3711_regulator *regs; @@ -253,53 +245,28 @@ static int as3711_regulator_probe(struct platform_device *pdev)  	regs = devm_kzalloc(&pdev->dev, AS3711_REGULATOR_NUM *  			sizeof(struct as3711_regulator), GFP_KERNEL); -	if (!regs) { -		dev_err(&pdev->dev, "Memory allocation failed exiting..\n"); +	if (!regs)  		return -ENOMEM; -	}  	for (id = 0, ri = as3711_reg_info; id < AS3711_REGULATOR_NUM; ++id, ri++) { -		reg_data = pdata->init_data[id]; - -		/* No need to register if there is no regulator data */ -		if (!reg_data) -			continue; -  		reg = ®s[id];  		reg->reg_info = ri; -		config.init_data = reg_data; +		config.init_data = pdata->init_data[id];  		config.driver_data = reg;  		config.regmap = as3711->regmap;  		config.of_node = of_node[id]; -		rdev = regulator_register(&ri->desc, &config); +		rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config);  		if (IS_ERR(rdev)) {  			dev_err(&pdev->dev, "Failed to register regulator %s\n",  				ri->desc.name); -			ret = PTR_ERR(rdev); -			goto eregreg; +			return PTR_ERR(rdev);  		}  		reg->rdev = rdev;  	}  	platform_set_drvdata(pdev, regs);  	return 0; - -eregreg: -	while (--id >= 0) -		regulator_unregister(regs[id].rdev); - -	return ret; -} - -static int as3711_regulator_remove(struct platform_device *pdev) -{ -	struct as3711_regulator *regs = platform_get_drvdata(pdev); -	int id; - -	for (id = 0; id < AS3711_REGULATOR_NUM; ++id) -		regulator_unregister(regs[id].rdev); -	return 0;  }  static struct platform_driver as3711_regulator_driver = { @@ -308,7 +275,6 @@ static struct platform_driver as3711_regulator_driver = {  		.owner	= THIS_MODULE,  	},  	.probe		= as3711_regulator_probe, -	.remove		= as3711_regulator_remove,  };  static int __init as3711_regulator_init(void) diff --git a/drivers/regulator/as3722-regulator.c b/drivers/regulator/as3722-regulator.c new file mode 100644 index 00000000000..ad9e0c9b7da --- /dev/null +++ b/drivers/regulator/as3722-regulator.c @@ -0,0 +1,931 @@ +/* + * Voltage regulator support for AMS AS3722 PMIC + * + * Copyright (C) 2013 ams + * + * Author: Florian Lobmaier <florian.lobmaier@ams.com> + * Author: Laxman Dewangan <ldewangan@nvidia.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA + * + */ + +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mfd/as3722.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/slab.h> + +/* Regulator IDs */ +enum as3722_regulators_id { +	AS3722_REGULATOR_ID_SD0, +	AS3722_REGULATOR_ID_SD1, +	AS3722_REGULATOR_ID_SD2, +	AS3722_REGULATOR_ID_SD3, +	AS3722_REGULATOR_ID_SD4, +	AS3722_REGULATOR_ID_SD5, +	AS3722_REGULATOR_ID_SD6, +	AS3722_REGULATOR_ID_LDO0, +	AS3722_REGULATOR_ID_LDO1, +	AS3722_REGULATOR_ID_LDO2, +	AS3722_REGULATOR_ID_LDO3, +	AS3722_REGULATOR_ID_LDO4, +	AS3722_REGULATOR_ID_LDO5, +	AS3722_REGULATOR_ID_LDO6, +	AS3722_REGULATOR_ID_LDO7, +	AS3722_REGULATOR_ID_LDO9, +	AS3722_REGULATOR_ID_LDO10, +	AS3722_REGULATOR_ID_LDO11, +	AS3722_REGULATOR_ID_MAX, +}; + +struct as3722_register_mapping { +	u8 regulator_id; +	const char *name; +	const char *sname; +	u8 vsel_reg; +	u8 vsel_mask; +	int n_voltages; +	u32 enable_reg; +	u8 enable_mask; +	u32 control_reg; +	u8 mode_mask; +	u32 sleep_ctrl_reg; +	u8 sleep_ctrl_mask; +}; + +struct as3722_regulator_config_data { +	struct regulator_init_data *reg_init; +	bool enable_tracking; +	int ext_control; +}; + +struct as3722_regulators { +	struct device *dev; +	struct as3722 *as3722; +	struct regulator_dev *rdevs[AS3722_REGULATOR_ID_MAX]; +	struct regulator_desc desc[AS3722_REGULATOR_ID_MAX]; +	struct as3722_regulator_config_data +			reg_config_data[AS3722_REGULATOR_ID_MAX]; +}; + +static const struct as3722_register_mapping as3722_reg_lookup[] = { +	{ +		.regulator_id = AS3722_REGULATOR_ID_SD0, +		.name = "as3722-sd0", +		.vsel_reg = AS3722_SD0_VOLTAGE_REG, +		.vsel_mask = AS3722_SD_VSEL_MASK, +		.enable_reg = AS3722_SD_CONTROL_REG, +		.enable_mask = AS3722_SDn_CTRL(0), +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL1_REG, +		.sleep_ctrl_mask = AS3722_SD0_EXT_ENABLE_MASK, +		.control_reg = AS3722_SD0_CONTROL_REG, +		.mode_mask = AS3722_SD0_MODE_FAST, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_SD1, +		.name = "as3722-sd1", +		.vsel_reg = AS3722_SD1_VOLTAGE_REG, +		.vsel_mask = AS3722_SD_VSEL_MASK, +		.enable_reg = AS3722_SD_CONTROL_REG, +		.enable_mask = AS3722_SDn_CTRL(1), +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL1_REG, +		.sleep_ctrl_mask = AS3722_SD1_EXT_ENABLE_MASK, +		.control_reg = AS3722_SD1_CONTROL_REG, +		.mode_mask = AS3722_SD1_MODE_FAST, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_SD2, +		.name = "as3722-sd2", +		.sname = "vsup-sd2", +		.vsel_reg = AS3722_SD2_VOLTAGE_REG, +		.vsel_mask = AS3722_SD_VSEL_MASK, +		.enable_reg = AS3722_SD_CONTROL_REG, +		.enable_mask = AS3722_SDn_CTRL(2), +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL1_REG, +		.sleep_ctrl_mask = AS3722_SD2_EXT_ENABLE_MASK, +		.control_reg = AS3722_SD23_CONTROL_REG, +		.mode_mask = AS3722_SD2_MODE_FAST, +		.n_voltages = AS3722_SD2_VSEL_MAX + 1, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_SD3, +		.name = "as3722-sd3", +		.sname = "vsup-sd3", +		.vsel_reg = AS3722_SD3_VOLTAGE_REG, +		.vsel_mask = AS3722_SD_VSEL_MASK, +		.enable_reg = AS3722_SD_CONTROL_REG, +		.enable_mask = AS3722_SDn_CTRL(3), +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL1_REG, +		.sleep_ctrl_mask = AS3722_SD3_EXT_ENABLE_MASK, +		.control_reg = AS3722_SD23_CONTROL_REG, +		.mode_mask = AS3722_SD3_MODE_FAST, +		.n_voltages = AS3722_SD2_VSEL_MAX + 1, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_SD4, +		.name = "as3722-sd4", +		.sname = "vsup-sd4", +		.vsel_reg = AS3722_SD4_VOLTAGE_REG, +		.vsel_mask = AS3722_SD_VSEL_MASK, +		.enable_reg = AS3722_SD_CONTROL_REG, +		.enable_mask = AS3722_SDn_CTRL(4), +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL2_REG, +		.sleep_ctrl_mask = AS3722_SD4_EXT_ENABLE_MASK, +		.control_reg = AS3722_SD4_CONTROL_REG, +		.mode_mask = AS3722_SD4_MODE_FAST, +		.n_voltages = AS3722_SD2_VSEL_MAX + 1, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_SD5, +		.name = "as3722-sd5", +		.sname = "vsup-sd5", +		.vsel_reg = AS3722_SD5_VOLTAGE_REG, +		.vsel_mask = AS3722_SD_VSEL_MASK, +		.enable_reg = AS3722_SD_CONTROL_REG, +		.enable_mask = AS3722_SDn_CTRL(5), +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL2_REG, +		.sleep_ctrl_mask = AS3722_SD5_EXT_ENABLE_MASK, +		.control_reg = AS3722_SD5_CONTROL_REG, +		.mode_mask = AS3722_SD5_MODE_FAST, +		.n_voltages = AS3722_SD2_VSEL_MAX + 1, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_SD6, +		.name = "as3722-sd6", +		.vsel_reg = AS3722_SD6_VOLTAGE_REG, +		.vsel_mask = AS3722_SD_VSEL_MASK, +		.enable_reg = AS3722_SD_CONTROL_REG, +		.enable_mask = AS3722_SDn_CTRL(6), +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL2_REG, +		.sleep_ctrl_mask = AS3722_SD6_EXT_ENABLE_MASK, +		.control_reg = AS3722_SD6_CONTROL_REG, +		.mode_mask = AS3722_SD6_MODE_FAST, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_LDO0, +		.name = "as3722-ldo0", +		.sname = "vin-ldo0", +		.vsel_reg = AS3722_LDO0_VOLTAGE_REG, +		.vsel_mask = AS3722_LDO0_VSEL_MASK, +		.enable_reg = AS3722_LDOCONTROL0_REG, +		.enable_mask = AS3722_LDO0_CTRL, +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL3_REG, +		.sleep_ctrl_mask = AS3722_LDO0_EXT_ENABLE_MASK, +		.n_voltages = AS3722_LDO0_NUM_VOLT, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_LDO1, +		.name = "as3722-ldo1", +		.sname = "vin-ldo1-6", +		.vsel_reg = AS3722_LDO1_VOLTAGE_REG, +		.vsel_mask = AS3722_LDO_VSEL_MASK, +		.enable_reg = AS3722_LDOCONTROL0_REG, +		.enable_mask = AS3722_LDO1_CTRL, +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL3_REG, +		.sleep_ctrl_mask = AS3722_LDO1_EXT_ENABLE_MASK, +		.n_voltages = AS3722_LDO_NUM_VOLT, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_LDO2, +		.name = "as3722-ldo2", +		.sname = "vin-ldo2-5-7", +		.vsel_reg = AS3722_LDO2_VOLTAGE_REG, +		.vsel_mask = AS3722_LDO_VSEL_MASK, +		.enable_reg = AS3722_LDOCONTROL0_REG, +		.enable_mask = AS3722_LDO2_CTRL, +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL3_REG, +		.sleep_ctrl_mask = AS3722_LDO2_EXT_ENABLE_MASK, +		.n_voltages = AS3722_LDO_NUM_VOLT, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_LDO3, +		.name = "as3722-ldo3", +		.name = "vin-ldo3-4", +		.vsel_reg = AS3722_LDO3_VOLTAGE_REG, +		.vsel_mask = AS3722_LDO3_VSEL_MASK, +		.enable_reg = AS3722_LDOCONTROL0_REG, +		.enable_mask = AS3722_LDO3_CTRL, +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL3_REG, +		.sleep_ctrl_mask = AS3722_LDO3_EXT_ENABLE_MASK, +		.n_voltages = AS3722_LDO3_NUM_VOLT, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_LDO4, +		.name = "as3722-ldo4", +		.name = "vin-ldo3-4", +		.vsel_reg = AS3722_LDO4_VOLTAGE_REG, +		.vsel_mask = AS3722_LDO_VSEL_MASK, +		.enable_reg = AS3722_LDOCONTROL0_REG, +		.enable_mask = AS3722_LDO4_CTRL, +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL4_REG, +		.sleep_ctrl_mask = AS3722_LDO4_EXT_ENABLE_MASK, +		.n_voltages = AS3722_LDO_NUM_VOLT, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_LDO5, +		.name = "as3722-ldo5", +		.sname = "vin-ldo2-5-7", +		.vsel_reg = AS3722_LDO5_VOLTAGE_REG, +		.vsel_mask = AS3722_LDO_VSEL_MASK, +		.enable_reg = AS3722_LDOCONTROL0_REG, +		.enable_mask = AS3722_LDO5_CTRL, +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL4_REG, +		.sleep_ctrl_mask = AS3722_LDO5_EXT_ENABLE_MASK, +		.n_voltages = AS3722_LDO_NUM_VOLT, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_LDO6, +		.name = "as3722-ldo6", +		.sname = "vin-ldo1-6", +		.vsel_reg = AS3722_LDO6_VOLTAGE_REG, +		.vsel_mask = AS3722_LDO_VSEL_MASK, +		.enable_reg = AS3722_LDOCONTROL0_REG, +		.enable_mask = AS3722_LDO6_CTRL, +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL4_REG, +		.sleep_ctrl_mask = AS3722_LDO6_EXT_ENABLE_MASK, +		.n_voltages = AS3722_LDO_NUM_VOLT, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_LDO7, +		.name = "as3722-ldo7", +		.sname = "vin-ldo2-5-7", +		.vsel_reg = AS3722_LDO7_VOLTAGE_REG, +		.vsel_mask = AS3722_LDO_VSEL_MASK, +		.enable_reg = AS3722_LDOCONTROL0_REG, +		.enable_mask = AS3722_LDO7_CTRL, +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL4_REG, +		.sleep_ctrl_mask = AS3722_LDO7_EXT_ENABLE_MASK, +		.n_voltages = AS3722_LDO_NUM_VOLT, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_LDO9, +		.name = "as3722-ldo9", +		.sname = "vin-ldo9-10", +		.vsel_reg = AS3722_LDO9_VOLTAGE_REG, +		.vsel_mask = AS3722_LDO_VSEL_MASK, +		.enable_reg = AS3722_LDOCONTROL1_REG, +		.enable_mask = AS3722_LDO9_CTRL, +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL5_REG, +		.sleep_ctrl_mask = AS3722_LDO9_EXT_ENABLE_MASK, +		.n_voltages = AS3722_LDO_NUM_VOLT, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_LDO10, +		.name = "as3722-ldo10", +		.sname = "vin-ldo9-10", +		.vsel_reg = AS3722_LDO10_VOLTAGE_REG, +		.vsel_mask = AS3722_LDO_VSEL_MASK, +		.enable_reg = AS3722_LDOCONTROL1_REG, +		.enable_mask = AS3722_LDO10_CTRL, +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL5_REG, +		.sleep_ctrl_mask = AS3722_LDO10_EXT_ENABLE_MASK, +		.n_voltages = AS3722_LDO_NUM_VOLT, +	}, +	{ +		.regulator_id = AS3722_REGULATOR_ID_LDO11, +		.name = "as3722-ldo11", +		.sname = "vin-ldo11", +		.vsel_reg = AS3722_LDO11_VOLTAGE_REG, +		.vsel_mask = AS3722_LDO_VSEL_MASK, +		.enable_reg = AS3722_LDOCONTROL1_REG, +		.enable_mask = AS3722_LDO11_CTRL, +		.sleep_ctrl_reg = AS3722_ENABLE_CTRL5_REG, +		.sleep_ctrl_mask = AS3722_LDO11_EXT_ENABLE_MASK, +		.n_voltages = AS3722_LDO_NUM_VOLT, +	}, +}; + + +static const int as3722_ldo_current[] = { 150000, 300000 }; +static const int as3722_sd016_current[] = { 2500000, 3000000, 3500000 }; + +static int as3722_current_to_index(int min_uA, int max_uA, +		const int *curr_table, int n_currents) +{ +	int i; + +	for (i = n_currents - 1; i >= 0; i--) { +		if ((min_uA <= curr_table[i]) && (curr_table[i] <= max_uA)) +			return i; +	} +	return -EINVAL; +} + +static int as3722_ldo_get_current_limit(struct regulator_dev *rdev) +{ +	struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); +	struct as3722 *as3722 = as3722_regs->as3722; +	int id = rdev_get_id(rdev); +	u32 val; +	int ret; + +	ret = as3722_read(as3722, as3722_reg_lookup[id].vsel_reg, &val); +	if (ret < 0) { +		dev_err(as3722_regs->dev, "Reg 0x%02x read failed: %d\n", +			as3722_reg_lookup[id].vsel_reg, ret); +		return ret; +	} +	if (val & AS3722_LDO_ILIMIT_MASK) +		return 300000; +	return 150000; +} + +static int as3722_ldo_set_current_limit(struct regulator_dev *rdev, +		int min_uA, int max_uA) +{ +	struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); +	struct as3722 *as3722 = as3722_regs->as3722; +	int id = rdev_get_id(rdev); +	int ret; +	u32 reg = 0; + +	ret = as3722_current_to_index(min_uA, max_uA, as3722_ldo_current, +				ARRAY_SIZE(as3722_ldo_current)); +	if (ret < 0) { +		dev_err(as3722_regs->dev, +			"Current range min:max = %d:%d does not support\n", +			min_uA, max_uA); +		return ret; +	} +	if (ret) +		reg = AS3722_LDO_ILIMIT_BIT; +	return as3722_update_bits(as3722, as3722_reg_lookup[id].vsel_reg, +			AS3722_LDO_ILIMIT_MASK, reg); +} + +static struct regulator_ops as3722_ldo0_ops = { +	.is_enabled = regulator_is_enabled_regmap, +	.enable = regulator_enable_regmap, +	.disable = regulator_disable_regmap, +	.list_voltage = regulator_list_voltage_linear, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.get_current_limit = as3722_ldo_get_current_limit, +	.set_current_limit = as3722_ldo_set_current_limit, +}; + +static struct regulator_ops as3722_ldo0_extcntrl_ops = { +	.list_voltage = regulator_list_voltage_linear, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.get_current_limit = as3722_ldo_get_current_limit, +	.set_current_limit = as3722_ldo_set_current_limit, +}; + +static int as3722_ldo3_set_tracking_mode(struct as3722_regulators *as3722_reg, +		int id, u8 mode) +{ +	struct as3722 *as3722 = as3722_reg->as3722; + +	switch (mode) { +	case AS3722_LDO3_MODE_PMOS: +	case AS3722_LDO3_MODE_PMOS_TRACKING: +	case AS3722_LDO3_MODE_NMOS: +	case AS3722_LDO3_MODE_SWITCH: +		return as3722_update_bits(as3722, +			as3722_reg_lookup[id].vsel_reg, +			AS3722_LDO3_MODE_MASK, mode); + +	default: +		return -EINVAL; +	} +} + +static int as3722_ldo3_get_current_limit(struct regulator_dev *rdev) +{ +	return 150000; +} + +static struct regulator_ops as3722_ldo3_ops = { +	.is_enabled = regulator_is_enabled_regmap, +	.enable = regulator_enable_regmap, +	.disable = regulator_disable_regmap, +	.list_voltage = regulator_list_voltage_linear, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.get_current_limit = as3722_ldo3_get_current_limit, +}; + +static struct regulator_ops as3722_ldo3_extcntrl_ops = { +	.list_voltage = regulator_list_voltage_linear, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.get_current_limit = as3722_ldo3_get_current_limit, +}; + +static const struct regulator_linear_range as3722_ldo_ranges[] = { +	REGULATOR_LINEAR_RANGE(0, 0x00, 0x00, 0), +	REGULATOR_LINEAR_RANGE(825000, 0x01, 0x24, 25000), +	REGULATOR_LINEAR_RANGE(1725000, 0x40, 0x7F, 25000), +}; + +static struct regulator_ops as3722_ldo_ops = { +	.is_enabled = regulator_is_enabled_regmap, +	.enable = regulator_enable_regmap, +	.disable = regulator_disable_regmap, +	.map_voltage = regulator_map_voltage_linear_range, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.list_voltage = regulator_list_voltage_linear_range, +	.get_current_limit = as3722_ldo_get_current_limit, +	.set_current_limit = as3722_ldo_set_current_limit, +}; + +static struct regulator_ops as3722_ldo_extcntrl_ops = { +	.map_voltage = regulator_map_voltage_linear_range, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.list_voltage = regulator_list_voltage_linear_range, +	.get_current_limit = as3722_ldo_get_current_limit, +	.set_current_limit = as3722_ldo_set_current_limit, +}; + +static unsigned int as3722_sd_get_mode(struct regulator_dev *rdev) +{ +	struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); +	struct as3722 *as3722 = as3722_regs->as3722; +	int id = rdev_get_id(rdev); +	u32 val; +	int ret; + +	if (!as3722_reg_lookup[id].control_reg) +		return -ENOTSUPP; + +	ret = as3722_read(as3722, as3722_reg_lookup[id].control_reg, &val); +	if (ret < 0) { +		dev_err(as3722_regs->dev, "Reg 0x%02x read failed: %d\n", +			as3722_reg_lookup[id].control_reg, ret); +		return ret; +	} + +	if (val & as3722_reg_lookup[id].mode_mask) +		return REGULATOR_MODE_FAST; +	else +		return REGULATOR_MODE_NORMAL; +} + +static int as3722_sd_set_mode(struct regulator_dev *rdev, +		unsigned int mode) +{ +	struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); +	struct as3722 *as3722 = as3722_regs->as3722; +	u8 id = rdev_get_id(rdev); +	u8 val = 0; +	int ret; + +	if (!as3722_reg_lookup[id].control_reg) +		return -ERANGE; + +	switch (mode) { +	case REGULATOR_MODE_FAST: +		val = as3722_reg_lookup[id].mode_mask; +	case REGULATOR_MODE_NORMAL: /* fall down */ +		break; +	default: +		return -EINVAL; +	} + +	ret = as3722_update_bits(as3722, as3722_reg_lookup[id].control_reg, +			as3722_reg_lookup[id].mode_mask, val); +	if (ret < 0) { +		dev_err(as3722_regs->dev, "Reg 0x%02x update failed: %d\n", +			as3722_reg_lookup[id].control_reg, ret); +		return ret; +	} +	return ret; +} + +static int as3722_sd016_get_current_limit(struct regulator_dev *rdev) +{ +	struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); +	struct as3722 *as3722 = as3722_regs->as3722; +	int id = rdev_get_id(rdev); +	u32 val, reg; +	int mask; +	int ret; + +	switch (id) { +	case AS3722_REGULATOR_ID_SD0: +		reg = AS3722_OVCURRENT_REG; +		mask = AS3722_OVCURRENT_SD0_TRIP_MASK; +		break; +	case AS3722_REGULATOR_ID_SD1: +		reg = AS3722_OVCURRENT_REG; +		mask = AS3722_OVCURRENT_SD1_TRIP_MASK; +		break; +	case AS3722_REGULATOR_ID_SD6: +		reg = AS3722_OVCURRENT_DEB_REG; +		mask = AS3722_OVCURRENT_SD6_TRIP_MASK; +		break; +	default: +		return -EINVAL; +	} +	ret = as3722_read(as3722, reg, &val); +	if (ret < 0) { +		dev_err(as3722_regs->dev, "Reg 0x%02x read failed: %d\n", +			reg, ret); +		return ret; +	} +	val &= mask; +	val >>= ffs(mask) - 1; +	if (val == 3) +		return -EINVAL; +	return as3722_sd016_current[val]; +} + +static int as3722_sd016_set_current_limit(struct regulator_dev *rdev, +		int min_uA, int max_uA) +{ +	struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); +	struct as3722 *as3722 = as3722_regs->as3722; +	int id = rdev_get_id(rdev); +	int ret; +	int val; +	int mask; +	u32 reg; + +	ret = as3722_current_to_index(min_uA, max_uA, as3722_sd016_current, +				ARRAY_SIZE(as3722_sd016_current)); +	if (ret < 0) { +		dev_err(as3722_regs->dev, +			"Current range min:max = %d:%d does not support\n", +			min_uA, max_uA); +		return ret; +	} + +	switch (id) { +	case AS3722_REGULATOR_ID_SD0: +		reg = AS3722_OVCURRENT_REG; +		mask = AS3722_OVCURRENT_SD0_TRIP_MASK; +		break; +	case AS3722_REGULATOR_ID_SD1: +		reg = AS3722_OVCURRENT_REG; +		mask = AS3722_OVCURRENT_SD1_TRIP_MASK; +		break; +	case AS3722_REGULATOR_ID_SD6: +		reg = AS3722_OVCURRENT_DEB_REG; +		mask = AS3722_OVCURRENT_SD6_TRIP_MASK; +		break; +	default: +		return -EINVAL; +	} +	ret <<= ffs(mask) - 1; +	val = ret & mask; +	return as3722_update_bits(as3722, reg, mask, val); +} + +static bool as3722_sd0_is_low_voltage(struct as3722_regulators *as3722_regs) +{ +	int err; +	unsigned val; + +	err = as3722_read(as3722_regs->as3722, AS3722_FUSE7_REG, &val); +	if (err < 0) { +		dev_err(as3722_regs->dev, "Reg 0x%02x read failed: %d\n", +			AS3722_FUSE7_REG, err); +		return false; +	} +	if (val & AS3722_FUSE7_SD0_LOW_VOLTAGE) +		return true; +	return false; +} + +static const struct regulator_linear_range as3722_sd2345_ranges[] = { +	REGULATOR_LINEAR_RANGE(0, 0x00, 0x00, 0), +	REGULATOR_LINEAR_RANGE(612500, 0x01, 0x40, 12500), +	REGULATOR_LINEAR_RANGE(1425000, 0x41, 0x70, 25000), +	REGULATOR_LINEAR_RANGE(2650000, 0x71, 0x7F, 50000), +}; + +static struct regulator_ops as3722_sd016_ops = { +	.is_enabled = regulator_is_enabled_regmap, +	.enable = regulator_enable_regmap, +	.disable = regulator_disable_regmap, +	.list_voltage = regulator_list_voltage_linear, +	.map_voltage = regulator_map_voltage_linear, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.get_current_limit = as3722_sd016_get_current_limit, +	.set_current_limit = as3722_sd016_set_current_limit, +	.get_mode = as3722_sd_get_mode, +	.set_mode = as3722_sd_set_mode, +}; + +static struct regulator_ops as3722_sd016_extcntrl_ops = { +	.list_voltage = regulator_list_voltage_linear, +	.map_voltage = regulator_map_voltage_linear, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.get_current_limit = as3722_sd016_get_current_limit, +	.set_current_limit = as3722_sd016_set_current_limit, +	.get_mode = as3722_sd_get_mode, +	.set_mode = as3722_sd_set_mode, +}; + +static struct regulator_ops as3722_sd2345_ops = { +	.is_enabled = regulator_is_enabled_regmap, +	.enable = regulator_enable_regmap, +	.disable = regulator_disable_regmap, +	.list_voltage = regulator_list_voltage_linear_range, +	.map_voltage = regulator_map_voltage_linear_range, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.get_mode = as3722_sd_get_mode, +	.set_mode = as3722_sd_set_mode, +}; + +static struct regulator_ops as3722_sd2345_extcntrl_ops = { +	.list_voltage = regulator_list_voltage_linear_range, +	.map_voltage = regulator_map_voltage_linear_range, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.get_mode = as3722_sd_get_mode, +	.set_mode = as3722_sd_set_mode, +}; + +static int as3722_extreg_init(struct as3722_regulators *as3722_regs, int id, +		int ext_pwr_ctrl) +{ +	int ret; +	unsigned int val; + +	if ((ext_pwr_ctrl < AS3722_EXT_CONTROL_ENABLE1) || +		(ext_pwr_ctrl > AS3722_EXT_CONTROL_ENABLE3)) +		return -EINVAL; + +	val =  ext_pwr_ctrl << (ffs(as3722_reg_lookup[id].sleep_ctrl_mask) - 1); +	ret = as3722_update_bits(as3722_regs->as3722, +			as3722_reg_lookup[id].sleep_ctrl_reg, +			as3722_reg_lookup[id].sleep_ctrl_mask, val); +	if (ret < 0) +		dev_err(as3722_regs->dev, "Reg 0x%02x update failed: %d\n", +			as3722_reg_lookup[id].sleep_ctrl_reg, ret); +	return ret; +} + +static struct of_regulator_match as3722_regulator_matches[] = { +	{ .name = "sd0", }, +	{ .name = "sd1", }, +	{ .name = "sd2", }, +	{ .name = "sd3", }, +	{ .name = "sd4", }, +	{ .name = "sd5", }, +	{ .name = "sd6", }, +	{ .name = "ldo0", }, +	{ .name = "ldo1", }, +	{ .name = "ldo2", }, +	{ .name = "ldo3", }, +	{ .name = "ldo4", }, +	{ .name = "ldo5", }, +	{ .name = "ldo6", }, +	{ .name = "ldo7", }, +	{ .name = "ldo9", }, +	{ .name = "ldo10", }, +	{ .name = "ldo11", }, +}; + +static int as3722_get_regulator_dt_data(struct platform_device *pdev, +		struct as3722_regulators *as3722_regs) +{ +	struct device_node *np; +	struct as3722_regulator_config_data *reg_config; +	u32 prop; +	int id; +	int ret; + +	np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); +	if (!np) { +		dev_err(&pdev->dev, "Device is not having regulators node\n"); +		return -ENODEV; +	} +	pdev->dev.of_node = np; + +	ret = of_regulator_match(&pdev->dev, np, as3722_regulator_matches, +			ARRAY_SIZE(as3722_regulator_matches)); +	of_node_put(np); +	if (ret < 0) { +		dev_err(&pdev->dev, "Parsing of regulator node failed: %d\n", +			ret); +		return ret; +	} + +	for (id = 0; id < ARRAY_SIZE(as3722_regulator_matches); ++id) { +		struct device_node *reg_node; + +		reg_config = &as3722_regs->reg_config_data[id]; +		reg_config->reg_init = as3722_regulator_matches[id].init_data; +		reg_node = as3722_regulator_matches[id].of_node; + +		if (!reg_config->reg_init || !reg_node) +			continue; + +		ret = of_property_read_u32(reg_node, "ams,ext-control", &prop); +		if (!ret) { +			if (prop < 3) +				reg_config->ext_control = prop; +			else +				dev_warn(&pdev->dev, +					"ext-control have invalid option: %u\n", +					prop); +		} +		reg_config->enable_tracking = +			of_property_read_bool(reg_node, "ams,enable-tracking"); +	} +	return 0; +} + +static int as3722_regulator_probe(struct platform_device *pdev) +{ +	struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent); +	struct as3722_regulators *as3722_regs; +	struct as3722_regulator_config_data *reg_config; +	struct regulator_dev *rdev; +	struct regulator_config config = { }; +	struct regulator_ops *ops; +	int id; +	int ret; + +	as3722_regs = devm_kzalloc(&pdev->dev, sizeof(*as3722_regs), +				GFP_KERNEL); +	if (!as3722_regs) +		return -ENOMEM; + +	as3722_regs->dev = &pdev->dev; +	as3722_regs->as3722 = as3722; +	platform_set_drvdata(pdev, as3722_regs); + +	ret = as3722_get_regulator_dt_data(pdev, as3722_regs); +	if (ret < 0) +		return ret; + +	config.dev = &pdev->dev; +	config.driver_data = as3722_regs; +	config.regmap = as3722->regmap; + +	for (id = 0; id < AS3722_REGULATOR_ID_MAX; id++) { +		reg_config = &as3722_regs->reg_config_data[id]; + +		as3722_regs->desc[id].name = as3722_reg_lookup[id].name; +		as3722_regs->desc[id].supply_name = as3722_reg_lookup[id].sname; +		as3722_regs->desc[id].id = as3722_reg_lookup[id].regulator_id; +		as3722_regs->desc[id].n_voltages = +					as3722_reg_lookup[id].n_voltages; +		as3722_regs->desc[id].type = REGULATOR_VOLTAGE; +		as3722_regs->desc[id].owner = THIS_MODULE; +		as3722_regs->desc[id].enable_reg = +					as3722_reg_lookup[id].enable_reg; +		as3722_regs->desc[id].enable_mask = +					as3722_reg_lookup[id].enable_mask; +		as3722_regs->desc[id].vsel_reg = as3722_reg_lookup[id].vsel_reg; +		as3722_regs->desc[id].vsel_mask = +					as3722_reg_lookup[id].vsel_mask; +		switch (id) { +		case AS3722_REGULATOR_ID_LDO0: +			if (reg_config->ext_control) +				ops = &as3722_ldo0_extcntrl_ops; +			else +				ops = &as3722_ldo0_ops; +			as3722_regs->desc[id].min_uV = 825000; +			as3722_regs->desc[id].uV_step = 25000; +			as3722_regs->desc[id].linear_min_sel = 1; +			as3722_regs->desc[id].enable_time = 500; +			break; +		case AS3722_REGULATOR_ID_LDO3: +			if (reg_config->ext_control) +				ops = &as3722_ldo3_extcntrl_ops; +			else +				ops = &as3722_ldo3_ops; +			as3722_regs->desc[id].min_uV = 620000; +			as3722_regs->desc[id].uV_step = 20000; +			as3722_regs->desc[id].linear_min_sel = 1; +			as3722_regs->desc[id].enable_time = 500; +			if (reg_config->enable_tracking) { +				ret = as3722_ldo3_set_tracking_mode(as3722_regs, +					id, AS3722_LDO3_MODE_PMOS_TRACKING); +				if (ret < 0) { +					dev_err(&pdev->dev, +						"LDO3 tracking failed: %d\n", +						ret); +					return ret; +				} +			} +			break; +		case AS3722_REGULATOR_ID_SD0: +		case AS3722_REGULATOR_ID_SD1: +		case AS3722_REGULATOR_ID_SD6: +			if (reg_config->ext_control) +				ops = &as3722_sd016_extcntrl_ops; +			else +				ops = &as3722_sd016_ops; +			if (id == AS3722_REGULATOR_ID_SD0 && +			    as3722_sd0_is_low_voltage(as3722_regs)) { +				as3722_regs->desc[id].n_voltages = +					AS3722_SD0_VSEL_LOW_VOL_MAX + 1; +				as3722_regs->desc[id].min_uV = 410000; +			} else { +				as3722_regs->desc[id].n_voltages = +					AS3722_SD0_VSEL_MAX + 1, +				as3722_regs->desc[id].min_uV = 610000; +			} +			as3722_regs->desc[id].uV_step = 10000; +			as3722_regs->desc[id].linear_min_sel = 1; +			as3722_regs->desc[id].enable_time = 600; +			break; +		case AS3722_REGULATOR_ID_SD2: +		case AS3722_REGULATOR_ID_SD3: +		case AS3722_REGULATOR_ID_SD4: +		case AS3722_REGULATOR_ID_SD5: +			if (reg_config->ext_control) +				ops = &as3722_sd2345_extcntrl_ops; +			else +				ops = &as3722_sd2345_ops; +			as3722_regs->desc[id].linear_ranges = +						as3722_sd2345_ranges; +			as3722_regs->desc[id].n_linear_ranges = +					ARRAY_SIZE(as3722_sd2345_ranges); +			break; +		default: +			if (reg_config->ext_control) +				ops = &as3722_ldo_extcntrl_ops; +			else +				ops = &as3722_ldo_ops; +			as3722_regs->desc[id].enable_time = 500; +			as3722_regs->desc[id].linear_ranges = as3722_ldo_ranges; +			as3722_regs->desc[id].n_linear_ranges = +						ARRAY_SIZE(as3722_ldo_ranges); +			break; +		} +		as3722_regs->desc[id].ops = ops; +		config.init_data = reg_config->reg_init; +		config.of_node = as3722_regulator_matches[id].of_node; +		rdev = devm_regulator_register(&pdev->dev, +					&as3722_regs->desc[id], &config); +		if (IS_ERR(rdev)) { +			ret = PTR_ERR(rdev); +			dev_err(&pdev->dev, "regulator %d register failed %d\n", +				id, ret); +			return ret; +		} + +		as3722_regs->rdevs[id] = rdev; +		if (reg_config->ext_control) { +			ret = regulator_enable_regmap(rdev); +			if (ret < 0) { +				dev_err(&pdev->dev, +					"Regulator %d enable failed: %d\n", +					id, ret); +				return ret; +			} +			ret = as3722_extreg_init(as3722_regs, id, +					reg_config->ext_control); +			if (ret < 0) { +				dev_err(&pdev->dev, +					"AS3722 ext control failed: %d", ret); +				return ret; +			} +		} +	} +	return 0; +} + +static const struct of_device_id of_as3722_regulator_match[] = { +	{ .compatible = "ams,as3722-regulator", }, +	{}, +}; +MODULE_DEVICE_TABLE(of, of_as3722_regulator_match); + +static struct platform_driver as3722_regulator_driver = { +	.driver = { +		.name = "as3722-regulator", +		.owner = THIS_MODULE, +		.of_match_table = of_as3722_regulator_match, +	}, +	.probe = as3722_regulator_probe, +}; + +module_platform_driver(as3722_regulator_driver); + +MODULE_ALIAS("platform:as3722-regulator"); +MODULE_DESCRIPTION("AS3722 regulator driver"); +MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@ams.com>"); +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c new file mode 100644 index 00000000000..004aadb7bcc --- /dev/null +++ b/drivers/regulator/axp20x-regulator.c @@ -0,0 +1,286 @@ +/* + * AXP20x regulators driver. + * + * Copyright (C) 2013 Carlo Caione <carlo@caione.org> + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/mfd/axp20x.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> + +#define AXP20X_IO_ENABLED		0x03 +#define AXP20X_IO_DISABLED		0x07 + +#define AXP20X_WORKMODE_DCDC2_MASK	BIT(2) +#define AXP20X_WORKMODE_DCDC3_MASK	BIT(1) + +#define AXP20X_FREQ_DCDC_MASK		0x0f + +#define AXP20X_DESC_IO(_id, _supply, _min, _max, _step, _vreg, _vmask, _ereg,   \ +		       _emask, _enable_val, _disable_val)			\ +	[AXP20X_##_id] = {							\ +		.name		= #_id,						\ +		.supply_name	= (_supply),					\ +		.type		= REGULATOR_VOLTAGE,				\ +		.id		= AXP20X_##_id,					\ +		.n_voltages	= (((_max) - (_min)) / (_step) + 1),		\ +		.owner		= THIS_MODULE,					\ +		.min_uV		= (_min) * 1000,				\ +		.uV_step	= (_step) * 1000,				\ +		.vsel_reg	= (_vreg),					\ +		.vsel_mask	= (_vmask),					\ +		.enable_reg	= (_ereg),					\ +		.enable_mask	= (_emask),					\ +		.enable_val	= (_enable_val),				\ +		.disable_val	= (_disable_val),				\ +		.ops		= &axp20x_ops,					\ +	} + +#define AXP20X_DESC(_id, _supply, _min, _max, _step, _vreg, _vmask, _ereg,	\ +		    _emask) 							\ +	[AXP20X_##_id] = {							\ +		.name		= #_id,						\ +		.supply_name	= (_supply),					\ +		.type		= REGULATOR_VOLTAGE,				\ +		.id		= AXP20X_##_id,					\ +		.n_voltages	= (((_max) - (_min)) / (_step) + 1),		\ +		.owner		= THIS_MODULE,					\ +		.min_uV		= (_min) * 1000,				\ +		.uV_step	= (_step) * 1000,				\ +		.vsel_reg	= (_vreg),					\ +		.vsel_mask	= (_vmask),					\ +		.enable_reg	= (_ereg),					\ +		.enable_mask	= (_emask),					\ +		.ops		= &axp20x_ops,					\ +	} + +#define AXP20X_DESC_FIXED(_id, _supply, _volt)					\ +	[AXP20X_##_id] = {							\ +		.name		= #_id,						\ +		.supply_name	= (_supply),					\ +		.type		= REGULATOR_VOLTAGE,				\ +		.id		= AXP20X_##_id,					\ +		.n_voltages	= 1,						\ +		.owner		= THIS_MODULE,					\ +		.min_uV		= (_volt) * 1000,				\ +		.ops		= &axp20x_ops_fixed				\ +	} + +#define AXP20X_DESC_TABLE(_id, _supply, _table, _vreg, _vmask, _ereg, _emask)	\ +	[AXP20X_##_id] = {							\ +		.name		= #_id,						\ +		.supply_name	= (_supply),					\ +		.type		= REGULATOR_VOLTAGE,				\ +		.id		= AXP20X_##_id,					\ +		.n_voltages	= ARRAY_SIZE(_table),				\ +		.owner		= THIS_MODULE,					\ +		.vsel_reg	= (_vreg),					\ +		.vsel_mask	= (_vmask),					\ +		.enable_reg	= (_ereg),					\ +		.enable_mask	= (_emask),					\ +		.volt_table	= (_table),					\ +		.ops		= &axp20x_ops_table,				\ +	} + +static const int axp20x_ldo4_data[] = { 1250000, 1300000, 1400000, 1500000, 1600000, +					1700000, 1800000, 1900000, 2000000, 2500000, +					2700000, 2800000, 3000000, 3100000, 3200000, +					3300000 }; + +static struct regulator_ops axp20x_ops_fixed = { +	.list_voltage		= regulator_list_voltage_linear, +}; + +static struct regulator_ops axp20x_ops_table = { +	.set_voltage_sel	= regulator_set_voltage_sel_regmap, +	.get_voltage_sel	= regulator_get_voltage_sel_regmap, +	.list_voltage		= regulator_list_voltage_table, +	.map_voltage		= regulator_map_voltage_ascend, +	.enable			= regulator_enable_regmap, +	.disable		= regulator_disable_regmap, +	.is_enabled		= regulator_is_enabled_regmap, +}; + +static struct regulator_ops axp20x_ops = { +	.set_voltage_sel	= regulator_set_voltage_sel_regmap, +	.get_voltage_sel	= regulator_get_voltage_sel_regmap, +	.list_voltage		= regulator_list_voltage_linear, +	.enable			= regulator_enable_regmap, +	.disable		= regulator_disable_regmap, +	.is_enabled		= regulator_is_enabled_regmap, +}; + +static const struct regulator_desc axp20x_regulators[] = { +	AXP20X_DESC(DCDC2, "vin2", 700, 2275, 25, AXP20X_DCDC2_V_OUT, 0x3f, +		    AXP20X_PWR_OUT_CTRL, 0x10), +	AXP20X_DESC(DCDC3, "vin3", 700, 3500, 25, AXP20X_DCDC3_V_OUT, 0x7f, +		    AXP20X_PWR_OUT_CTRL, 0x02), +	AXP20X_DESC_FIXED(LDO1, "acin", 1300), +	AXP20X_DESC(LDO2, "ldo24in", 1800, 3300, 100, AXP20X_LDO24_V_OUT, 0xf0, +		    AXP20X_PWR_OUT_CTRL, 0x04), +	AXP20X_DESC(LDO3, "ldo3in", 700, 3500, 25, AXP20X_LDO3_V_OUT, 0x7f, +		    AXP20X_PWR_OUT_CTRL, 0x40), +	AXP20X_DESC_TABLE(LDO4, "ldo24in", axp20x_ldo4_data, AXP20X_LDO24_V_OUT, 0x0f, +			  AXP20X_PWR_OUT_CTRL, 0x08), +	AXP20X_DESC_IO(LDO5, "ldo5in", 1800, 3300, 100, AXP20X_LDO5_V_OUT, 0xf0, +		       AXP20X_GPIO0_CTRL, 0x07, AXP20X_IO_ENABLED, +		       AXP20X_IO_DISABLED), +}; + +#define AXP_MATCH(_name, _id) \ +	[AXP20X_##_id] = { \ +		.name		= #_name, \ +		.driver_data	= (void *) &axp20x_regulators[AXP20X_##_id], \ +	} + +static struct of_regulator_match axp20x_matches[] = { +	AXP_MATCH(dcdc2, DCDC2), +	AXP_MATCH(dcdc3, DCDC3), +	AXP_MATCH(ldo1, LDO1), +	AXP_MATCH(ldo2, LDO2), +	AXP_MATCH(ldo3, LDO3), +	AXP_MATCH(ldo4, LDO4), +	AXP_MATCH(ldo5, LDO5), +}; + +static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) +{ +	struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); + +	if (dcdcfreq < 750) { +		dcdcfreq = 750; +		dev_warn(&pdev->dev, "DCDC frequency too low. Set to 750kHz\n"); +	} + +	if (dcdcfreq > 1875) { +		dcdcfreq = 1875; +		dev_warn(&pdev->dev, "DCDC frequency too high. Set to 1875kHz\n"); +	} + +	dcdcfreq = (dcdcfreq - 750) / 75; + +	return regmap_update_bits(axp20x->regmap, AXP20X_DCDC_FREQ, +				  AXP20X_FREQ_DCDC_MASK, dcdcfreq); +} + +static int axp20x_regulator_parse_dt(struct platform_device *pdev) +{ +	struct device_node *np, *regulators; +	int ret; +	u32 dcdcfreq; + +	np = of_node_get(pdev->dev.parent->of_node); +	if (!np) +		return 0; + +	regulators = of_get_child_by_name(np, "regulators"); +	if (!regulators) { +		dev_warn(&pdev->dev, "regulators node not found\n"); +	} else { +		ret = of_regulator_match(&pdev->dev, regulators, axp20x_matches, +					 ARRAY_SIZE(axp20x_matches)); +		if (ret < 0) { +			dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret); +			return ret; +		} + +		dcdcfreq = 1500; +		of_property_read_u32(regulators, "x-powers,dcdc-freq", &dcdcfreq); +		ret = axp20x_set_dcdc_freq(pdev, dcdcfreq); +		if (ret < 0) { +			dev_err(&pdev->dev, "Error setting dcdc frequency: %d\n", ret); +			return ret; +		} + +		of_node_put(regulators); +	} + +	return 0; +} + +static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 workmode) +{ +	unsigned int mask = AXP20X_WORKMODE_DCDC2_MASK; + +	if ((id != AXP20X_DCDC2) && (id != AXP20X_DCDC3)) +		return -EINVAL; + +	if (id == AXP20X_DCDC3) +		mask = AXP20X_WORKMODE_DCDC3_MASK; + +	workmode <<= ffs(mask) - 1; + +	return regmap_update_bits(rdev->regmap, AXP20X_DCDC_MODE, mask, workmode); +} + +static int axp20x_regulator_probe(struct platform_device *pdev) +{ +	struct regulator_dev *rdev; +	struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); +	struct regulator_config config = { }; +	struct regulator_init_data *init_data; +	int ret, i; +	u32 workmode; + +	ret = axp20x_regulator_parse_dt(pdev); +	if (ret) +		return ret; + +	for (i = 0; i < AXP20X_REG_ID_MAX; i++) { +		init_data = axp20x_matches[i].init_data; + +		config.dev = &pdev->dev; +		config.init_data = init_data; +		config.regmap = axp20x->regmap; +		config.of_node = axp20x_matches[i].of_node; + +		rdev = devm_regulator_register(&pdev->dev, &axp20x_regulators[i], +					       &config); +		if (IS_ERR(rdev)) { +			dev_err(&pdev->dev, "Failed to register %s\n", +				axp20x_regulators[i].name); + +			return PTR_ERR(rdev); +		} + +		ret = of_property_read_u32(axp20x_matches[i].of_node, "x-powers,dcdc-workmode", +					   &workmode); +		if (!ret) { +			if (axp20x_set_dcdc_workmode(rdev, i, workmode)) +				dev_err(&pdev->dev, "Failed to set workmode on %s\n", +					axp20x_regulators[i].name); +		} +	} + +	return 0; +} + +static struct platform_driver axp20x_regulator_driver = { +	.probe	= axp20x_regulator_probe, +	.driver	= { +		.name		= "axp20x-regulator", +		.owner		= THIS_MODULE, +	}, +}; + +module_platform_driver(axp20x_regulator_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Carlo Caione <carlo@caione.org>"); +MODULE_DESCRIPTION("Regulator Driver for AXP20X PMIC"); diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c new file mode 100644 index 00000000000..58ece59367a --- /dev/null +++ b/drivers/regulator/bcm590xx-regulator.c @@ -0,0 +1,481 @@ +/* + * Broadcom BCM590xx regulator driver + * + * Copyright 2014 Linaro Limited + * Author: Matt Porter <mporter@linaro.org> + * + * This program is free software; you can redistribute it and/or modify it + * under  the terms of the GNU General  Public License as published by the + * Free Software Foundation;  either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mfd/bcm590xx.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/slab.h> + +/* I2C slave 0 registers */ +#define BCM590XX_RFLDOPMCTRL1	0x60 +#define BCM590XX_IOSR1PMCTRL1	0x7a +#define BCM590XX_IOSR2PMCTRL1	0x7c +#define BCM590XX_CSRPMCTRL1	0x7e +#define BCM590XX_SDSR1PMCTRL1	0x82 +#define BCM590XX_SDSR2PMCTRL1	0x86 +#define BCM590XX_MSRPMCTRL1	0x8a +#define BCM590XX_VSRPMCTRL1	0x8e +#define BCM590XX_RFLDOCTRL	0x96 +#define BCM590XX_CSRVOUT1	0xc0 + +/* I2C slave 1 registers */ +#define BCM590XX_GPLDO5PMCTRL1	0x16 +#define BCM590XX_GPLDO6PMCTRL1	0x18 +#define BCM590XX_GPLDO1CTRL	0x1a +#define BCM590XX_GPLDO2CTRL	0x1b +#define BCM590XX_GPLDO3CTRL	0x1c +#define BCM590XX_GPLDO4CTRL	0x1d +#define BCM590XX_GPLDO5CTRL	0x1e +#define BCM590XX_GPLDO6CTRL	0x1f +#define BCM590XX_OTG_CTRL	0x40 +#define BCM590XX_GPLDO1PMCTRL1	0x57 +#define BCM590XX_GPLDO2PMCTRL1	0x59 +#define BCM590XX_GPLDO3PMCTRL1	0x5b +#define BCM590XX_GPLDO4PMCTRL1	0x5d + +#define BCM590XX_REG_ENABLE	BIT(7) +#define BCM590XX_VBUS_ENABLE	BIT(2) +#define BCM590XX_LDO_VSEL_MASK	GENMASK(5, 3) +#define BCM590XX_SR_VSEL_MASK	GENMASK(5, 0) + +/* + * RFLDO to VSR regulators are + * accessed via I2C slave 0 + */ + +/* LDO regulator IDs */ +#define BCM590XX_REG_RFLDO	0 +#define BCM590XX_REG_CAMLDO1	1 +#define BCM590XX_REG_CAMLDO2	2 +#define BCM590XX_REG_SIMLDO1	3 +#define BCM590XX_REG_SIMLDO2	4 +#define BCM590XX_REG_SDLDO	5 +#define BCM590XX_REG_SDXLDO	6 +#define BCM590XX_REG_MMCLDO1	7 +#define BCM590XX_REG_MMCLDO2	8 +#define BCM590XX_REG_AUDLDO	9 +#define BCM590XX_REG_MICLDO	10 +#define BCM590XX_REG_USBLDO	11 +#define BCM590XX_REG_VIBLDO	12 + +/* DCDC regulator IDs */ +#define BCM590XX_REG_CSR	13 +#define BCM590XX_REG_IOSR1	14 +#define BCM590XX_REG_IOSR2	15 +#define BCM590XX_REG_MSR	16 +#define BCM590XX_REG_SDSR1	17 +#define BCM590XX_REG_SDSR2	18 +#define BCM590XX_REG_VSR	19 + +/* + * GPLDO1 to VBUS regulators are + * accessed via I2C slave 1 + */ + +#define BCM590XX_REG_GPLDO1	20 +#define BCM590XX_REG_GPLDO2	21 +#define BCM590XX_REG_GPLDO3	22 +#define BCM590XX_REG_GPLDO4	23 +#define BCM590XX_REG_GPLDO5	24 +#define BCM590XX_REG_GPLDO6	25 +#define BCM590XX_REG_VBUS	26 + +#define BCM590XX_NUM_REGS	27 + +#define BCM590XX_REG_IS_LDO(n)	(n < BCM590XX_REG_CSR) +#define BCM590XX_REG_IS_GPLDO(n) \ +	((n > BCM590XX_REG_VSR) && (n < BCM590XX_REG_VBUS)) +#define BCM590XX_REG_IS_VBUS(n)	(n == BCM590XX_REG_VBUS) + +struct bcm590xx_board { +	struct regulator_init_data *bcm590xx_pmu_init_data[BCM590XX_NUM_REGS]; +}; + +/* LDO group A: supported voltages in microvolts */ +static const unsigned int ldo_a_table[] = { +	1200000, 1800000, 2500000, 2700000, 2800000, +	2900000, 3000000, 3300000, +}; + +/* LDO group C: supported voltages in microvolts */ +static const unsigned int ldo_c_table[] = { +	3100000, 1800000, 2500000, 2700000, 2800000, +	2900000, 3000000, 3300000, +}; + +static const unsigned int ldo_vbus[] = { +	5000000, +}; + +/* DCDC group CSR: supported voltages in microvolts */ +static const struct regulator_linear_range dcdc_csr_ranges[] = { +	REGULATOR_LINEAR_RANGE(860000, 2, 50, 10000), +	REGULATOR_LINEAR_RANGE(1360000, 51, 55, 20000), +	REGULATOR_LINEAR_RANGE(900000, 56, 63, 0), +}; + +/* DCDC group IOSR1: supported voltages in microvolts */ +static const struct regulator_linear_range dcdc_iosr1_ranges[] = { +	REGULATOR_LINEAR_RANGE(860000, 2, 51, 10000), +	REGULATOR_LINEAR_RANGE(1500000, 52, 52, 0), +	REGULATOR_LINEAR_RANGE(1800000, 53, 53, 0), +	REGULATOR_LINEAR_RANGE(900000, 54, 63, 0), +}; + +/* DCDC group SDSR1: supported voltages in microvolts */ +static const struct regulator_linear_range dcdc_sdsr1_ranges[] = { +	REGULATOR_LINEAR_RANGE(860000, 2, 50, 10000), +	REGULATOR_LINEAR_RANGE(1340000, 51, 51, 0), +	REGULATOR_LINEAR_RANGE(900000, 52, 63, 0), +}; + +struct bcm590xx_info { +	const char *name; +	const char *vin_name; +	u8 n_voltages; +	const unsigned int *volt_table; +	u8 n_linear_ranges; +	const struct regulator_linear_range *linear_ranges; +}; + +#define BCM590XX_REG_TABLE(_name, _table) \ +	{ \ +		.name = #_name, \ +		.n_voltages = ARRAY_SIZE(_table), \ +		.volt_table = _table, \ +	} + +#define BCM590XX_REG_RANGES(_name, _ranges) \ +	{ \ +		.name = #_name, \ +		.n_voltages = 64, \ +		.n_linear_ranges = ARRAY_SIZE(_ranges), \ +		.linear_ranges = _ranges, \ +	} + +static struct bcm590xx_info bcm590xx_regs[] = { +	BCM590XX_REG_TABLE(rfldo, ldo_a_table), +	BCM590XX_REG_TABLE(camldo1, ldo_c_table), +	BCM590XX_REG_TABLE(camldo2, ldo_c_table), +	BCM590XX_REG_TABLE(simldo1, ldo_a_table), +	BCM590XX_REG_TABLE(simldo2, ldo_a_table), +	BCM590XX_REG_TABLE(sdldo, ldo_c_table), +	BCM590XX_REG_TABLE(sdxldo, ldo_a_table), +	BCM590XX_REG_TABLE(mmcldo1, ldo_a_table), +	BCM590XX_REG_TABLE(mmcldo2, ldo_a_table), +	BCM590XX_REG_TABLE(audldo, ldo_a_table), +	BCM590XX_REG_TABLE(micldo, ldo_a_table), +	BCM590XX_REG_TABLE(usbldo, ldo_a_table), +	BCM590XX_REG_TABLE(vibldo, ldo_c_table), +	BCM590XX_REG_RANGES(csr, dcdc_csr_ranges), +	BCM590XX_REG_RANGES(iosr1, dcdc_iosr1_ranges), +	BCM590XX_REG_RANGES(iosr2, dcdc_iosr1_ranges), +	BCM590XX_REG_RANGES(msr, dcdc_iosr1_ranges), +	BCM590XX_REG_RANGES(sdsr1, dcdc_sdsr1_ranges), +	BCM590XX_REG_RANGES(sdsr2, dcdc_iosr1_ranges), +	BCM590XX_REG_RANGES(vsr, dcdc_iosr1_ranges), +	BCM590XX_REG_TABLE(gpldo1, ldo_a_table), +	BCM590XX_REG_TABLE(gpldo2, ldo_a_table), +	BCM590XX_REG_TABLE(gpldo3, ldo_a_table), +	BCM590XX_REG_TABLE(gpldo4, ldo_a_table), +	BCM590XX_REG_TABLE(gpldo5, ldo_a_table), +	BCM590XX_REG_TABLE(gpldo6, ldo_a_table), +	BCM590XX_REG_TABLE(vbus, ldo_vbus), +}; + +struct bcm590xx_reg { +	struct regulator_desc *desc; +	struct bcm590xx *mfd; +	struct bcm590xx_info **info; +}; + +static int bcm590xx_get_vsel_register(int id) +{ +	if (BCM590XX_REG_IS_LDO(id)) +		return BCM590XX_RFLDOCTRL + id; +	else if (BCM590XX_REG_IS_GPLDO(id)) +		return BCM590XX_GPLDO1CTRL + id; +	else +		return BCM590XX_CSRVOUT1 + (id - BCM590XX_REG_CSR) * 3; +} + +static int bcm590xx_get_enable_register(int id) +{ +	int reg = 0; + +	if (BCM590XX_REG_IS_LDO(id)) +		reg = BCM590XX_RFLDOPMCTRL1 + id * 2; +	else if (BCM590XX_REG_IS_GPLDO(id)) +		reg = BCM590XX_GPLDO1PMCTRL1 + id * 2; +	else +		switch (id) { +		case BCM590XX_REG_CSR: +			reg = BCM590XX_CSRPMCTRL1; +			break; +		case BCM590XX_REG_IOSR1: +			reg = BCM590XX_IOSR1PMCTRL1; +			break; +		case BCM590XX_REG_IOSR2: +			reg = BCM590XX_IOSR2PMCTRL1; +			break; +		case BCM590XX_REG_MSR: +			reg = BCM590XX_MSRPMCTRL1; +			break; +		case BCM590XX_REG_SDSR1: +			reg = BCM590XX_SDSR1PMCTRL1; +			break; +		case BCM590XX_REG_SDSR2: +			reg = BCM590XX_SDSR2PMCTRL1; +			break; +		case BCM590XX_REG_VBUS: +			reg = BCM590XX_OTG_CTRL; +		}; + + +	return reg; +} + +static struct regulator_ops bcm590xx_ops_ldo = { +	.is_enabled		= regulator_is_enabled_regmap, +	.enable			= regulator_enable_regmap, +	.disable		= regulator_disable_regmap, +	.get_voltage_sel	= regulator_get_voltage_sel_regmap, +	.set_voltage_sel	= regulator_set_voltage_sel_regmap, +	.list_voltage		= regulator_list_voltage_table, +	.map_voltage		= regulator_map_voltage_iterate, +}; + +static struct regulator_ops bcm590xx_ops_dcdc = { +	.is_enabled		= regulator_is_enabled_regmap, +	.enable			= regulator_enable_regmap, +	.disable		= regulator_disable_regmap, +	.get_voltage_sel	= regulator_get_voltage_sel_regmap, +	.set_voltage_sel	= regulator_set_voltage_sel_regmap, +	.list_voltage		= regulator_list_voltage_linear_range, +	.map_voltage		= regulator_map_voltage_linear_range, +}; + +static struct regulator_ops bcm590xx_ops_vbus = { +	.is_enabled		= regulator_is_enabled_regmap, +	.enable			= regulator_enable_regmap, +	.disable		= regulator_disable_regmap, +}; + +#define BCM590XX_MATCH(_name, _id) \ +	{ \ +		.name = #_name, \ +		.driver_data = (void *)&bcm590xx_regs[BCM590XX_REG_##_id], \ +	} + +static struct of_regulator_match bcm590xx_matches[] = { +	BCM590XX_MATCH(rfldo, RFLDO), +	BCM590XX_MATCH(camldo1, CAMLDO1), +	BCM590XX_MATCH(camldo2, CAMLDO2), +	BCM590XX_MATCH(simldo1, SIMLDO1), +	BCM590XX_MATCH(simldo2, SIMLDO2), +	BCM590XX_MATCH(sdldo, SDLDO), +	BCM590XX_MATCH(sdxldo, SDXLDO), +	BCM590XX_MATCH(mmcldo1, MMCLDO1), +	BCM590XX_MATCH(mmcldo2, MMCLDO2), +	BCM590XX_MATCH(audldo, AUDLDO), +	BCM590XX_MATCH(micldo, MICLDO), +	BCM590XX_MATCH(usbldo, USBLDO), +	BCM590XX_MATCH(vibldo, VIBLDO), +	BCM590XX_MATCH(csr, CSR), +	BCM590XX_MATCH(iosr1, IOSR1), +	BCM590XX_MATCH(iosr2, IOSR2), +	BCM590XX_MATCH(msr, MSR), +	BCM590XX_MATCH(sdsr1, SDSR1), +	BCM590XX_MATCH(sdsr2, SDSR2), +	BCM590XX_MATCH(vsr, VSR), +	BCM590XX_MATCH(gpldo1, GPLDO1), +	BCM590XX_MATCH(gpldo2, GPLDO2), +	BCM590XX_MATCH(gpldo3, GPLDO3), +	BCM590XX_MATCH(gpldo4, GPLDO4), +	BCM590XX_MATCH(gpldo5, GPLDO5), +	BCM590XX_MATCH(gpldo6, GPLDO6), +	BCM590XX_MATCH(vbus, VBUS), +}; + +static struct bcm590xx_board *bcm590xx_parse_dt_reg_data( +		struct platform_device *pdev, +		struct of_regulator_match **bcm590xx_reg_matches) +{ +	struct bcm590xx_board *data; +	struct device_node *np = pdev->dev.parent->of_node; +	struct device_node *regulators; +	struct of_regulator_match *matches = bcm590xx_matches; +	int count = ARRAY_SIZE(bcm590xx_matches); +	int idx = 0; +	int ret; + +	if (!np) { +		dev_err(&pdev->dev, "of node not found\n"); +		return NULL; +	} + +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); +	if (!data) { +		dev_err(&pdev->dev, "failed to allocate regulator board data\n"); +		return NULL; +	} + +	np = of_node_get(np); +	regulators = of_get_child_by_name(np, "regulators"); +	if (!regulators) { +		dev_warn(&pdev->dev, "regulator node not found\n"); +		return NULL; +	} + +	ret = of_regulator_match(&pdev->dev, regulators, matches, count); +	of_node_put(regulators); +	if (ret < 0) { +		dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", +			ret); +		return NULL; +	} + +	*bcm590xx_reg_matches = matches; + +	for (idx = 0; idx < count; idx++) { +		if (!matches[idx].init_data || !matches[idx].of_node) +			continue; + +		data->bcm590xx_pmu_init_data[idx] = matches[idx].init_data; +	} + +	return data; +} + +static int bcm590xx_probe(struct platform_device *pdev) +{ +	struct bcm590xx *bcm590xx = dev_get_drvdata(pdev->dev.parent); +	struct bcm590xx_board *pmu_data = NULL; +	struct bcm590xx_reg *pmu; +	struct regulator_config config = { }; +	struct bcm590xx_info *info; +	struct regulator_init_data *reg_data; +	struct regulator_dev *rdev; +	struct of_regulator_match *bcm590xx_reg_matches = NULL; +	int i; + +	pmu_data = bcm590xx_parse_dt_reg_data(pdev, +					      &bcm590xx_reg_matches); + +	pmu = devm_kzalloc(&pdev->dev, sizeof(*pmu), GFP_KERNEL); +	if (!pmu) { +		dev_err(&pdev->dev, "Memory allocation failed for pmu\n"); +		return -ENOMEM; +	} + +	pmu->mfd = bcm590xx; + +	platform_set_drvdata(pdev, pmu); + +	pmu->desc = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS * +			sizeof(struct regulator_desc), GFP_KERNEL); +	if (!pmu->desc) { +		dev_err(&pdev->dev, "Memory alloc fails for desc\n"); +		return -ENOMEM; +	} + +	pmu->info = devm_kzalloc(&pdev->dev, BCM590XX_NUM_REGS * +			sizeof(struct bcm590xx_info *), GFP_KERNEL); +	if (!pmu->info) { +		dev_err(&pdev->dev, "Memory alloc fails for info\n"); +		return -ENOMEM; +	} + +	info = bcm590xx_regs; + +	for (i = 0; i < BCM590XX_NUM_REGS; i++, info++) { +		if (pmu_data) +			reg_data = pmu_data->bcm590xx_pmu_init_data[i]; +		else +			reg_data = NULL; + +		/* Register the regulators */ +		pmu->info[i] = info; + +		pmu->desc[i].name = info->name; +		pmu->desc[i].supply_name = info->vin_name; +		pmu->desc[i].id = i; +		pmu->desc[i].volt_table = info->volt_table; +		pmu->desc[i].n_voltages = info->n_voltages; +		pmu->desc[i].linear_ranges = info->linear_ranges; +		pmu->desc[i].n_linear_ranges = info->n_linear_ranges; + +		if ((BCM590XX_REG_IS_LDO(i)) || (BCM590XX_REG_IS_GPLDO(i))) { +			pmu->desc[i].ops = &bcm590xx_ops_ldo; +			pmu->desc[i].vsel_mask = BCM590XX_LDO_VSEL_MASK; +		} else if (BCM590XX_REG_IS_VBUS(i)) +			pmu->desc[i].ops = &bcm590xx_ops_vbus; +		else { +			pmu->desc[i].ops = &bcm590xx_ops_dcdc; +			pmu->desc[i].vsel_mask = BCM590XX_SR_VSEL_MASK; +		} + +		if (BCM590XX_REG_IS_VBUS(i)) +			pmu->desc[i].enable_mask = BCM590XX_VBUS_ENABLE; +		else { +			pmu->desc[i].vsel_reg = bcm590xx_get_vsel_register(i); +			pmu->desc[i].enable_is_inverted = true; +			pmu->desc[i].enable_mask = BCM590XX_REG_ENABLE; +		} +		pmu->desc[i].enable_reg = bcm590xx_get_enable_register(i); +		pmu->desc[i].type = REGULATOR_VOLTAGE; +		pmu->desc[i].owner = THIS_MODULE; + +		config.dev = bcm590xx->dev; +		config.init_data = reg_data; +		config.driver_data = pmu; +		if (BCM590XX_REG_IS_GPLDO(i) || BCM590XX_REG_IS_VBUS(i)) +			config.regmap = bcm590xx->regmap_sec; +		else +			config.regmap = bcm590xx->regmap_pri; + +		if (bcm590xx_reg_matches) +			config.of_node = bcm590xx_reg_matches[i].of_node; + +		rdev = devm_regulator_register(&pdev->dev, &pmu->desc[i], +					       &config); +		if (IS_ERR(rdev)) { +			dev_err(bcm590xx->dev, +				"failed to register %s regulator\n", +				pdev->name); +			return PTR_ERR(rdev); +		} +	} + +	return 0; +} + +static struct platform_driver bcm590xx_regulator_driver = { +	.driver = { +		.name = "bcm590xx-vregs", +		.owner = THIS_MODULE, +	}, +	.probe = bcm590xx_probe, +}; +module_platform_driver(bcm590xx_regulator_driver); + +MODULE_AUTHOR("Matt Porter <mporter@linaro.org>"); +MODULE_DESCRIPTION("BCM590xx voltage regulator driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:bcm590xx-vregs"); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a01b8b3b70c..4c1f999041d 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -36,6 +36,7 @@  #include <trace/events/regulator.h>  #include "dummy.h" +#include "internal.h"  #define rdev_crit(rdev, fmt, ...)					\  	pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) @@ -52,8 +53,8 @@ static DEFINE_MUTEX(regulator_list_mutex);  static LIST_HEAD(regulator_list);  static LIST_HEAD(regulator_map_list);  static LIST_HEAD(regulator_ena_gpio_list); +static LIST_HEAD(regulator_supply_alias_list);  static bool has_full_constraints; -static bool board_wants_dummy_regulator;  static struct dentry *debugfs_root; @@ -83,22 +84,16 @@ struct regulator_enable_gpio {  };  /* - * struct regulator + * struct regulator_supply_alias   * - * One for each consumer device. + * Used to map lookups for a supply onto an alternative device.   */ -struct regulator { -	struct device *dev; +struct regulator_supply_alias {  	struct list_head list; -	unsigned int always_on:1; -	unsigned int bypass:1; -	int uA_load; -	int min_uV; -	int max_uV; -	char *supply_name; -	struct device_attribute dev_attr; -	struct regulator_dev *rdev; -	struct dentry *debugfs; +	struct device *src_dev; +	const char *src_supply; +	struct device *alias_dev; +	const char *alias_supply;  };  static int _regulator_is_enabled(struct regulator_dev *rdev); @@ -124,6 +119,11 @@ static const char *rdev_get_name(struct regulator_dev *rdev)  		return "";  } +static bool have_full_constraints(void) +{ +	return has_full_constraints || of_have_populated_dt(); +} +  /**   * of_get_regulator - get a regulator device node based on supply name   * @dev: Device pointer for the consumer (of regulator) device @@ -844,13 +844,22 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,  	/* do we need to apply the constraint voltage */  	if (rdev->constraints->apply_uV &&  	    rdev->constraints->min_uV == rdev->constraints->max_uV) { -		ret = _regulator_do_set_voltage(rdev, -						rdev->constraints->min_uV, -						rdev->constraints->max_uV); -		if (ret < 0) { -			rdev_err(rdev, "failed to apply %duV constraint\n", -				 rdev->constraints->min_uV); -			return ret; +		int current_uV = _regulator_get_voltage(rdev); +		if (current_uV < 0) { +			rdev_err(rdev, "failed to get the current voltage\n"); +			return current_uV; +		} +		if (current_uV < rdev->constraints->min_uV || +		    current_uV > rdev->constraints->max_uV) { +			ret = _regulator_do_set_voltage( +				rdev, rdev->constraints->min_uV, +				rdev->constraints->max_uV); +			if (ret < 0) { +				rdev_err(rdev, +					"failed to apply %duV constraint\n", +					rdev->constraints->min_uV); +				return ret; +			}  		}  	} @@ -923,6 +932,38 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,  	return 0;  } +static int machine_constraints_current(struct regulator_dev *rdev, +	struct regulation_constraints *constraints) +{ +	struct regulator_ops *ops = rdev->desc->ops; +	int ret; + +	if (!constraints->min_uA && !constraints->max_uA) +		return 0; + +	if (constraints->min_uA > constraints->max_uA) { +		rdev_err(rdev, "Invalid current constraints\n"); +		return -EINVAL; +	} + +	if (!ops->set_current_limit || !ops->get_current_limit) { +		rdev_warn(rdev, "Operation of current configuration missing\n"); +		return 0; +	} + +	/* Set regulator current in constraints range */ +	ret = ops->set_current_limit(rdev, constraints->min_uA, +			constraints->max_uA); +	if (ret < 0) { +		rdev_err(rdev, "Failed to set current constraint, %d\n", ret); +		return ret; +	} + +	return 0; +} + +static int _regulator_do_enable(struct regulator_dev *rdev); +  /**   * set_machine_constraints - sets regulator constraints   * @rdev: regulator source @@ -953,6 +994,10 @@ static int set_machine_constraints(struct regulator_dev *rdev,  	if (ret != 0)  		goto out; +	ret = machine_constraints_current(rdev, rdev->constraints); +	if (ret != 0) +		goto out; +  	/* do we need to setup our suspend state */  	if (rdev->constraints->initial_state) {  		ret = suspend_prepare(rdev, rdev->constraints->initial_state); @@ -979,10 +1024,9 @@ static int set_machine_constraints(struct regulator_dev *rdev,  	/* If the constraints say the regulator should be on at this point  	 * and we have control then make sure it is enabled.  	 */ -	if ((rdev->constraints->always_on || rdev->constraints->boot_on) && -	    ops->enable) { -		ret = ops->enable(rdev); -		if (ret < 0) { +	if (rdev->constraints->always_on || rdev->constraints->boot_on) { +		ret = _regulator_do_enable(rdev); +		if (ret < 0 && ret != -EINVAL) {  			rdev_err(rdev, "failed to enable\n");  			goto out;  		} @@ -1186,11 +1230,39 @@ overflow_err:  static int _regulator_get_enable_time(struct regulator_dev *rdev)  { +	if (rdev->constraints && rdev->constraints->enable_time) +		return rdev->constraints->enable_time;  	if (!rdev->desc->ops->enable_time)  		return rdev->desc->enable_time;  	return rdev->desc->ops->enable_time(rdev);  } +static struct regulator_supply_alias *regulator_find_supply_alias( +		struct device *dev, const char *supply) +{ +	struct regulator_supply_alias *map; + +	list_for_each_entry(map, ®ulator_supply_alias_list, list) +		if (map->src_dev == dev && strcmp(map->src_supply, supply) == 0) +			return map; + +	return NULL; +} + +static void regulator_supply_alias(struct device **dev, const char **supply) +{ +	struct regulator_supply_alias *map; + +	map = regulator_find_supply_alias(*dev, *supply); +	if (map) { +		dev_dbg(*dev, "Mapping supply %s to %s,%s\n", +				*supply, map->alias_supply, +				dev_name(map->alias_dev)); +		*dev = map->alias_dev; +		*supply = map->alias_supply; +	} +} +  static struct regulator_dev *regulator_dev_lookup(struct device *dev,  						  const char *supply,  						  int *ret) @@ -1200,6 +1272,8 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,  	struct regulator_map *map;  	const char *devname = NULL; +	regulator_supply_alias(&dev, &supply); +  	/* first do a dt based lookup */  	if (dev && dev->of_node) {  		node = of_get_regulator(dev, supply); @@ -1208,6 +1282,8 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,  				if (r->dev.parent &&  					node == r->dev.of_node)  					return r; +			*ret = -EPROBE_DEFER; +			return NULL;  		} else {  			/*  			 * If we couldn't even get the node then it's @@ -1243,55 +1319,58 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,  /* Internal regulator request function */  static struct regulator *_regulator_get(struct device *dev, const char *id, -					bool exclusive) +					bool exclusive, bool allow_dummy)  {  	struct regulator_dev *rdev;  	struct regulator *regulator = ERR_PTR(-EPROBE_DEFER);  	const char *devname = NULL; -	int ret = 0; +	int ret;  	if (id == NULL) {  		pr_err("get() with no identifier\n"); -		return regulator; +		return ERR_PTR(-EINVAL);  	}  	if (dev)  		devname = dev_name(dev); +	if (have_full_constraints()) +		ret = -ENODEV; +	else +		ret = -EPROBE_DEFER; +  	mutex_lock(®ulator_list_mutex);  	rdev = regulator_dev_lookup(dev, id, &ret);  	if (rdev)  		goto found; +	regulator = ERR_PTR(ret); +  	/*  	 * If we have return value from dev_lookup fail, we do not expect to  	 * succeed, so, quit with appropriate error value  	 */ -	if (ret) { -		regulator = ERR_PTR(ret); +	if (ret && ret != -ENODEV)  		goto out; -	} - -	if (board_wants_dummy_regulator) { -		rdev = dummy_regulator_rdev; -		goto found; -	} -#ifdef CONFIG_REGULATOR_DUMMY  	if (!devname)  		devname = "deviceless"; -	/* If the board didn't flag that it was fully constrained then -	 * substitute in a dummy regulator so consumers can continue. +	/* +	 * Assume that a regulator is physically present and enabled +	 * even if it isn't hooked up and just provide a dummy.  	 */ -	if (!has_full_constraints) { +	if (have_full_constraints() && allow_dummy) {  		pr_warn("%s supply %s not found, using dummy regulator\n",  			devname, id); +  		rdev = dummy_regulator_rdev;  		goto found; +	/* Don't log an error when called from regulator_get_optional() */ +	} else if (!have_full_constraints() || exclusive) { +		dev_warn(dev, "dummy supplies not allowed\n");  	} -#endif  	mutex_unlock(®ulator_list_mutex);  	return regulator; @@ -1349,44 +1428,10 @@ out:   */  struct regulator *regulator_get(struct device *dev, const char *id)  { -	return _regulator_get(dev, id, false); +	return _regulator_get(dev, id, false, true);  }  EXPORT_SYMBOL_GPL(regulator_get); -static void devm_regulator_release(struct device *dev, void *res) -{ -	regulator_put(*(struct regulator **)res); -} - -/** - * devm_regulator_get - Resource managed regulator_get() - * @dev: device for regulator "consumer" - * @id: Supply name or regulator ID. - * - * Managed regulator_get(). Regulators returned from this function are - * automatically regulator_put() on driver detach. See regulator_get() for more - * information. - */ -struct regulator *devm_regulator_get(struct device *dev, const char *id) -{ -	struct regulator **ptr, *regulator; - -	ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); -	if (!ptr) -		return ERR_PTR(-ENOMEM); - -	regulator = regulator_get(dev, id); -	if (!IS_ERR(regulator)) { -		*ptr = regulator; -		devres_add(dev, ptr); -	} else { -		devres_free(ptr); -	} - -	return regulator; -} -EXPORT_SYMBOL_GPL(devm_regulator_get); -  /**   * regulator_get_exclusive - obtain exclusive access to a regulator.   * @dev: device for regulator "consumer" @@ -1394,9 +1439,9 @@ EXPORT_SYMBOL_GPL(devm_regulator_get);   *   * Returns a struct regulator corresponding to the regulator producer,   * or IS_ERR() condition containing errno.  Other consumers will be - * unable to obtain this reference is held and the use count for the - * regulator will be initialised to reflect the current state of the - * regulator. + * unable to obtain this regulator while this reference is held and the + * use count for the regulator will be initialised to reflect the current + * state of the regulator.   *   * This is intended for use by consumers which cannot tolerate shared   * use of the regulator such as those which need to force the @@ -1410,7 +1455,7 @@ EXPORT_SYMBOL_GPL(devm_regulator_get);   */  struct regulator *regulator_get_exclusive(struct device *dev, const char *id)  { -	return _regulator_get(dev, id, true); +	return _regulator_get(dev, id, true, false);  }  EXPORT_SYMBOL_GPL(regulator_get_exclusive); @@ -1420,10 +1465,7 @@ EXPORT_SYMBOL_GPL(regulator_get_exclusive);   * @id: Supply name or regulator ID.   *   * Returns a struct regulator corresponding to the regulator producer, - * or IS_ERR() condition containing errno.  Other consumers will be - * unable to obtain this reference is held and the use count for the - * regulator will be initialised to reflect the current state of the - * regulator. + * or IS_ERR() condition containing errno.   *   * This is intended for use by consumers for devices which can have   * some supplies unconnected in normal use, such as some MMC devices. @@ -1439,40 +1481,10 @@ EXPORT_SYMBOL_GPL(regulator_get_exclusive);   */  struct regulator *regulator_get_optional(struct device *dev, const char *id)  { -	return _regulator_get(dev, id, 0); +	return _regulator_get(dev, id, false, false);  }  EXPORT_SYMBOL_GPL(regulator_get_optional); -/** - * devm_regulator_get_optional - Resource managed regulator_get_optional() - * @dev: device for regulator "consumer" - * @id: Supply name or regulator ID. - * - * Managed regulator_get_optional(). Regulators returned from this - * function are automatically regulator_put() on driver detach. See - * regulator_get_optional() for more information. - */ -struct regulator *devm_regulator_get_optional(struct device *dev, -					      const char *id) -{ -	struct regulator **ptr, *regulator; - -	ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); -	if (!ptr) -		return ERR_PTR(-ENOMEM); - -	regulator = regulator_get_optional(dev, id); -	if (!IS_ERR(regulator)) { -		*ptr = regulator; -		devres_add(dev, ptr); -	} else { -		devres_free(ptr); -	} - -	return regulator; -} -EXPORT_SYMBOL_GPL(devm_regulator_get_optional); -  /* Locks held by regulator_put() */  static void _regulator_put(struct regulator *regulator)  { @@ -1499,36 +1511,6 @@ static void _regulator_put(struct regulator *regulator)  }  /** - * devm_regulator_get_exclusive - Resource managed regulator_get_exclusive() - * @dev: device for regulator "consumer" - * @id: Supply name or regulator ID. - * - * Managed regulator_get_exclusive(). Regulators returned from this function - * are automatically regulator_put() on driver detach. See regulator_get() for - * more information. - */ -struct regulator *devm_regulator_get_exclusive(struct device *dev, -					       const char *id) -{ -	struct regulator **ptr, *regulator; - -	ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); -	if (!ptr) -		return ERR_PTR(-ENOMEM); - -	regulator = _regulator_get(dev, id, 1); -	if (!IS_ERR(regulator)) { -		*ptr = regulator; -		devres_add(dev, ptr); -	} else { -		devres_free(ptr); -	} - -	return regulator; -} -EXPORT_SYMBOL_GPL(devm_regulator_get_exclusive); - -/**   * regulator_put - "free" the regulator source   * @regulator: regulator source   * @@ -1544,34 +1526,134 @@ void regulator_put(struct regulator *regulator)  }  EXPORT_SYMBOL_GPL(regulator_put); -static int devm_regulator_match(struct device *dev, void *res, void *data) +/** + * regulator_register_supply_alias - Provide device alias for supply lookup + * + * @dev: device that will be given as the regulator "consumer" + * @id: Supply name or regulator ID + * @alias_dev: device that should be used to lookup the supply + * @alias_id: Supply name or regulator ID that should be used to lookup the + * supply + * + * All lookups for id on dev will instead be conducted for alias_id on + * alias_dev. + */ +int regulator_register_supply_alias(struct device *dev, const char *id, +				    struct device *alias_dev, +				    const char *alias_id)  { -	struct regulator **r = res; -	if (!r || !*r) { -		WARN_ON(!r || !*r); -		return 0; +	struct regulator_supply_alias *map; + +	map = regulator_find_supply_alias(dev, id); +	if (map) +		return -EEXIST; + +	map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL); +	if (!map) +		return -ENOMEM; + +	map->src_dev = dev; +	map->src_supply = id; +	map->alias_dev = alias_dev; +	map->alias_supply = alias_id; + +	list_add(&map->list, ®ulator_supply_alias_list); + +	pr_info("Adding alias for supply %s,%s -> %s,%s\n", +		id, dev_name(dev), alias_id, dev_name(alias_dev)); + +	return 0; +} +EXPORT_SYMBOL_GPL(regulator_register_supply_alias); + +/** + * regulator_unregister_supply_alias - Remove device alias + * + * @dev: device that will be given as the regulator "consumer" + * @id: Supply name or regulator ID + * + * Remove a lookup alias if one exists for id on dev. + */ +void regulator_unregister_supply_alias(struct device *dev, const char *id) +{ +	struct regulator_supply_alias *map; + +	map = regulator_find_supply_alias(dev, id); +	if (map) { +		list_del(&map->list); +		kfree(map); +	} +} +EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias); + +/** + * regulator_bulk_register_supply_alias - register multiple aliases + * + * @dev: device that will be given as the regulator "consumer" + * @id: List of supply names or regulator IDs + * @alias_dev: device that should be used to lookup the supply + * @alias_id: List of supply names or regulator IDs that should be used to + * lookup the supply + * @num_id: Number of aliases to register + * + * @return 0 on success, an errno on failure. + * + * This helper function allows drivers to register several supply + * aliases in one operation.  If any of the aliases cannot be + * registered any aliases that were registered will be removed + * before returning to the caller. + */ +int regulator_bulk_register_supply_alias(struct device *dev, +					 const char *const *id, +					 struct device *alias_dev, +					 const char *const *alias_id, +					 int num_id) +{ +	int i; +	int ret; + +	for (i = 0; i < num_id; ++i) { +		ret = regulator_register_supply_alias(dev, id[i], alias_dev, +						      alias_id[i]); +		if (ret < 0) +			goto err;  	} -	return *r == data; + +	return 0; + +err: +	dev_err(dev, +		"Failed to create supply alias %s,%s -> %s,%s\n", +		id[i], dev_name(dev), alias_id[i], dev_name(alias_dev)); + +	while (--i >= 0) +		regulator_unregister_supply_alias(dev, id[i]); + +	return ret;  } +EXPORT_SYMBOL_GPL(regulator_bulk_register_supply_alias);  /** - * devm_regulator_put - Resource managed regulator_put() - * @regulator: regulator to free + * regulator_bulk_unregister_supply_alias - unregister multiple aliases   * - * Deallocate a regulator allocated with devm_regulator_get(). Normally - * this function will not need to be called and the resource management - * code will ensure that the resource is freed. + * @dev: device that will be given as the regulator "consumer" + * @id: List of supply names or regulator IDs + * @num_id: Number of aliases to unregister + * + * This helper function allows drivers to unregister several supply + * aliases in one operation.   */ -void devm_regulator_put(struct regulator *regulator) +void regulator_bulk_unregister_supply_alias(struct device *dev, +					    const char *const *id, +					    int num_id)  { -	int rc; +	int i; -	rc = devres_release(regulator->dev, devm_regulator_release, -			    devm_regulator_match, regulator); -	if (rc != 0) -		WARN_ON(rc); +	for (i = 0; i < num_id; ++i) +		regulator_unregister_supply_alias(dev, id[i]);  } -EXPORT_SYMBOL_GPL(devm_regulator_put); +EXPORT_SYMBOL_GPL(regulator_bulk_unregister_supply_alias); +  /* Manage enable GPIO list. Same GPIO pin can be shared among regulators */  static int regulator_ena_gpio_request(struct regulator_dev *rdev, @@ -1704,11 +1786,39 @@ static int _regulator_do_enable(struct regulator_dev *rdev)  	 * together.  */  	trace_regulator_enable_delay(rdev_get_name(rdev)); -	if (delay >= 1000) { -		mdelay(delay / 1000); -		udelay(delay % 1000); -	} else if (delay) { -		udelay(delay); +	/* +	 * Delay for the requested amount of time as per the guidelines in: +	 * +	 *     Documentation/timers/timers-howto.txt +	 * +	 * The assumption here is that regulators will never be enabled in +	 * atomic context and therefore sleeping functions can be used. +	 */ +	if (delay) { +		unsigned int ms = delay / 1000; +		unsigned int us = delay % 1000; + +		if (ms > 0) { +			/* +			 * For small enough values, handle super-millisecond +			 * delays in the usleep_range() call below. +			 */ +			if (ms < 20) +				us += ms * 1000; +			else +				msleep(ms); +		} + +		/* +		 * Give the scheduler some room to coalesce with any other +		 * wakeup sources. For delays shorter than 10 us, don't even +		 * bother setting up high-resolution timers and just busy- +		 * loop. +		 */ +		if (us >= 10) +			usleep_range(us, us + 100); +		else +			udelay(us);  	}  	trace_regulator_enable_complete(rdev_get_name(rdev)); @@ -1805,8 +1915,6 @@ static int _regulator_do_disable(struct regulator_dev *rdev)  	trace_regulator_disable_complete(rdev_get_name(rdev)); -	_notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, -			     NULL);  	return 0;  } @@ -1830,6 +1938,8 @@ static int _regulator_disable(struct regulator_dev *rdev)  				rdev_err(rdev, "failed to disable\n");  				return ret;  			} +			_notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, +					NULL);  		}  		rdev->use_count = 0; @@ -1882,20 +1992,16 @@ static int _regulator_force_disable(struct regulator_dev *rdev)  {  	int ret = 0; -	/* force disable */ -	if (rdev->desc->ops->disable) { -		/* ah well, who wants to live forever... */ -		ret = rdev->desc->ops->disable(rdev); -		if (ret < 0) { -			rdev_err(rdev, "failed to force disable\n"); -			return ret; -		} -		/* notify other consumers that power has been forced off */ -		_notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | -			REGULATOR_EVENT_DISABLE, NULL); +	ret = _regulator_do_disable(rdev); +	if (ret < 0) { +		rdev_err(rdev, "failed to force disable\n"); +		return ret;  	} -	return ret; +	_notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | +			REGULATOR_EVENT_DISABLE, NULL); + +	return 0;  }  /** @@ -2039,7 +2145,7 @@ EXPORT_SYMBOL_GPL(regulator_is_enabled);   * @regulator: regulator source   *   * Returns positive if the regulator driver backing the source/client - * can change its voltage, false otherwise. Usefull for detecting fixed + * can change its voltage, false otherwise. Useful for detecting fixed   * or dummy regulators and disabling voltage change logic in the client   * driver.   */ @@ -2094,6 +2200,9 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector)  	struct regulator_ops	*ops = rdev->desc->ops;  	int			ret; +	if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector) +		return rdev->desc->fixed_uV; +  	if (!ops->list_voltage || selector >= rdev->desc->n_voltages)  		return -EINVAL; @@ -2146,7 +2255,7 @@ int regulator_is_supported_voltage(struct regulator *regulator,  	if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {  		ret = regulator_get_voltage(regulator);  		if (ret >= 0) -			return (min_uV <= ret && ret <= max_uV); +			return min_uV <= ret && ret <= max_uV;  		else  			return ret;  	} @@ -2219,6 +2328,10 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,  			    regulator_list_voltage_linear)  				ret = regulator_map_voltage_linear(rdev,  								min_uV, max_uV); +			else if (rdev->desc->ops->list_voltage == +				 regulator_list_voltage_linear_range) +				ret = regulator_map_voltage_linear_range(rdev, +								min_uV, max_uV);  			else  				ret = regulator_map_voltage_iterate(rdev,  								min_uV, max_uV); @@ -2297,6 +2410,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)  	struct regulator_dev *rdev = regulator->rdev;  	int ret = 0;  	int old_min_uV, old_max_uV; +	int current_uV;  	mutex_lock(&rdev->mutex); @@ -2307,6 +2421,19 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)  	if (regulator->min_uV == min_uV && regulator->max_uV == max_uV)  		goto out; +	/* If we're trying to set a range that overlaps the current voltage, +	 * return succesfully even though the regulator does not support +	 * changing the voltage. +	 */ +	if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { +		current_uV = _regulator_get_voltage(rdev); +		if (min_uV <= current_uV && current_uV <= max_uV) { +			regulator->min_uV = min_uV; +			regulator->max_uV = max_uV; +			goto out; +		} +	} +  	/* sanity check */  	if (!rdev->desc->ops->set_voltage &&  	    !rdev->desc->ops->set_voltage_sel) { @@ -2318,7 +2445,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)  	ret = regulator_check_voltage(rdev, &min_uV, &max_uV);  	if (ret < 0)  		goto out; -	 +  	/* restore original values in case of error */  	old_min_uV = regulator->min_uV;  	old_max_uV = regulator->max_uV; @@ -2332,7 +2459,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)  	ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);  	if (ret < 0)  		goto out2; -	 +  out:  	mutex_unlock(&rdev->mutex);  	return ret; @@ -2489,6 +2616,8 @@ static int _regulator_get_voltage(struct regulator_dev *rdev)  		ret = rdev->desc->ops->get_voltage(rdev);  	} else if (rdev->desc->ops->list_voltage) {  		ret = rdev->desc->ops->list_voltage(rdev, 0); +	} else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) { +		ret = rdev->desc->fixed_uV;  	} else {  		return -EINVAL;  	} @@ -2912,52 +3041,6 @@ err:  }  EXPORT_SYMBOL_GPL(regulator_bulk_get); -/** - * devm_regulator_bulk_get - managed get multiple regulator consumers - * - * @dev:           Device to supply - * @num_consumers: Number of consumers to register - * @consumers:     Configuration of consumers; clients are stored here. - * - * @return 0 on success, an errno on failure. - * - * This helper function allows drivers to get several regulator - * consumers in one operation with management, the regulators will - * automatically be freed when the device is unbound.  If any of the - * regulators cannot be acquired then any regulators that were - * allocated will be freed before returning to the caller. - */ -int devm_regulator_bulk_get(struct device *dev, int num_consumers, -			    struct regulator_bulk_data *consumers) -{ -	int i; -	int ret; - -	for (i = 0; i < num_consumers; i++) -		consumers[i].consumer = NULL; - -	for (i = 0; i < num_consumers; i++) { -		consumers[i].consumer = devm_regulator_get(dev, -							   consumers[i].supply); -		if (IS_ERR(consumers[i].consumer)) { -			ret = PTR_ERR(consumers[i].consumer); -			dev_err(dev, "Failed to get supply '%s': %d\n", -				consumers[i].supply, ret); -			consumers[i].consumer = NULL; -			goto err; -		} -	} - -	return 0; - -err: -	for (i = 0; i < num_consumers && consumers[i].consumer; i++) -		devm_regulator_put(consumers[i].consumer); - -	return ret; -} -EXPORT_SYMBOL_GPL(devm_regulator_bulk_get); -  static void regulator_bulk_enable_async(void *data, async_cookie_t cookie)  {  	struct regulator_bulk_data *bulk = data; @@ -3170,7 +3253,8 @@ static int add_regulator_attributes(struct regulator_dev *rdev)  	/* some attributes need specific methods to be displayed */  	if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) ||  	    (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) || -	    (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0)) { +	    (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) || +		(rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1))) {  		status = device_create_file(dev, &dev_attr_microvolts);  		if (status < 0)  			return status; @@ -3374,7 +3458,7 @@ regulator_register(const struct regulator_desc *regulator_desc,  	/* register with sysfs */  	rdev->dev.class = ®ulator_class; -	rdev->dev.of_node = config->of_node; +	rdev->dev.of_node = of_node_get(config->of_node);  	rdev->dev.parent = dev;  	dev_set_name(&rdev->dev, "regulator.%d",  		     atomic_inc_return(®ulator_no) - 1); @@ -3516,6 +3600,7 @@ void regulator_unregister(struct regulator_dev *rdev)  	list_del(&rdev->list);  	kfree(rdev->constraints);  	regulator_ena_gpio_free(rdev); +	of_node_put(rdev->dev.of_node);  	device_unregister(&rdev->dev);  	mutex_unlock(®ulator_list_mutex);  } @@ -3568,23 +3653,18 @@ int regulator_suspend_finish(void)  	mutex_lock(®ulator_list_mutex);  	list_for_each_entry(rdev, ®ulator_list, list) { -		struct regulator_ops *ops = rdev->desc->ops; -  		mutex_lock(&rdev->mutex); -		if ((rdev->use_count > 0  || rdev->constraints->always_on) && -				ops->enable) { -			error = ops->enable(rdev); +		if (rdev->use_count > 0  || rdev->constraints->always_on) { +			error = _regulator_do_enable(rdev);  			if (error)  				ret = error;  		} else { -			if (!has_full_constraints) -				goto unlock; -			if (!ops->disable) +			if (!have_full_constraints())  				goto unlock;  			if (!_regulator_is_enabled(rdev))  				goto unlock; -			error = ops->disable(rdev); +			error = _regulator_do_disable(rdev);  			if (error)  				ret = error;  		} @@ -3614,22 +3694,6 @@ void regulator_has_full_constraints(void)  EXPORT_SYMBOL_GPL(regulator_has_full_constraints);  /** - * regulator_use_dummy_regulator - Provide a dummy regulator when none is found - * - * Calling this function will cause the regulator API to provide a - * dummy regulator to consumers if no physical regulator is found, - * allowing most consumers to proceed as though a regulator were - * configured.  This allows systems such as those with software - * controllable regulators for the CPU core only to be brought up more - * readily. - */ -void regulator_use_dummy_regulator(void) -{ -	board_wants_dummy_regulator = true; -} -EXPORT_SYMBOL_GPL(regulator_use_dummy_regulator); - -/**   * rdev_get_drvdata - get rdev regulator driver data   * @rdev: regulator   * @@ -3767,14 +3831,18 @@ static int __init regulator_init_complete(void)  	mutex_lock(®ulator_list_mutex);  	/* If we have a full configuration then disable any regulators -	 * which are not in use or always_on.  This will become the -	 * default behaviour in the future. +	 * we have permission to change the status for and which are +	 * not in use or always_on.  This is effectively the default +	 * for DT and ACPI as they have full constraints.  	 */  	list_for_each_entry(rdev, ®ulator_list, list) {  		ops = rdev->desc->ops;  		c = rdev->constraints; -		if (!ops->disable || (c && c->always_on)) +		if (c && c->always_on) +			continue; + +		if (c && !(c->valid_ops_mask & REGULATOR_CHANGE_STATUS))  			continue;  		mutex_lock(&rdev->mutex); @@ -3791,14 +3859,13 @@ static int __init regulator_init_complete(void)  		if (!enabled)  			goto unlock; -		if (has_full_constraints) { +		if (have_full_constraints()) {  			/* We log since this may kill the system if it  			 * goes wrong. */  			rdev_info(rdev, "disabling\n"); -			ret = ops->disable(rdev); -			if (ret != 0) { +			ret = _regulator_do_disable(rdev); +			if (ret != 0)  				rdev_err(rdev, "couldn't disable: %d\n", ret); -			}  		} else {  			/* The intention is that in future we will  			 * assume that full constraints are provided @@ -3816,4 +3883,4 @@ unlock:  	return 0;  } -late_initcall(regulator_init_complete); +late_initcall_sync(regulator_init_complete); diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index f06854cf8cf..b431ae357fc 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -253,10 +253,8 @@ static int da9034_set_dvc_voltage_sel(struct regulator_dev *rdev,  }  static const struct regulator_linear_range da9034_ldo12_ranges[] = { -	{ .min_uV = 1700000, .max_uV = 2050000, .min_sel =  0, .max_sel = 7, -	  .uV_step =  50000 }, -	{ .min_uV = 2700000, .max_uV = 3050000, .min_sel =  8, .max_sel = 15, -	  .uV_step =  50000 }, +	REGULATOR_LINEAR_RANGE(1700000, 0, 7, 50000), +	REGULATOR_LINEAR_RANGE(2700000, 8, 15, 50000),  };  static struct regulator_ops da903x_regulator_ldo_ops = { @@ -463,7 +461,7 @@ static int da903x_regulator_probe(struct platform_device *pdev)  	config.init_data = dev_get_platdata(&pdev->dev);  	config.driver_data = ri; -	rdev = regulator_register(&ri->desc, &config); +	rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config);  	if (IS_ERR(rdev)) {  		dev_err(&pdev->dev, "failed to register regulator %s\n",  				ri->desc.name); @@ -474,21 +472,12 @@ static int da903x_regulator_probe(struct platform_device *pdev)  	return 0;  } -static int da903x_regulator_remove(struct platform_device *pdev) -{ -	struct regulator_dev *rdev = platform_get_drvdata(pdev); - -	regulator_unregister(rdev); -	return 0; -} -  static struct platform_driver da903x_regulator_driver = {  	.driver	= {  		.name	= "da903x-regulator",  		.owner	= THIS_MODULE,  	},  	.probe		= da903x_regulator_probe, -	.remove		= da903x_regulator_remove,  };  static int __init da903x_regulator_init(void) diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index 1e4d483f616..fdb6ea8ae7e 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -70,6 +70,7 @@ struct da9052_regulator_info {  	int step_uV;  	int min_uV;  	int max_uV; +	unsigned char activate_bit;  };  struct da9052_regulator { @@ -209,6 +210,61 @@ static int da9052_map_voltage(struct regulator_dev *rdev,  	return sel;  } +static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev, +					    unsigned int selector) +{ +	struct da9052_regulator *regulator = rdev_get_drvdata(rdev); +	struct da9052_regulator_info *info = regulator->info; +	int id = rdev_get_id(rdev); +	int ret; + +	ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg, +				rdev->desc->vsel_mask, selector); +	if (ret < 0) +		return ret; + +	/* Some LDOs and DCDCs are DVC controlled which requires enabling of +	 * the activate bit to implment the changes on the output. +	 */ +	switch (id) { +	case DA9052_ID_BUCK1: +	case DA9052_ID_BUCK2: +	case DA9052_ID_BUCK3: +	case DA9052_ID_LDO2: +	case DA9052_ID_LDO3: +		ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, +					info->activate_bit, info->activate_bit); +		break; +	} + +	return ret; +} + +static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev, +						 unsigned int old_sel, +						 unsigned int new_sel) +{ +	struct da9052_regulator *regulator = rdev_get_drvdata(rdev); +	struct da9052_regulator_info *info = regulator->info; +	int id = rdev_get_id(rdev); +	int ret = 0; + +	/* The DVC controlled LDOs and DCDCs ramp with 6.25mV/µs after enabling +	 * the activate bit. +	 */ +	switch (id) { +	case DA9052_ID_BUCK1: +	case DA9052_ID_BUCK2: +	case DA9052_ID_BUCK3: +	case DA9052_ID_LDO2: +	case DA9052_ID_LDO3: +		ret = (new_sel - old_sel) * info->step_uV / 6250; +		break; +	} + +	return ret; +} +  static struct regulator_ops da9052_dcdc_ops = {  	.get_current_limit = da9052_dcdc_get_current_limit,  	.set_current_limit = da9052_dcdc_set_current_limit, @@ -216,7 +272,8 @@ static struct regulator_ops da9052_dcdc_ops = {  	.list_voltage = da9052_list_voltage,  	.map_voltage = da9052_map_voltage,  	.get_voltage_sel = regulator_get_voltage_sel_regmap, -	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.set_voltage_sel = da9052_regulator_set_voltage_sel, +	.set_voltage_time_sel = da9052_regulator_set_voltage_time_sel,  	.is_enabled = regulator_is_enabled_regmap,  	.enable = regulator_enable_regmap,  	.disable = regulator_disable_regmap, @@ -226,7 +283,8 @@ static struct regulator_ops da9052_ldo_ops = {  	.list_voltage = da9052_list_voltage,  	.map_voltage = da9052_map_voltage,  	.get_voltage_sel = regulator_get_voltage_sel_regmap, -	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.set_voltage_sel = da9052_regulator_set_voltage_sel, +	.set_voltage_time_sel = da9052_regulator_set_voltage_time_sel,  	.is_enabled = regulator_is_enabled_regmap,  	.enable = regulator_enable_regmap,  	.disable = regulator_disable_regmap, @@ -243,14 +301,13 @@ static struct regulator_ops da9052_ldo_ops = {  		.owner = THIS_MODULE,\  		.vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \  		.vsel_mask = (1 << (sbits)) - 1,\ -		.apply_reg = DA9052_SUPPLY_REG, \ -		.apply_bit = (abits), \  		.enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \  		.enable_mask = 1 << (ebits),\  	},\  	.min_uV = (min) * 1000,\  	.max_uV = (max) * 1000,\  	.step_uV = (step) * 1000,\ +	.activate_bit = (abits),\  }  #define DA9052_DCDC(_id, step, min, max, sbits, ebits, abits) \ @@ -264,14 +321,13 @@ static struct regulator_ops da9052_ldo_ops = {  		.owner = THIS_MODULE,\  		.vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \  		.vsel_mask = (1 << (sbits)) - 1,\ -		.apply_reg = DA9052_SUPPLY_REG, \ -		.apply_bit = (abits), \  		.enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \  		.enable_mask = 1 << (ebits),\  	},\  	.min_uV = (min) * 1000,\  	.max_uV = (max) * 1000,\  	.step_uV = (step) * 1000,\ +	.activate_bit = (abits),\  }  static struct da9052_regulator_info da9052_regulator_info[] = { @@ -372,7 +428,7 @@ static int da9052_regulator_probe(struct platform_device *pdev)  		if (!nproot)  			return -ENODEV; -		nproot = of_find_node_by_name(nproot, "regulators"); +		nproot = of_get_child_by_name(nproot, "regulators");  		if (!nproot)  			return -ENODEV; @@ -389,8 +445,9 @@ static int da9052_regulator_probe(struct platform_device *pdev)  #endif  	} -	regulator->rdev = regulator_register(®ulator->info->reg_desc, -					     &config); +	regulator->rdev = devm_regulator_register(&pdev->dev, +						  ®ulator->info->reg_desc, +						  &config);  	if (IS_ERR(regulator->rdev)) {  		dev_err(&pdev->dev, "failed to register regulator %s\n",  			regulator->info->reg_desc.name); @@ -402,17 +459,8 @@ static int da9052_regulator_probe(struct platform_device *pdev)  	return 0;  } -static int da9052_regulator_remove(struct platform_device *pdev) -{ -	struct da9052_regulator *regulator = platform_get_drvdata(pdev); - -	regulator_unregister(regulator->rdev); -	return 0; -} -  static struct platform_driver da9052_regulator_driver = {  	.probe = da9052_regulator_probe, -	.remove = da9052_regulator_remove,  	.driver = {  		.name = "da9052-regulator",  		.owner = THIS_MODULE, diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c index 77b53e5a231..9516317e1a9 100644 --- a/drivers/regulator/da9055-regulator.c +++ b/drivers/regulator/da9055-regulator.c @@ -19,6 +19,8 @@  #include <linux/platform_device.h>  #include <linux/regulator/driver.h>  #include <linux/regulator/machine.h> +#include <linux/of.h> +#include <linux/regulator/of_regulator.h>  #include <linux/mfd/da9055/core.h>  #include <linux/mfd/da9055/reg.h> @@ -446,6 +448,9 @@ static int da9055_gpio_init(struct da9055_regulator *regulator,  	struct da9055_regulator_info *info = regulator->info;  	int ret = 0; +	if (!pdata) +		return 0; +  	if (pdata->gpio_ren && pdata->gpio_ren[id]) {  		char name[18];  		int gpio_mux = pdata->gpio_ren[id]; @@ -530,6 +535,59 @@ static inline struct da9055_regulator_info *find_regulator_info(int id)  	return NULL;  } +#ifdef CONFIG_OF +static struct of_regulator_match da9055_reg_matches[] = { +	{ .name = "BUCK1", }, +	{ .name = "BUCK2", }, +	{ .name = "LDO1", }, +	{ .name = "LDO2", }, +	{ .name = "LDO3", }, +	{ .name = "LDO4", }, +	{ .name = "LDO5", }, +	{ .name = "LDO6", }, +}; + +static int da9055_regulator_dt_init(struct platform_device *pdev, +				    struct da9055_regulator *regulator, +				    struct regulator_config *config, +				    int regid) +{ +	struct device_node *nproot, *np; +	int ret; + +	nproot = of_node_get(pdev->dev.parent->of_node); +	if (!nproot) +		return -ENODEV; + +	np = of_get_child_by_name(nproot, "regulators"); +	if (!np) +		return -ENODEV; + +	ret = of_regulator_match(&pdev->dev, np, &da9055_reg_matches[regid], 1); +	of_node_put(nproot); +	if (ret < 0) { +		dev_err(&pdev->dev, "Error matching regulator: %d\n", ret); +		return ret; +	} + +	config->init_data = da9055_reg_matches[regid].init_data; +	config->of_node = da9055_reg_matches[regid].of_node; + +	if (!config->of_node) +		return -ENODEV; + +	return 0; +} +#else +static inline int da9055_regulator_dt_init(struct platform_device *pdev, +				       struct da9055_regulator *regulator, +				       struct regulator_config *config, +				       int regid) +{ +	return -ENODEV; +} +#endif /* CONFIG_OF */ +  static int da9055_regulator_probe(struct platform_device *pdev)  {  	struct regulator_config config = { }; @@ -538,9 +596,6 @@ static int da9055_regulator_probe(struct platform_device *pdev)  	struct da9055_pdata *pdata = dev_get_platdata(da9055->dev);  	int ret, irq; -	if (pdata == NULL || pdata->regulators[pdev->id] == NULL) -		return -ENODEV; -  	regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9055_regulator),  				 GFP_KERNEL);  	if (!regulator) @@ -557,26 +612,34 @@ static int da9055_regulator_probe(struct platform_device *pdev)  	config.driver_data = regulator;  	config.regmap = da9055->regmap; -	if (pdata && pdata->regulators) +	if (pdata && pdata->regulators) {  		config.init_data = pdata->regulators[pdev->id]; +	} else { +		ret = da9055_regulator_dt_init(pdev, regulator, &config, +					       pdev->id); +		if (ret < 0) +			return ret; +	}  	ret = da9055_gpio_init(regulator, &config, pdata, pdev->id);  	if (ret < 0)  		return ret; -	regulator->rdev = regulator_register(®ulator->info->reg_desc, -					     &config); +	regulator->rdev = devm_regulator_register(&pdev->dev, +						  ®ulator->info->reg_desc, +						  &config);  	if (IS_ERR(regulator->rdev)) {  		dev_err(&pdev->dev, "Failed to register regulator %s\n",  			regulator->info->reg_desc.name); -		ret = PTR_ERR(regulator->rdev); -		return ret; +		return PTR_ERR(regulator->rdev);  	}  	/* Only LDO 5 and 6 has got the over current interrupt */  	if (pdev->id == DA9055_ID_LDO5 || pdev->id ==  DA9055_ID_LDO6) {  		irq = platform_get_irq_byname(pdev, "REGULATOR"); -		irq = regmap_irq_get_virq(da9055->irq_data, irq); +		if (irq < 0) +			return irq; +  		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,  						da9055_ldo5_6_oc_irq,  						IRQF_TRIGGER_HIGH | @@ -588,7 +651,7 @@ static int da9055_regulator_probe(struct platform_device *pdev)  				dev_err(&pdev->dev,  				"Failed to request Regulator IRQ %d: %d\n",  				irq, ret); -				goto err_regulator; +				return ret;  			}  		}  	} @@ -596,24 +659,10 @@ static int da9055_regulator_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, regulator);  	return 0; - -err_regulator: -	regulator_unregister(regulator->rdev); -	return ret; -} - -static int da9055_regulator_remove(struct platform_device *pdev) -{ -	struct da9055_regulator *regulator = platform_get_drvdata(pdev); - -	regulator_unregister(regulator->rdev); - -	return 0;  }  static struct platform_driver da9055_regulator_driver = {  	.probe = da9055_regulator_probe, -	.remove = da9055_regulator_remove,  	.driver = {  		.name = "da9055-regulator",  		.owner = THIS_MODULE, diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index 1a781639077..7c9461d1331 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -1,3 +1,4 @@ +  /*   * Regulator driver for DA9063 PMIC series   * @@ -60,7 +61,8 @@ struct da9063_regulator_info {  	.desc.ops = &da9063_ldo_ops, \  	.desc.min_uV = (min_mV) * 1000, \  	.desc.uV_step = (step_mV) * 1000, \ -	.desc.n_voltages = (((max_mV) - (min_mV))/(step_mV) + 1), \ +	.desc.n_voltages = (((max_mV) - (min_mV))/(step_mV) + 1 \ +		+ (DA9063_V##regl_name##_BIAS)), \  	.desc.enable_reg = DA9063_REG_##regl_name##_CONT, \  	.desc.enable_mask = DA9063_LDO_EN, \  	.desc.vsel_reg = DA9063_REG_V##regl_name##_A, \ @@ -363,7 +365,7 @@ static int da9063_set_suspend_voltage(struct regulator_dev *rdev, int uV)  	sel = regulator_map_voltage_linear(rdev, uV, uV);  	if (sel < 0) -		return -EINVAL; +		return sel;  	sel <<= ffs(rdev->desc->vsel_mask) - 1; @@ -664,7 +666,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(  	struct device_node *node;  	int i, n, num; -	node = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); +	node = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");  	if (!node) {  		dev_err(&pdev->dev, "Regulators device node not found\n");  		return ERR_PTR(-ENODEV); @@ -672,6 +674,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(  	num = of_regulator_match(&pdev->dev, node, da9063_matches,  				 ARRAY_SIZE(da9063_matches)); +	of_node_put(node);  	if (num < 0) {  		dev_err(&pdev->dev, "Failed to match regulators\n");  		return ERR_PTR(-EINVAL); @@ -708,8 +711,8 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt(  		struct platform_device *pdev,  		struct of_regulator_match **da9063_reg_matches)  { -	da9063_reg_matches = NULL; -	return PTR_ERR(-ENODEV); +	*da9063_reg_matches = NULL; +	return ERR_PTR(-ENODEV);  }  #endif @@ -717,7 +720,7 @@ static int da9063_regulator_probe(struct platform_device *pdev)  {  	struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent);  	struct da9063_pdata *da9063_pdata = dev_get_platdata(da9063->dev); -	struct of_regulator_match *da9063_reg_matches; +	struct of_regulator_match *da9063_reg_matches = NULL;  	struct da9063_regulators_pdata *regl_pdata;  	const struct da9063_dev_model *model;  	struct da9063_regulators *regulators; @@ -754,7 +757,7 @@ static int da9063_regulator_probe(struct platform_device *pdev)  	if (ret < 0) {  		dev_err(&pdev->dev,  			"Error while reading BUCKs configuration\n"); -		return -EIO; +		return ret;  	}  	bcores_merged = val & DA9063_BCORE_MERGE;  	bmem_bio_merged = val & DA9063_BUCK_MERGE; @@ -773,10 +776,8 @@ static int da9063_regulator_probe(struct platform_device *pdev)  	size = sizeof(struct da9063_regulators) +  		n_regulators * sizeof(struct da9063_regulator);  	regulators = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); -	if (!regulators) { -		dev_err(&pdev->dev, "No memory for regulators\n"); +	if (!regulators)  		return -ENOMEM; -	}  	regulators->n_regulators = n_regulators;  	platform_set_drvdata(pdev, regulators); @@ -847,13 +848,13 @@ static int da9063_regulator_probe(struct platform_device *pdev)  		if (da9063_reg_matches)  			config.of_node = da9063_reg_matches[id].of_node;  		config.regmap = da9063->regmap; -		regl->rdev = regulator_register(®l->desc, &config); +		regl->rdev = devm_regulator_register(&pdev->dev, ®l->desc, +						     &config);  		if (IS_ERR(regl->rdev)) {  			dev_err(&pdev->dev,  				"Failed to register %s regulator\n",  				regl->desc.name); -			ret = PTR_ERR(regl->rdev); -			goto err; +			return PTR_ERR(regl->rdev);  		}  		id++;  		n++; @@ -862,9 +863,8 @@ static int da9063_regulator_probe(struct platform_device *pdev)  	/* LDOs overcurrent event support */  	irq = platform_get_irq_byname(pdev, "LDO_LIM");  	if (irq < 0) { -		ret = irq;  		dev_err(&pdev->dev, "Failed to get IRQ.\n"); -		goto err; +		return irq;  	}  	regulators->irq_ldo_lim = regmap_irq_get_virq(da9063->regmap_irq, irq); @@ -881,27 +881,15 @@ static int da9063_regulator_probe(struct platform_device *pdev)  	}  	return 0; - -err: -	/* Wind back regulators registeration */ -	while (--n >= 0) -		regulator_unregister(regulators->regulator[n].rdev); - -	return ret;  }  static int da9063_regulator_remove(struct platform_device *pdev)  {  	struct da9063_regulators *regulators = platform_get_drvdata(pdev); -	struct da9063_regulator *regl;  	free_irq(regulators->irq_ldo_lim, regulators);  	free_irq(regulators->irq_uvov, regulators); -	for (regl = ®ulators->regulator[regulators->n_regulators - 1]; -	     regl >= ®ulators->regulator[0]; regl--) -		regulator_unregister(regl->rdev); -  	return 0;  } diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index f0fe54b3897..7a320dd11c4 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -25,6 +25,7 @@  #include <linux/slab.h>  #include <linux/regulator/driver.h>  #include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h>  #include <linux/regmap.h>  #include "da9210-regulator.h" @@ -126,17 +127,15 @@ static int da9210_i2c_probe(struct i2c_client *i2c,  			    const struct i2c_device_id *id)  {  	struct da9210 *chip; -	struct da9210_pdata *pdata = i2c->dev.platform_data; +	struct device *dev = &i2c->dev; +	struct da9210_pdata *pdata = dev_get_platdata(dev);  	struct regulator_dev *rdev = NULL;  	struct regulator_config config = { };  	int error;  	chip = devm_kzalloc(&i2c->dev, sizeof(struct da9210), GFP_KERNEL); -	if (NULL == chip) { -		dev_err(&i2c->dev, -			"Cannot kzalloc memory for regulator structure\n"); +	if (!chip)  		return -ENOMEM; -	}  	chip->regmap = devm_regmap_init_i2c(i2c, &da9210_regmap_config);  	if (IS_ERR(chip->regmap)) { @@ -147,12 +146,13 @@ static int da9210_i2c_probe(struct i2c_client *i2c,  	}  	config.dev = &i2c->dev; -	if (pdata) -		config.init_data = &pdata->da9210_constraints; +	config.init_data = pdata ? &pdata->da9210_constraints : +		of_get_regulator_init_data(dev, dev->of_node);  	config.driver_data = chip;  	config.regmap = chip->regmap; +	config.of_node = dev->of_node; -	rdev = regulator_register(&da9210_reg, &config); +	rdev = devm_regulator_register(&i2c->dev, &da9210_reg, &config);  	if (IS_ERR(rdev)) {  		dev_err(&i2c->dev, "Failed to register DA9210 regulator\n");  		return PTR_ERR(rdev); @@ -165,13 +165,6 @@ static int da9210_i2c_probe(struct i2c_client *i2c,  	return 0;  } -static int da9210_i2c_remove(struct i2c_client *i2c) -{ -	struct da9210 *chip = i2c_get_clientdata(i2c); -	regulator_unregister(chip->rdev); -	return 0; -} -  static const struct i2c_device_id da9210_i2c_id[] = {  	{"da9210", 0},  	{}, @@ -185,7 +178,6 @@ static struct i2c_driver da9210_regulator_driver = {  		.owner = THIS_MODULE,  	},  	.probe = da9210_i2c_probe, -	.remove = da9210_i2c_remove,  	.id_table = da9210_i2c_id,  }; diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c index a53c11a529d..617c1adca81 100644 --- a/drivers/regulator/db8500-prcmu.c +++ b/drivers/regulator/db8500-prcmu.c @@ -263,6 +263,8 @@ dbx500_regulator_info[DB8500_NUM_REGULATORS] = {  			.ops	= &db8500_regulator_ops,  			.type	= REGULATOR_VOLTAGE,  			.owner	= THIS_MODULE, +			.fixed_uV = 1800000, +			.n_voltages = 1,  		},  		.exclude_from_power_state = true,  	}, @@ -431,17 +433,11 @@ static int db8500_regulator_register(struct platform_device *pdev,  	config.of_node = np;  	/* register with the regulator framework */ -	info->rdev = regulator_register(&info->desc, &config); +	info->rdev = devm_regulator_register(&pdev->dev, &info->desc, &config);  	if (IS_ERR(info->rdev)) {  		err = PTR_ERR(info->rdev);  		dev_err(&pdev->dev, "failed to register %s: err %i\n",  			info->desc.name, err); - -		/* if failing, unregister all earlier regulators */ -		while (--id >= 0) { -			info = &dbx500_regulator_info[id]; -			regulator_unregister(info->rdev); -		}  		return err;  	} @@ -530,20 +526,8 @@ static int db8500_regulator_probe(struct platform_device *pdev)  static int db8500_regulator_remove(struct platform_device *pdev)  { -	int i; -  	ux500_regulator_debug_exit(); -	for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) { -		struct dbx500_regulator_info *info; -		info = &dbx500_regulator_info[i]; - -		dev_vdbg(rdev_get_dev(info->rdev), -			"regulator-%s-remove\n", info->desc.name); - -		regulator_unregister(info->rdev); -	} -  	return 0;  } diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c index ce89f7848a5..2d16b9f16de 100644 --- a/drivers/regulator/dbx500-prcmu.c +++ b/drivers/regulator/dbx500-prcmu.c @@ -78,6 +78,7 @@ static struct ux500_regulator_debug {  void ux500_regulator_suspend_debug(void)  {  	int i; +  	for (i = 0; i < rdebug.num_regulators; i++)  		rdebug.state_before_suspend[i] =  			rdebug.regulator_array[i].is_enabled; @@ -86,6 +87,7 @@ void ux500_regulator_suspend_debug(void)  void ux500_regulator_resume_debug(void)  {  	int i; +  	for (i = 0; i < rdebug.num_regulators; i++)  		rdebug.state_after_suspend[i] =  			rdebug.regulator_array[i].is_enabled; @@ -127,9 +129,9 @@ static int ux500_regulator_status_print(struct seq_file *s, void *p)  	int i;  	/* print dump header */ -	err = seq_printf(s, "ux500-regulator status:\n"); +	err = seq_puts(s, "ux500-regulator status:\n");  	if (err < 0) -		dev_err(dev, "seq_printf overflow\n"); +		dev_err(dev, "seq_puts overflow\n");  	err = seq_printf(s, "%31s : %8s : %8s\n", "current",  		"before", "after"); @@ -202,18 +204,12 @@ ux500_regulator_debug_init(struct platform_device *pdev,  	rdebug.num_regulators = num_regulators;  	rdebug.state_before_suspend = kzalloc(num_regulators, GFP_KERNEL); -	if (!rdebug.state_before_suspend) { -		dev_err(&pdev->dev, -			"could not allocate memory for saving state\n"); +	if (!rdebug.state_before_suspend)  		goto exit_destroy_power_state; -	}  	rdebug.state_after_suspend = kzalloc(num_regulators, GFP_KERNEL); -	if (!rdebug.state_after_suspend) { -		dev_err(&pdev->dev, -			"could not allocate memory for saving state\n"); +	if (!rdebug.state_after_suspend)  		goto exit_free; -	}  	dbx500_regulator_testcase(regulator_info, num_regulators);  	return 0; diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c new file mode 100644 index 00000000000..8f785bc9e51 --- /dev/null +++ b/drivers/regulator/devres.c @@ -0,0 +1,415 @@ +/* + * devres.c  --  Voltage/Current Regulator framework devres implementation. + * + * Copyright 2013 Linaro Ltd + * + *  This program is free software; you can redistribute  it and/or modify it + *  under  the terms of  the GNU General  Public License as published by the + *  Free Software Foundation;  either version 2 of the  License, or (at your + *  option) any later version. + * + */ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/driver.h> +#include <linux/module.h> + +#include "internal.h" + +enum { +	NORMAL_GET, +	EXCLUSIVE_GET, +	OPTIONAL_GET, +}; + +static void devm_regulator_release(struct device *dev, void *res) +{ +	regulator_put(*(struct regulator **)res); +} + +static struct regulator *_devm_regulator_get(struct device *dev, const char *id, +					     int get_type) +{ +	struct regulator **ptr, *regulator; + +	ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); +	if (!ptr) +		return ERR_PTR(-ENOMEM); + +	switch (get_type) { +	case NORMAL_GET: +		regulator = regulator_get(dev, id); +		break; +	case EXCLUSIVE_GET: +		regulator = regulator_get_exclusive(dev, id); +		break; +	case OPTIONAL_GET: +		regulator = regulator_get_optional(dev, id); +		break; +	default: +		regulator = ERR_PTR(-EINVAL); +	} + +	if (!IS_ERR(regulator)) { +		*ptr = regulator; +		devres_add(dev, ptr); +	} else { +		devres_free(ptr); +	} + +	return regulator; +} + +/** + * devm_regulator_get - Resource managed regulator_get() + * @dev: device for regulator "consumer" + * @id: Supply name or regulator ID. + * + * Managed regulator_get(). Regulators returned from this function are + * automatically regulator_put() on driver detach. See regulator_get() for more + * information. + */ +struct regulator *devm_regulator_get(struct device *dev, const char *id) +{ +	return _devm_regulator_get(dev, id, NORMAL_GET); +} +EXPORT_SYMBOL_GPL(devm_regulator_get); + +/** + * devm_regulator_get_exclusive - Resource managed regulator_get_exclusive() + * @dev: device for regulator "consumer" + * @id: Supply name or regulator ID. + * + * Managed regulator_get_exclusive(). Regulators returned from this function + * are automatically regulator_put() on driver detach. See regulator_get() for + * more information. + */ +struct regulator *devm_regulator_get_exclusive(struct device *dev, +					       const char *id) +{ +	return _devm_regulator_get(dev, id, EXCLUSIVE_GET); +} +EXPORT_SYMBOL_GPL(devm_regulator_get_exclusive); + +/** + * devm_regulator_get_optional - Resource managed regulator_get_optional() + * @dev: device for regulator "consumer" + * @id: Supply name or regulator ID. + * + * Managed regulator_get_optional(). Regulators returned from this + * function are automatically regulator_put() on driver detach. See + * regulator_get_optional() for more information. + */ +struct regulator *devm_regulator_get_optional(struct device *dev, +					      const char *id) +{ +	return _devm_regulator_get(dev, id, OPTIONAL_GET); +} +EXPORT_SYMBOL_GPL(devm_regulator_get_optional); + +static int devm_regulator_match(struct device *dev, void *res, void *data) +{ +	struct regulator **r = res; +	if (!r || !*r) { +		WARN_ON(!r || !*r); +		return 0; +	} +	return *r == data; +} + +/** + * devm_regulator_put - Resource managed regulator_put() + * @regulator: regulator to free + * + * Deallocate a regulator allocated with devm_regulator_get(). Normally + * this function will not need to be called and the resource management + * code will ensure that the resource is freed. + */ +void devm_regulator_put(struct regulator *regulator) +{ +	int rc; + +	rc = devres_release(regulator->dev, devm_regulator_release, +			    devm_regulator_match, regulator); +	if (rc != 0) +		WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_regulator_put); + +/** + * devm_regulator_bulk_get - managed get multiple regulator consumers + * + * @dev:           Device to supply + * @num_consumers: Number of consumers to register + * @consumers:     Configuration of consumers; clients are stored here. + * + * @return 0 on success, an errno on failure. + * + * This helper function allows drivers to get several regulator + * consumers in one operation with management, the regulators will + * automatically be freed when the device is unbound.  If any of the + * regulators cannot be acquired then any regulators that were + * allocated will be freed before returning to the caller. + */ +int devm_regulator_bulk_get(struct device *dev, int num_consumers, +			    struct regulator_bulk_data *consumers) +{ +	int i; +	int ret; + +	for (i = 0; i < num_consumers; i++) +		consumers[i].consumer = NULL; + +	for (i = 0; i < num_consumers; i++) { +		consumers[i].consumer = devm_regulator_get(dev, +							   consumers[i].supply); +		if (IS_ERR(consumers[i].consumer)) { +			ret = PTR_ERR(consumers[i].consumer); +			dev_err(dev, "Failed to get supply '%s': %d\n", +				consumers[i].supply, ret); +			consumers[i].consumer = NULL; +			goto err; +		} +	} + +	return 0; + +err: +	for (i = 0; i < num_consumers && consumers[i].consumer; i++) +		devm_regulator_put(consumers[i].consumer); + +	return ret; +} +EXPORT_SYMBOL_GPL(devm_regulator_bulk_get); + +static void devm_rdev_release(struct device *dev, void *res) +{ +	regulator_unregister(*(struct regulator_dev **)res); +} + +/** + * devm_regulator_register - Resource managed regulator_register() + * @regulator_desc: regulator to register + * @config: runtime configuration for regulator + * + * Called by regulator drivers to register a regulator.  Returns a + * valid pointer to struct regulator_dev on success or an ERR_PTR() on + * error.  The regulator will automatically be released when the device + * is unbound. + */ +struct regulator_dev *devm_regulator_register(struct device *dev, +				  const struct regulator_desc *regulator_desc, +				  const struct regulator_config *config) +{ +	struct regulator_dev **ptr, *rdev; + +	ptr = devres_alloc(devm_rdev_release, sizeof(*ptr), +			   GFP_KERNEL); +	if (!ptr) +		return ERR_PTR(-ENOMEM); + +	rdev = regulator_register(regulator_desc, config); +	if (!IS_ERR(rdev)) { +		*ptr = rdev; +		devres_add(dev, ptr); +	} else { +		devres_free(ptr); +	} + +	return rdev; +} +EXPORT_SYMBOL_GPL(devm_regulator_register); + +static int devm_rdev_match(struct device *dev, void *res, void *data) +{ +	struct regulator_dev **r = res; +	if (!r || !*r) { +		WARN_ON(!r || !*r); +		return 0; +	} +	return *r == data; +} + +/** + * devm_regulator_unregister - Resource managed regulator_unregister() + * @regulator: regulator to free + * + * Unregister a regulator registered with devm_regulator_register(). + * Normally this function will not need to be called and the resource + * management code will ensure that the resource is freed. + */ +void devm_regulator_unregister(struct device *dev, struct regulator_dev *rdev) +{ +	int rc; + +	rc = devres_release(dev, devm_rdev_release, devm_rdev_match, rdev); +	if (rc != 0) +		WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_regulator_unregister); + +struct regulator_supply_alias_match { +	struct device *dev; +	const char *id; +}; + +static int devm_regulator_match_supply_alias(struct device *dev, void *res, +					     void *data) +{ +	struct regulator_supply_alias_match *match = res; +	struct regulator_supply_alias_match *target = data; + +	return match->dev == target->dev && strcmp(match->id, target->id) == 0; +} + +static void devm_regulator_destroy_supply_alias(struct device *dev, void *res) +{ +	struct regulator_supply_alias_match *match = res; + +	regulator_unregister_supply_alias(match->dev, match->id); +} + +/** + * devm_regulator_register_supply_alias - Resource managed + * regulator_register_supply_alias() + * + * @dev: device that will be given as the regulator "consumer" + * @id: Supply name or regulator ID + * @alias_dev: device that should be used to lookup the supply + * @alias_id: Supply name or regulator ID that should be used to lookup the + * supply + * + * The supply alias will automatically be unregistered when the source + * device is unbound. + */ +int devm_regulator_register_supply_alias(struct device *dev, const char *id, +					 struct device *alias_dev, +					 const char *alias_id) +{ +	struct regulator_supply_alias_match *match; +	int ret; + +	match = devres_alloc(devm_regulator_destroy_supply_alias, +			   sizeof(struct regulator_supply_alias_match), +			   GFP_KERNEL); +	if (!match) +		return -ENOMEM; + +	match->dev = dev; +	match->id = id; + +	ret = regulator_register_supply_alias(dev, id, alias_dev, alias_id); +	if (ret < 0) { +		devres_free(match); +		return ret; +	} + +	devres_add(dev, match); + +	return 0; +} +EXPORT_SYMBOL_GPL(devm_regulator_register_supply_alias); + +/** + * devm_regulator_unregister_supply_alias - Resource managed + * regulator_unregister_supply_alias() + * + * @dev: device that will be given as the regulator "consumer" + * @id: Supply name or regulator ID + * + * Unregister an alias registered with + * devm_regulator_register_supply_alias(). Normally this function + * will not need to be called and the resource management code + * will ensure that the resource is freed. + */ +void devm_regulator_unregister_supply_alias(struct device *dev, const char *id) +{ +	struct regulator_supply_alias_match match; +	int rc; + +	match.dev = dev; +	match.id = id; + +	rc = devres_release(dev, devm_regulator_destroy_supply_alias, +			    devm_regulator_match_supply_alias, &match); +	if (rc != 0) +		WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_regulator_unregister_supply_alias); + +/** + * devm_regulator_bulk_register_supply_alias - Managed register + * multiple aliases + * + * @dev: device that will be given as the regulator "consumer" + * @id: List of supply names or regulator IDs + * @alias_dev: device that should be used to lookup the supply + * @alias_id: List of supply names or regulator IDs that should be used to + * lookup the supply + * @num_id: Number of aliases to register + * + * @return 0 on success, an errno on failure. + * + * This helper function allows drivers to register several supply + * aliases in one operation, the aliases will be automatically + * unregisters when the source device is unbound.  If any of the + * aliases cannot be registered any aliases that were registered + * will be removed before returning to the caller. + */ +int devm_regulator_bulk_register_supply_alias(struct device *dev, +					      const char *const *id, +					      struct device *alias_dev, +					      const char *const *alias_id, +					      int num_id) +{ +	int i; +	int ret; + +	for (i = 0; i < num_id; ++i) { +		ret = devm_regulator_register_supply_alias(dev, id[i], +							   alias_dev, +							   alias_id[i]); +		if (ret < 0) +			goto err; +	} + +	return 0; + +err: +	dev_err(dev, +		"Failed to create supply alias %s,%s -> %s,%s\n", +		id[i], dev_name(dev), alias_id[i], dev_name(alias_dev)); + +	while (--i >= 0) +		devm_regulator_unregister_supply_alias(dev, id[i]); + +	return ret; +} +EXPORT_SYMBOL_GPL(devm_regulator_bulk_register_supply_alias); + +/** + * devm_regulator_bulk_unregister_supply_alias - Managed unregister + * multiple aliases + * + * @dev: device that will be given as the regulator "consumer" + * @id: List of supply names or regulator IDs + * @num_id: Number of aliases to unregister + * + * Unregister aliases registered with + * devm_regulator_bulk_register_supply_alias(). Normally this function + * will not need to be called and the resource management code + * will ensure that the resource is freed. + */ +void devm_regulator_bulk_unregister_supply_alias(struct device *dev, +						 const char *const *id, +						 int num_id) +{ +	int i; + +	for (i = 0; i < num_id; ++i) +		devm_regulator_unregister_supply_alias(dev, id[i]); +} +EXPORT_SYMBOL_GPL(devm_regulator_bulk_unregister_supply_alias); diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c index df9f42524ab..2436db9e2ca 100644 --- a/drivers/regulator/dummy.c +++ b/drivers/regulator/dummy.c @@ -25,7 +25,11 @@  struct regulator_dev *dummy_regulator_rdev; -static struct regulator_init_data dummy_initdata; +static struct regulator_init_data dummy_initdata = { +	.constraints = { +		.always_on = 1, +	}, +};  static struct regulator_ops dummy_ops; diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 70b7220c587..714fd9a89aa 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -90,11 +90,11 @@ static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV)  		return 0;  	ret = regulator_map_voltage_linear(rdev, uV, uV);  	if (ret < 0) -		return -EINVAL; +		return ret;  	ret = regmap_update_bits(di->regmap, di->sleep_reg,  					VSEL_NSEL_MASK, ret);  	if (ret < 0) -		return -EINVAL; +		return ret;  	/* Cache the sleep voltage setting.  	 * Might not be the real voltage which is rounded */  	di->sleep_vol_cache = uV; @@ -218,9 +218,8 @@ static int fan53555_regulator_register(struct fan53555_device_info *di,  	rdesc->vsel_mask = VSEL_NSEL_MASK;  	rdesc->owner = THIS_MODULE; -	di->rdev = regulator_register(&di->desc, config); +	di->rdev = devm_regulator_register(di->dev, &di->desc, config);  	return PTR_ERR_OR_ZERO(di->rdev); -  }  static struct regmap_config fan53555_regmap_config = { @@ -245,10 +244,9 @@ static int fan53555_regulator_probe(struct i2c_client *client,  	di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info),  					GFP_KERNEL); -	if (!di) { -		dev_err(&client->dev, "Failed to allocate device info data!\n"); +	if (!di)  		return -ENOMEM; -	} +  	di->regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config);  	if (IS_ERR(di->regmap)) {  		dev_err(&client->dev, "Failed to allocate regmap!\n"); @@ -261,14 +259,14 @@ static int fan53555_regulator_probe(struct i2c_client *client,  	ret = regmap_read(di->regmap, FAN53555_ID1, &val);  	if (ret < 0) {  		dev_err(&client->dev, "Failed to get chip ID!\n"); -		return -ENODEV; +		return ret;  	}  	di->chip_id = val & DIE_ID;  	/* Get chip revision */  	ret = regmap_read(di->regmap, FAN53555_ID2, &val);  	if (ret < 0) {  		dev_err(&client->dev, "Failed to get chip Rev!\n"); -		return -ENODEV; +		return ret;  	}  	di->chip_rev = val & DIE_REV;  	dev_info(&client->dev, "FAN53555 Option[%d] Rev[%d] Detected!\n", @@ -291,14 +289,6 @@ static int fan53555_regulator_probe(struct i2c_client *client,  } -static int fan53555_regulator_remove(struct i2c_client *client) -{ -	struct fan53555_device_info *di = i2c_get_clientdata(client); - -	regulator_unregister(di->rdev); -	return 0; -} -  static const struct i2c_device_id fan53555_id[] = {  	{"fan53555", -1},  	{ }, @@ -309,7 +299,6 @@ static struct i2c_driver fan53555_regulator_driver = {  		.name = "fan53555-regulator",  	},  	.probe = fan53555_regulator_probe, -	.remove = fan53555_regulator_remove,  	.id_table = fan53555_id,  }; diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 7610920014d..354105eff1f 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -34,7 +34,6 @@  struct fixed_voltage_data {  	struct regulator_desc desc;  	struct regulator_dev *dev; -	int microvolts;  }; @@ -51,7 +50,6 @@ of_get_fixed_voltage_config(struct device *dev)  {  	struct fixed_voltage_config *config;  	struct device_node *np = dev->of_node; -	const __be32 *delay;  	struct regulator_init_data *init_data;  	config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config), @@ -92,15 +90,11 @@ of_get_fixed_voltage_config(struct device *dev)  	if ((config->gpio == -ENODEV) || (config->gpio == -EPROBE_DEFER))  		return ERR_PTR(-EPROBE_DEFER); -	delay = of_get_property(np, "startup-delay-us", NULL); -	if (delay) -		config->startup_delay = be32_to_cpu(*delay); +	of_property_read_u32(np, "startup-delay-us", &config->startup_delay); -	if (of_find_property(np, "enable-active-high", NULL)) -		config->enable_high = true; - -	if (of_find_property(np, "gpio-open-drain", NULL)) -		config->gpio_is_open_drain = true; +	config->enable_high = of_property_read_bool(np, "enable-active-high"); +	config->gpio_is_open_drain = of_property_read_bool(np, +							   "gpio-open-drain");  	if (of_find_property(np, "vin-supply", NULL))  		config->input_supply = "vin"; @@ -108,30 +102,7 @@ of_get_fixed_voltage_config(struct device *dev)  	return config;  } -static int fixed_voltage_get_voltage(struct regulator_dev *dev) -{ -	struct fixed_voltage_data *data = rdev_get_drvdata(dev); - -	if (data->microvolts) -		return data->microvolts; -	else -		return -EINVAL; -} - -static int fixed_voltage_list_voltage(struct regulator_dev *dev, -				      unsigned selector) -{ -	struct fixed_voltage_data *data = rdev_get_drvdata(dev); - -	if (selector != 0) -		return -EINVAL; - -	return data->microvolts; -} -  static struct regulator_ops fixed_voltage_ops = { -	.get_voltage = fixed_voltage_get_voltage, -	.list_voltage = fixed_voltage_list_voltage,  };  static int reg_fixed_voltage_probe(struct platform_device *pdev) @@ -154,17 +125,15 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)  	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data),  			       GFP_KERNEL); -	if (drvdata == NULL) { -		dev_err(&pdev->dev, "Failed to allocate device data\n"); -		ret = -ENOMEM; -		goto err; -	} +	if (!drvdata) +		return -ENOMEM; -	drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL); +	drvdata->desc.name = devm_kstrdup(&pdev->dev, +					  config->supply_name, +					  GFP_KERNEL);  	if (drvdata->desc.name == NULL) {  		dev_err(&pdev->dev, "Failed to allocate supply name\n"); -		ret = -ENOMEM; -		goto err; +		return -ENOMEM;  	}  	drvdata->desc.type = REGULATOR_VOLTAGE;  	drvdata->desc.owner = THIS_MODULE; @@ -173,36 +142,34 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)  	drvdata->desc.enable_time = config->startup_delay;  	if (config->input_supply) { -		drvdata->desc.supply_name = kstrdup(config->input_supply, -							GFP_KERNEL); +		drvdata->desc.supply_name = devm_kstrdup(&pdev->dev, +					    config->input_supply, +					    GFP_KERNEL);  		if (!drvdata->desc.supply_name) {  			dev_err(&pdev->dev,  				"Failed to allocate input supply\n"); -			ret = -ENOMEM; -			goto err_name; +			return -ENOMEM;  		}  	}  	if (config->microvolts)  		drvdata->desc.n_voltages = 1; -	drvdata->microvolts = config->microvolts; +	drvdata->desc.fixed_uV = config->microvolts;  	if (config->gpio >= 0)  		cfg.ena_gpio = config->gpio;  	cfg.ena_gpio_invert = !config->enable_high;  	if (config->enabled_at_boot) { -		if (config->enable_high) { +		if (config->enable_high)  			cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; -		} else { +		else  			cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; -		}  	} else { -		if (config->enable_high) { +		if (config->enable_high)  			cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; -		} else { +		else  			cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; -		}  	}  	if (config->gpio_is_open_drain)  		cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN; @@ -212,35 +179,18 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)  	cfg.driver_data = drvdata;  	cfg.of_node = pdev->dev.of_node; -	drvdata->dev = regulator_register(&drvdata->desc, &cfg); +	drvdata->dev = devm_regulator_register(&pdev->dev, &drvdata->desc, +					       &cfg);  	if (IS_ERR(drvdata->dev)) {  		ret = PTR_ERR(drvdata->dev);  		dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); -		goto err_input; +		return ret;  	}  	platform_set_drvdata(pdev, drvdata);  	dev_dbg(&pdev->dev, "%s supplying %duV\n", drvdata->desc.name, -		drvdata->microvolts); - -	return 0; - -err_input: -	kfree(drvdata->desc.supply_name); -err_name: -	kfree(drvdata->desc.name); -err: -	return ret; -} - -static int reg_fixed_voltage_remove(struct platform_device *pdev) -{ -	struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev); - -	regulator_unregister(drvdata->dev); -	kfree(drvdata->desc.supply_name); -	kfree(drvdata->desc.name); +		drvdata->desc.fixed_uV);  	return 0;  } @@ -255,7 +205,6 @@ MODULE_DEVICE_TABLE(of, fixed_of_match);  static struct platform_driver regulator_fixed_voltage_driver = {  	.probe		= reg_fixed_voltage_probe, -	.remove		= reg_fixed_voltage_remove,  	.driver		= {  		.name		= "reg-fixed-voltage",  		.owner		= THIS_MODULE, diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index 98a98ffa7fe..989b23b377c 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -136,9 +136,9 @@ static struct gpio_regulator_config *  of_get_gpio_regulator_config(struct device *dev, struct device_node *np)  {  	struct gpio_regulator_config *config; -	struct property *prop;  	const char *regtype;  	int proplen, gpio, i; +	int ret;  	config = devm_kzalloc(dev,  			sizeof(struct gpio_regulator_config), @@ -171,22 +171,35 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np)  	if (!config->gpios)  		return ERR_PTR(-ENOMEM); +	proplen = of_property_count_u32_elems(np, "gpios-states"); +	/* optional property */ +	if (proplen < 0) +		proplen = 0; + +	if (proplen > 0 && proplen != config->nr_gpios) { +		dev_warn(dev, "gpios <-> gpios-states mismatch\n"); +		proplen = 0; +	} +  	for (i = 0; i < config->nr_gpios; i++) {  		gpio = of_get_named_gpio(np, "gpios", i);  		if (gpio < 0)  			break;  		config->gpios[i].gpio = gpio; +		if (proplen > 0) { +			of_property_read_u32_index(np, "gpios-states", i, &ret); +			if (ret) +				config->gpios[i].flags = GPIOF_OUT_INIT_HIGH; +		}  	}  	/* Fetch states. */ -	prop = of_find_property(np, "states", NULL); -	if (!prop) { +	proplen = of_property_count_u32_elems(np, "states"); +	if (proplen < 0) {  		dev_err(dev, "No 'states' property found\n");  		return ERR_PTR(-EINVAL);  	} -	proplen = prop->length / sizeof(int); -  	config->states = devm_kzalloc(dev,  				sizeof(struct gpio_regulator_state)  				* (proplen / 2), @@ -195,19 +208,24 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np)  		return ERR_PTR(-ENOMEM);  	for (i = 0; i < proplen / 2; i++) { -		config->states[i].value = -			be32_to_cpup((int *)prop->value + (i * 2)); -		config->states[i].gpios = -			be32_to_cpup((int *)prop->value + (i * 2 + 1)); +		of_property_read_u32_index(np, "states", i * 2, +					   &config->states[i].value); +		of_property_read_u32_index(np, "states", i * 2 + 1, +					   &config->states[i].gpios);  	}  	config->nr_states = i; -	of_property_read_string(np, "regulator-type", ®type); - -	if (!strncmp("voltage", regtype, 7)) -		config->type = REGULATOR_VOLTAGE; -	else if (!strncmp("current", regtype, 7)) -		config->type = REGULATOR_CURRENT; +	config->type = REGULATOR_VOLTAGE; +	ret = of_property_read_string(np, "regulator-type", ®type); +	if (ret >= 0) { +		if (!strncmp("voltage", regtype, 7)) +			config->type = REGULATOR_VOLTAGE; +		else if (!strncmp("current", regtype, 7)) +			config->type = REGULATOR_CURRENT; +		else +			dev_warn(dev, "Unknown regulator-type '%s'\n", +				 regtype); +	}  	return config;  } @@ -233,10 +251,8 @@ static int gpio_regulator_probe(struct platform_device *pdev)  	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data),  			       GFP_KERNEL); -	if (drvdata == NULL) { -		dev_err(&pdev->dev, "Failed to allocate device data\n"); +	if (drvdata == NULL)  		return -ENOMEM; -	}  	drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);  	if (drvdata->desc.name == NULL) { @@ -283,7 +299,6 @@ static int gpio_regulator_probe(struct platform_device *pdev)  		dev_err(&pdev->dev, "No regulator type set\n");  		ret = -EINVAL;  		goto err_memgpio; -		break;  	}  	drvdata->nr_gpios = config->nr_gpios; diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index 6e30df14714..cbc39096c78 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -37,10 +37,17 @@ int regulator_is_enabled_regmap(struct regulator_dev *rdev)  	if (ret != 0)  		return ret; -	if (rdev->desc->enable_is_inverted) -		return (val & rdev->desc->enable_mask) == 0; -	else -		return (val & rdev->desc->enable_mask) != 0; +	val &= rdev->desc->enable_mask; + +	if (rdev->desc->enable_is_inverted) { +		if (rdev->desc->enable_val) +			return val != rdev->desc->enable_val; +		return val == 0; +	} else { +		if (rdev->desc->enable_val) +			return val == rdev->desc->enable_val; +		return val != 0; +	}  }  EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap); @@ -57,10 +64,13 @@ int regulator_enable_regmap(struct regulator_dev *rdev)  {  	unsigned int val; -	if (rdev->desc->enable_is_inverted) -		val = 0; -	else -		val = rdev->desc->enable_mask; +	if (rdev->desc->enable_is_inverted) { +		val = rdev->desc->disable_val; +	} else { +		val = rdev->desc->enable_val; +		if (!val) +			val = rdev->desc->enable_mask; +	}  	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,  				  rdev->desc->enable_mask, val); @@ -80,10 +90,13 @@ int regulator_disable_regmap(struct regulator_dev *rdev)  {  	unsigned int val; -	if (rdev->desc->enable_is_inverted) -		val = rdev->desc->enable_mask; -	else -		val = 0; +	if (rdev->desc->enable_is_inverted) { +		val = rdev->desc->enable_val; +		if (!val) +			val = rdev->desc->enable_mask; +	} else { +		val = rdev->desc->disable_val; +	}  	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,  				  rdev->desc->enable_mask, val); @@ -284,9 +297,13 @@ int regulator_map_voltage_linear_range(struct regulator_dev *rdev,  	}  	for (i = 0; i < rdev->desc->n_linear_ranges; i++) { +		int linear_max_uV; +  		range = &rdev->desc->linear_ranges[i]; +		linear_max_uV = range->min_uV + +			(range->max_sel - range->min_sel) * range->uV_step; -		if (!(min_uV <= range->max_uV && max_uV >= range->min_uV)) +		if (!(min_uV <= linear_max_uV && max_uV >= range->min_uV))  			continue;  		if (min_uV <= range->min_uV) @@ -415,10 +432,13 @@ int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable)  {  	unsigned int val; -	if (enable) -		val = rdev->desc->bypass_mask; -	else -		val = 0; +	if (enable) { +		val = rdev->desc->bypass_val_on; +		if (!val) +			val = rdev->desc->bypass_mask; +	} else { +		val = rdev->desc->bypass_val_off; +	}  	return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg,  				  rdev->desc->bypass_mask, val); diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h new file mode 100644 index 00000000000..84bbda10c39 --- /dev/null +++ b/drivers/regulator/internal.h @@ -0,0 +1,38 @@ +/* + * internal.h  --  Voltage/Current Regulator framework internal code + * + * Copyright 2007, 2008 Wolfson Microelectronics PLC. + * Copyright 2008 SlimLogic Ltd. + * + * Author: Liam Girdwood <lrg@slimlogic.co.uk> + * + *  This program is free software; you can redistribute  it and/or modify it + *  under  the terms of  the GNU General  Public License as published by the + *  Free Software Foundation;  either version 2 of the  License, or (at your + *  option) any later version. + * + */ + +#ifndef __REGULATOR_INTERNAL_H +#define __REGULATOR_INTERNAL_H + +/* + * struct regulator + * + * One for each consumer device. + */ +struct regulator { +	struct device *dev; +	struct list_head list; +	unsigned int always_on:1; +	unsigned int bypass:1; +	int uA_load; +	int min_uV; +	int max_uV; +	char *supply_name; +	struct device_attribute dev_attr; +	struct regulator_dev *rdev; +	struct dentry *debugfs; +}; + +#endif diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index 88c1a3acf56..6e5da95fa02 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -112,7 +112,7 @@ static int isl6271a_probe(struct i2c_client *i2c,  	struct regulator_config config = { };  	struct regulator_init_data *init_data	= dev_get_platdata(&i2c->dev);  	struct isl_pmic *pmic; -	int err, i; +	int i;  	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))  		return -EIO; @@ -133,32 +133,17 @@ static int isl6271a_probe(struct i2c_client *i2c,  			config.init_data = NULL;  		config.driver_data = pmic; -		pmic->rdev[i] = regulator_register(&isl_rd[i], &config); +		pmic->rdev[i] = devm_regulator_register(&i2c->dev, &isl_rd[i], +							&config);  		if (IS_ERR(pmic->rdev[i])) {  			dev_err(&i2c->dev, "failed to register %s\n", id->name); -			err = PTR_ERR(pmic->rdev[i]); -			goto error; +			return PTR_ERR(pmic->rdev[i]);  		}  	}  	i2c_set_clientdata(i2c, pmic);  	return 0; - -error: -	while (--i >= 0) -		regulator_unregister(pmic->rdev[i]); -	return err; -} - -static int isl6271a_remove(struct i2c_client *i2c) -{ -	struct isl_pmic *pmic = i2c_get_clientdata(i2c); -	int i; - -	for (i = 0; i < 3; i++) -		regulator_unregister(pmic->rdev[i]); -	return 0;  }  static const struct i2c_device_id isl6271a_id[] = { @@ -174,7 +159,6 @@ static struct i2c_driver isl6271a_i2c_driver = {  		.owner = THIS_MODULE,  	},  	.probe = isl6271a_probe, -	.remove = isl6271a_remove,  	.id_table = isl6271a_id,  }; diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 5a4604ee5ea..66fd2330dca 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -25,8 +25,6 @@ struct lp3971 {  	struct device *dev;  	struct mutex io_lock;  	struct i2c_client *i2c; -	int num_regulators; -	struct regulator_dev **rdev;  };  static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg); @@ -329,7 +327,7 @@ static int lp3971_i2c_read(struct i2c_client *i2c, char reg, int count,  		return -EIO;  	ret = i2c_smbus_read_byte_data(i2c, reg);  	if (ret < 0) -		return -EIO; +		return ret;  	*dest = ret;  	return 0; @@ -383,42 +381,27 @@ static int setup_regulators(struct lp3971 *lp3971,  {  	int i, err; -	lp3971->num_regulators = pdata->num_regulators; -	lp3971->rdev = kcalloc(pdata->num_regulators, -				sizeof(struct regulator_dev *), GFP_KERNEL); -	if (!lp3971->rdev) { -		err = -ENOMEM; -		goto err_nomem; -	} -  	/* Instantiate the regulators */  	for (i = 0; i < pdata->num_regulators; i++) {  		struct regulator_config config = { };  		struct lp3971_regulator_subdev *reg = &pdata->regulators[i]; +		struct regulator_dev *rdev;  		config.dev = lp3971->dev;  		config.init_data = reg->initdata;  		config.driver_data = lp3971; -		lp3971->rdev[i] = regulator_register(®ulators[reg->id], -						     &config); -		if (IS_ERR(lp3971->rdev[i])) { -			err = PTR_ERR(lp3971->rdev[i]); +		rdev = devm_regulator_register(lp3971->dev, +					       ®ulators[reg->id], &config); +		if (IS_ERR(rdev)) { +			err = PTR_ERR(rdev);  			dev_err(lp3971->dev, "regulator init failed: %d\n",  				err); -			goto error; +			return err;  		}  	}  	return 0; - -error: -	while (--i >= 0) -		regulator_unregister(lp3971->rdev[i]); -	kfree(lp3971->rdev); -	lp3971->rdev = NULL; -err_nomem: -	return err;  }  static int lp3971_i2c_probe(struct i2c_client *i2c, @@ -460,22 +443,9 @@ static int lp3971_i2c_probe(struct i2c_client *i2c,  	return 0;  } -static int lp3971_i2c_remove(struct i2c_client *i2c) -{ -	struct lp3971 *lp3971 = i2c_get_clientdata(i2c); -	int i; - -	for (i = 0; i < lp3971->num_regulators; i++) -		regulator_unregister(lp3971->rdev[i]); - -	kfree(lp3971->rdev); - -	return 0; -} -  static const struct i2c_device_id lp3971_i2c_id[] = { -       { "lp3971", 0 }, -       { } +	{ "lp3971", 0 }, +	{ }  };  MODULE_DEVICE_TABLE(i2c, lp3971_i2c_id); @@ -485,7 +455,6 @@ static struct i2c_driver lp3971_i2c_driver = {  		.owner = THIS_MODULE,  	},  	.probe    = lp3971_i2c_probe, -	.remove   = lp3971_i2c_remove,  	.id_table = lp3971_i2c_id,  }; diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index 093e6f44ff8..aea485afcc1 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -22,8 +22,6 @@ struct lp3972 {  	struct device *dev;  	struct mutex io_lock;  	struct i2c_client *i2c; -	int num_regulators; -	struct regulator_dev **rdev;  };  /* LP3972 Control Registers */ @@ -478,41 +476,27 @@ static int setup_regulators(struct lp3972 *lp3972,  {  	int i, err; -	lp3972->num_regulators = pdata->num_regulators; -	lp3972->rdev = kcalloc(pdata->num_regulators, -				sizeof(struct regulator_dev *), GFP_KERNEL); -	if (!lp3972->rdev) { -		err = -ENOMEM; -		goto err_nomem; -	} -  	/* Instantiate the regulators */  	for (i = 0; i < pdata->num_regulators; i++) {  		struct lp3972_regulator_subdev *reg = &pdata->regulators[i];  		struct regulator_config config = { }; +		struct regulator_dev *rdev;  		config.dev = lp3972->dev;  		config.init_data = reg->initdata;  		config.driver_data = lp3972; -		lp3972->rdev[i] = regulator_register(®ulators[reg->id], -						     &config); -		if (IS_ERR(lp3972->rdev[i])) { -			err = PTR_ERR(lp3972->rdev[i]); +		rdev = devm_regulator_register(lp3972->dev, +					       ®ulators[reg->id], &config); +		if (IS_ERR(rdev)) { +			err = PTR_ERR(rdev);  			dev_err(lp3972->dev, "regulator init failed: %d\n",  				err); -			goto error; +			return err;  		}  	}  	return 0; -error: -	while (--i >= 0) -		regulator_unregister(lp3972->rdev[i]); -	kfree(lp3972->rdev); -	lp3972->rdev = NULL; -err_nomem: -	return err;  }  static int lp3972_i2c_probe(struct i2c_client *i2c, @@ -557,18 +541,6 @@ static int lp3972_i2c_probe(struct i2c_client *i2c,  	return 0;  } -static int lp3972_i2c_remove(struct i2c_client *i2c) -{ -	struct lp3972 *lp3972 = i2c_get_clientdata(i2c); -	int i; - -	for (i = 0; i < lp3972->num_regulators; i++) -		regulator_unregister(lp3972->rdev[i]); -	kfree(lp3972->rdev); - -	return 0; -} -  static const struct i2c_device_id lp3972_i2c_id[] = {  	{ "lp3972", 0 },  	{ } @@ -581,7 +553,6 @@ static struct i2c_driver lp3972_i2c_driver = {  		.owner = THIS_MODULE,  	},  	.probe    = lp3972_i2c_probe, -	.remove   = lp3972_i2c_remove,  	.id_table = lp3972_i2c_id,  }; diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index 2b84b727a3c..2e022aabd95 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -211,7 +211,7 @@ static int lp872x_get_timestep_usec(struct lp872x *lp)  	ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val);  	if (ret) -		return -EINVAL; +		return ret;  	val = (val & mask) >> shift;  	if (val >= size) @@ -229,7 +229,7 @@ static int lp872x_regulator_enable_time(struct regulator_dev *rdev)  	u8 addr, val;  	if (time_step_us < 0) -		return -EINVAL; +		return time_step_us;  	switch (rid) {  	case LP8720_ID_LDO1 ... LP8720_ID_BUCK: @@ -785,7 +785,7 @@ static int lp872x_regulator_register(struct lp872x *lp)  	struct regulator_desc *desc;  	struct regulator_config cfg = { };  	struct regulator_dev *rdev; -	int i, ret; +	int i;  	for (i = 0; i < lp->num_regulators; i++) {  		desc = (lp->chipid == LP8720) ? &lp8720_regulator_desc[i] : @@ -796,34 +796,16 @@ static int lp872x_regulator_register(struct lp872x *lp)  		cfg.driver_data = lp;  		cfg.regmap = lp->regmap; -		rdev = regulator_register(desc, &cfg); +		rdev = devm_regulator_register(lp->dev, desc, &cfg);  		if (IS_ERR(rdev)) {  			dev_err(lp->dev, "regulator register err"); -			ret =  PTR_ERR(rdev); -			goto err; +			return PTR_ERR(rdev);  		}  		*(lp->regulators + i) = rdev;  	}  	return 0; -err: -	while (--i >= 0) { -		rdev = *(lp->regulators + i); -		regulator_unregister(rdev); -	} -	return ret; -} - -static void lp872x_regulator_unregister(struct lp872x *lp) -{ -	struct regulator_dev *rdev; -	int i; - -	for (i = 0; i < lp->num_regulators; i++) { -		rdev = *(lp->regulators + i); -		regulator_unregister(rdev); -	}  }  static const struct regmap_config lp872x_regmap_config = { @@ -979,14 +961,6 @@ err_dev:  	return ret;  } -static int lp872x_remove(struct i2c_client *cl) -{ -	struct lp872x *lp = i2c_get_clientdata(cl); - -	lp872x_regulator_unregister(lp); -	return 0; -} -  static const struct of_device_id lp872x_dt_ids[] = {  	{ .compatible = "ti,lp8720", },  	{ .compatible = "ti,lp8725", }, @@ -1008,7 +982,6 @@ static struct i2c_driver lp872x_driver = {  		.of_match_table = of_match_ptr(lp872x_dt_ids),  	},  	.probe = lp872x_probe, -	.remove = lp872x_remove,  	.id_table = lp872x_ids,  }; diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c index 0b015f2a7fd..948afc249e2 100644 --- a/drivers/regulator/lp8788-buck.c +++ b/drivers/regulator/lp8788-buck.c @@ -515,7 +515,7 @@ static int lp8788_buck_probe(struct platform_device *pdev)  	cfg.driver_data = buck;  	cfg.regmap = lp->regmap; -	rdev = regulator_register(&lp8788_buck_desc[id], &cfg); +	rdev = devm_regulator_register(&pdev->dev, &lp8788_buck_desc[id], &cfg);  	if (IS_ERR(rdev)) {  		ret = PTR_ERR(rdev);  		dev_err(&pdev->dev, "BUCK%d regulator register err = %d\n", @@ -529,18 +529,8 @@ static int lp8788_buck_probe(struct platform_device *pdev)  	return 0;  } -static int lp8788_buck_remove(struct platform_device *pdev) -{ -	struct lp8788_buck *buck = platform_get_drvdata(pdev); - -	regulator_unregister(buck->regulator); - -	return 0; -} -  static struct platform_driver lp8788_buck_driver = {  	.probe = lp8788_buck_probe, -	.remove = lp8788_buck_remove,  	.driver = {  		.name = LP8788_DEV_BUCK,  		.owner = THIS_MODULE, diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c index 0527d87c6dd..b9a29a29933 100644 --- a/drivers/regulator/lp8788-ldo.c +++ b/drivers/regulator/lp8788-ldo.c @@ -543,7 +543,7 @@ static int lp8788_dldo_probe(struct platform_device *pdev)  	cfg.driver_data = ldo;  	cfg.regmap = lp->regmap; -	rdev = regulator_register(&lp8788_dldo_desc[id], &cfg); +	rdev = devm_regulator_register(&pdev->dev, &lp8788_dldo_desc[id], &cfg);  	if (IS_ERR(rdev)) {  		ret = PTR_ERR(rdev);  		dev_err(&pdev->dev, "DLDO%d regulator register err = %d\n", @@ -557,18 +557,8 @@ static int lp8788_dldo_probe(struct platform_device *pdev)  	return 0;  } -static int lp8788_dldo_remove(struct platform_device *pdev) -{ -	struct lp8788_ldo *ldo = platform_get_drvdata(pdev); - -	regulator_unregister(ldo->regulator); - -	return 0; -} -  static struct platform_driver lp8788_dldo_driver = {  	.probe = lp8788_dldo_probe, -	.remove = lp8788_dldo_remove,  	.driver = {  		.name = LP8788_DEV_DLDO,  		.owner = THIS_MODULE, @@ -603,7 +593,7 @@ static int lp8788_aldo_probe(struct platform_device *pdev)  	cfg.driver_data = ldo;  	cfg.regmap = lp->regmap; -	rdev = regulator_register(&lp8788_aldo_desc[id], &cfg); +	rdev = devm_regulator_register(&pdev->dev, &lp8788_aldo_desc[id], &cfg);  	if (IS_ERR(rdev)) {  		ret = PTR_ERR(rdev);  		dev_err(&pdev->dev, "ALDO%d regulator register err = %d\n", @@ -617,18 +607,8 @@ static int lp8788_aldo_probe(struct platform_device *pdev)  	return 0;  } -static int lp8788_aldo_remove(struct platform_device *pdev) -{ -	struct lp8788_ldo *ldo = platform_get_drvdata(pdev); - -	regulator_unregister(ldo->regulator); - -	return 0; -} -  static struct platform_driver lp8788_aldo_driver = {  	.probe = lp8788_aldo_probe, -	.remove = lp8788_aldo_remove,  	.driver = {  		.name = LP8788_DEV_ALDO,  		.owner = THIS_MODULE, diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c new file mode 100644 index 00000000000..c8105182b8b --- /dev/null +++ b/drivers/regulator/ltc3589.c @@ -0,0 +1,554 @@ +/* + * Linear Technology LTC3589,LTC3589-1 regulator support + * + * Copyright (c) 2014 Philipp Zabel <p.zabel@pengutronix.de>, Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + */ +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> + +#define DRIVER_NAME		"ltc3589" + +#define LTC3589_IRQSTAT		0x02 +#define LTC3589_SCR1		0x07 +#define LTC3589_OVEN		0x10 +#define LTC3589_SCR2		0x12 +#define LTC3589_PGSTAT		0x13 +#define LTC3589_VCCR		0x20 +#define LTC3589_CLIRQ		0x21 +#define LTC3589_B1DTV1		0x23 +#define LTC3589_B1DTV2		0x24 +#define LTC3589_VRRCR		0x25 +#define LTC3589_B2DTV1		0x26 +#define LTC3589_B2DTV2		0x27 +#define LTC3589_B3DTV1		0x29 +#define LTC3589_B3DTV2		0x2a +#define LTC3589_L2DTV1		0x32 +#define LTC3589_L2DTV2		0x33 + +#define LTC3589_IRQSTAT_PGOOD_TIMEOUT	BIT(3) +#define LTC3589_IRQSTAT_UNDERVOLT_WARN	BIT(4) +#define LTC3589_IRQSTAT_UNDERVOLT_FAULT	BIT(5) +#define LTC3589_IRQSTAT_THERMAL_WARN	BIT(6) +#define LTC3589_IRQSTAT_THERMAL_FAULT	BIT(7) + +#define LTC3589_OVEN_SW1		BIT(0) +#define LTC3589_OVEN_SW2		BIT(1) +#define LTC3589_OVEN_SW3		BIT(2) +#define LTC3589_OVEN_BB_OUT		BIT(3) +#define LTC3589_OVEN_LDO2		BIT(4) +#define LTC3589_OVEN_LDO3		BIT(5) +#define LTC3589_OVEN_LDO4		BIT(6) +#define LTC3589_OVEN_SW_CTRL		BIT(7) + +#define LTC3589_VCCR_SW1_GO		BIT(0) +#define LTC3589_VCCR_SW2_GO		BIT(2) +#define LTC3589_VCCR_SW3_GO		BIT(4) +#define LTC3589_VCCR_LDO2_GO		BIT(6) + +enum ltc3589_variant { +	LTC3589, +	LTC3589_1, +	LTC3589_2, +}; + +enum ltc3589_reg { +	LTC3589_SW1, +	LTC3589_SW2, +	LTC3589_SW3, +	LTC3589_BB_OUT, +	LTC3589_LDO1, +	LTC3589_LDO2, +	LTC3589_LDO3, +	LTC3589_LDO4, +	LTC3589_NUM_REGULATORS, +}; + +struct ltc3589_regulator { +	struct regulator_desc desc; + +	/* External feedback voltage divider */ +	unsigned int r1; +	unsigned int r2; +}; + +struct ltc3589 { +	struct regmap *regmap; +	struct device *dev; +	enum ltc3589_variant variant; +	struct ltc3589_regulator regulator_descs[LTC3589_NUM_REGULATORS]; +	struct regulator_dev *regulators[LTC3589_NUM_REGULATORS]; +}; + +static const int ltc3589_ldo4[] = { +	2800000, 2500000, 1800000, 3300000, +}; + +static const int ltc3589_12_ldo4[] = { +	1200000, 1800000, 2500000, 3200000, +}; + +static int ltc3589_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) +{ +	struct ltc3589 *ltc3589 = rdev_get_drvdata(rdev); +	int sel, shift; + +	if (unlikely(ramp_delay <= 0)) +		return -EINVAL; + +	/* VRRCR slew rate offsets are the same as VCCR go bit offsets */ +	shift = ffs(rdev->desc->apply_bit) - 1; + +	/* The slew rate can be set to 0.88, 1.75, 3.5, or 7 mV/uS */ +	for (sel = 0; sel < 4; sel++) { +		if ((880 << sel) >= ramp_delay) { +			return regmap_update_bits(ltc3589->regmap, +						  LTC3589_VRRCR, +						  0x3 << shift, sel << shift); +		} +	} +	return -EINVAL; +} + +static int ltc3589_set_suspend_voltage(struct regulator_dev *rdev, int uV) +{ +	struct ltc3589 *ltc3589 = rdev_get_drvdata(rdev); +	int sel; + +	sel = regulator_map_voltage_linear(rdev, uV, uV); +	if (sel < 0) +		return sel; + +	/* DTV2 register follows right after the corresponding DTV1 register */ +	return regmap_update_bits(ltc3589->regmap, rdev->desc->vsel_reg + 1, +				  rdev->desc->vsel_mask, sel); +} + +static int ltc3589_set_suspend_mode(struct regulator_dev *rdev, +				    unsigned int mode) +{ +	struct ltc3589 *ltc3589 = rdev_get_drvdata(rdev); +	int mask, bit = 0; + +	/* VCCR reference selects are right next to the VCCR go bits */ +	mask = rdev->desc->apply_bit << 1; + +	if (mode == REGULATOR_MODE_STANDBY) +		bit = mask;	/* Select DTV2 */ + +	mask |= rdev->desc->apply_bit; +	bit |= rdev->desc->apply_bit; +	return regmap_update_bits(ltc3589->regmap, LTC3589_VCCR, mask, bit); +} + +/* SW1, SW2, SW3, LDO2 */ +static struct regulator_ops ltc3589_linear_regulator_ops = { +	.enable = regulator_enable_regmap, +	.disable = regulator_disable_regmap, +	.is_enabled = regulator_is_enabled_regmap, +	.list_voltage = regulator_list_voltage_linear, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.set_ramp_delay = ltc3589_set_ramp_delay, +	.set_voltage_time_sel = regulator_set_voltage_time_sel, +	.set_suspend_voltage = ltc3589_set_suspend_voltage, +	.set_suspend_mode = ltc3589_set_suspend_mode, +}; + +/* BB_OUT, LDO3 */ +static struct regulator_ops ltc3589_fixed_regulator_ops = { +	.enable = regulator_enable_regmap, +	.disable = regulator_disable_regmap, +	.is_enabled = regulator_is_enabled_regmap, +}; + +/* LDO1 */ +static struct regulator_ops ltc3589_fixed_standby_regulator_ops = { +}; + +/* LDO4 */ +static struct regulator_ops ltc3589_table_regulator_ops = { +	.enable = regulator_enable_regmap, +	.disable = regulator_disable_regmap, +	.is_enabled = regulator_is_enabled_regmap, +	.list_voltage = regulator_list_voltage_table, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + + +#define LTC3589_REG(_name, _ops, en_bit, dtv1_reg, dtv_mask, go_bit)	\ +	[LTC3589_ ## _name] = {						\ +		.desc = {						\ +			.name = #_name,					\ +			.n_voltages = (dtv_mask) + 1,			\ +			.min_uV = (go_bit) ? 362500 : 0,		\ +			.uV_step = (go_bit) ? 12500 : 0,		\ +			.ramp_delay = (go_bit) ? 1750 : 0,		\ +			.fixed_uV = (dtv_mask) ? 0 : 800000,		\ +			.ops = <c3589_ ## _ops ## _regulator_ops,	\ +			.type = REGULATOR_VOLTAGE,			\ +			.id = LTC3589_ ## _name,			\ +			.owner = THIS_MODULE,				\ +			.vsel_reg = (dtv1_reg),			\ +			.vsel_mask = (dtv_mask),			\ +			.apply_reg = (go_bit) ? LTC3589_VCCR : 0,	\ +			.apply_bit = (go_bit),				\ +			.enable_reg = (en_bit) ? LTC3589_OVEN : 0,	\ +			.enable_mask = (en_bit),			\ +		},							\ +	} + +#define LTC3589_LINEAR_REG(_name, _dtv1)				\ +	LTC3589_REG(_name, linear, LTC3589_OVEN_ ## _name,		\ +		    LTC3589_ ## _dtv1, 0x1f,				\ +		    LTC3589_VCCR_ ## _name ## _GO) + +#define LTC3589_FIXED_REG(_name) \ +	LTC3589_REG(_name, fixed, LTC3589_OVEN_ ## _name, 0, 0, 0) + +static struct ltc3589_regulator ltc3589_regulators[LTC3589_NUM_REGULATORS] = { +	LTC3589_LINEAR_REG(SW1, B1DTV1), +	LTC3589_LINEAR_REG(SW2, B2DTV1), +	LTC3589_LINEAR_REG(SW3, B3DTV1), +	LTC3589_FIXED_REG(BB_OUT), +	LTC3589_REG(LDO1, fixed_standby, 0, 0, 0, 0), +	LTC3589_LINEAR_REG(LDO2, L2DTV1), +	LTC3589_FIXED_REG(LDO3), +	LTC3589_REG(LDO4, table, LTC3589_OVEN_LDO4, LTC3589_L2DTV2, 0x60, 0), +}; + +#ifdef CONFIG_OF +static struct of_regulator_match ltc3589_matches[LTC3589_NUM_REGULATORS] = { +	{ .name = "sw1",    }, +	{ .name = "sw2",    }, +	{ .name = "sw3",    }, +	{ .name = "bb-out", }, +	{ .name = "ldo1",   }, /* standby */ +	{ .name = "ldo2",   }, +	{ .name = "ldo3",   }, +	{ .name = "ldo4",   }, +}; + +static int ltc3589_parse_regulators_dt(struct ltc3589 *ltc3589) +{ +	struct device *dev = ltc3589->dev; +	struct device_node *node; +	int i, ret; + +	node = of_get_child_by_name(dev->of_node, "regulators"); +	if (!node) { +		dev_err(dev, "regulators node not found\n"); +		return -EINVAL; +	} + +	ret = of_regulator_match(dev, node, ltc3589_matches, +				 ARRAY_SIZE(ltc3589_matches)); +	of_node_put(node); +	if (ret < 0) { +		dev_err(dev, "Error parsing regulator init data: %d\n", ret); +		return ret; +	} +	if (ret != LTC3589_NUM_REGULATORS) { +		dev_err(dev, "Only %d regulators described in device tree\n", +			ret); +		return -EINVAL; +	} + +	/* Parse feedback voltage dividers. LDO3 and LDO4 don't have them */ +	for (i = 0; i < LTC3589_LDO3; i++) { +		struct ltc3589_regulator *desc = <c3589->regulator_descs[i]; +		struct device_node *np = ltc3589_matches[i].of_node; +		u32 vdiv[2]; + +		ret = of_property_read_u32_array(np, "lltc,fb-voltage-divider", +						 vdiv, 2); +		if (ret) { +			dev_err(dev, "Failed to parse voltage divider: %d\n", +				ret); +			return ret; +		} + +		desc->r1 = vdiv[0]; +		desc->r2 = vdiv[1]; +	} + +	return 0; +} + +static inline struct regulator_init_data *match_init_data(int index) +{ +	return ltc3589_matches[index].init_data; +} + +static inline struct device_node *match_of_node(int index) +{ +	return ltc3589_matches[index].of_node; +} +#else +static inline int ltc3589_parse_regulators_dt(struct ltc3589 *ltc3589) +{ +	return 0; +} + +static inline struct regulator_init_data *match_init_data(int index) +{ +	return NULL; +} + +static inline struct device_node *match_of_node(int index) +{ +	return NULL; +} +#endif + +static bool ltc3589_writeable_reg(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case LTC3589_IRQSTAT: +	case LTC3589_SCR1: +	case LTC3589_OVEN: +	case LTC3589_SCR2: +	case LTC3589_VCCR: +	case LTC3589_CLIRQ: +	case LTC3589_B1DTV1: +	case LTC3589_B1DTV2: +	case LTC3589_VRRCR: +	case LTC3589_B2DTV1: +	case LTC3589_B2DTV2: +	case LTC3589_B3DTV1: +	case LTC3589_B3DTV2: +	case LTC3589_L2DTV1: +	case LTC3589_L2DTV2: +		return true; +	} +	return false; +} + +static bool ltc3589_readable_reg(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case LTC3589_IRQSTAT: +	case LTC3589_SCR1: +	case LTC3589_OVEN: +	case LTC3589_SCR2: +	case LTC3589_PGSTAT: +	case LTC3589_VCCR: +	case LTC3589_B1DTV1: +	case LTC3589_B1DTV2: +	case LTC3589_VRRCR: +	case LTC3589_B2DTV1: +	case LTC3589_B2DTV2: +	case LTC3589_B3DTV1: +	case LTC3589_B3DTV2: +	case LTC3589_L2DTV1: +	case LTC3589_L2DTV2: +		return true; +	} +	return false; +} + +static bool ltc3589_volatile_reg(struct device *dev, unsigned int reg) +{ +	switch (reg) { +	case LTC3589_IRQSTAT: +	case LTC3589_PGSTAT: +		return true; +	} +	return false; +} + +struct reg_default ltc3589_reg_defaults[] = { +	{ LTC3589_SCR1,   0x00 }, +	{ LTC3589_OVEN,   0x00 }, +	{ LTC3589_SCR2,   0x00 }, +	{ LTC3589_VCCR,   0x00 }, +	{ LTC3589_B1DTV1, 0x19 }, +	{ LTC3589_B1DTV2, 0x19 }, +	{ LTC3589_VRRCR,  0xff }, +	{ LTC3589_B2DTV1, 0x19 }, +	{ LTC3589_B2DTV2, 0x19 }, +	{ LTC3589_B3DTV1, 0x19 }, +	{ LTC3589_B3DTV2, 0x19 }, +	{ LTC3589_L2DTV1, 0x19 }, +	{ LTC3589_L2DTV2, 0x19 }, +}; + +static const struct regmap_config ltc3589_regmap_config = { +	.reg_bits = 8, +	.val_bits = 8, +	.writeable_reg = ltc3589_writeable_reg, +	.readable_reg = ltc3589_readable_reg, +	.volatile_reg = ltc3589_volatile_reg, +	.max_register = LTC3589_L2DTV2, +	.reg_defaults = ltc3589_reg_defaults, +	.num_reg_defaults = ARRAY_SIZE(ltc3589_reg_defaults), +	.use_single_rw = true, +	.cache_type = REGCACHE_RBTREE, +}; + + +static irqreturn_t ltc3589_isr(int irq, void *dev_id) +{ +	struct ltc3589 *ltc3589 = dev_id; +	unsigned int i, irqstat, event; + +	regmap_read(ltc3589->regmap, LTC3589_IRQSTAT, &irqstat); + +	if (irqstat & LTC3589_IRQSTAT_THERMAL_WARN) { +		event = REGULATOR_EVENT_OVER_TEMP; +		for (i = 0; i < LTC3589_NUM_REGULATORS; i++) +			regulator_notifier_call_chain(ltc3589->regulators[i], +						      event, NULL); +	} + +	if (irqstat & LTC3589_IRQSTAT_UNDERVOLT_WARN) { +		event = REGULATOR_EVENT_UNDER_VOLTAGE; +		for (i = 0; i < LTC3589_NUM_REGULATORS; i++) +			regulator_notifier_call_chain(ltc3589->regulators[i], +						      event, NULL); +	} + +	/* Clear warning condition */ +	regmap_write(ltc3589->regmap, LTC3589_CLIRQ, 0); + +	return IRQ_HANDLED; +} + +static inline unsigned int ltc3589_scale(unsigned int uV, u32 r1, u32 r2) +{ +	uint64_t tmp; +	if (uV == 0) +		return 0; +	tmp = (uint64_t)uV * r1; +	do_div(tmp, r2); +	return uV + (unsigned int)tmp; +} + +static void ltc3589_apply_fb_voltage_divider(struct ltc3589_regulator *rdesc) +{ +	struct regulator_desc *desc = &rdesc->desc; + +	if (!rdesc->r1 || !rdesc->r2) +		return; + +	desc->min_uV = ltc3589_scale(desc->min_uV, rdesc->r1, rdesc->r2); +	desc->uV_step = ltc3589_scale(desc->uV_step, rdesc->r1, rdesc->r2); +	desc->fixed_uV = ltc3589_scale(desc->fixed_uV, rdesc->r1, rdesc->r2); +} + +static int ltc3589_probe(struct i2c_client *client, +			 const struct i2c_device_id *id) +{ +	struct device *dev = &client->dev; +	struct ltc3589_regulator *descs; +	struct ltc3589 *ltc3589; +	int i, ret; + +	ltc3589 = devm_kzalloc(dev, sizeof(*ltc3589), GFP_KERNEL); +	if (!ltc3589) +		return -ENOMEM; + +	i2c_set_clientdata(client, ltc3589); +	ltc3589->variant = id->driver_data; +	ltc3589->dev = dev; + +	descs = ltc3589->regulator_descs; +	memcpy(descs, ltc3589_regulators, sizeof(ltc3589_regulators)); +	if (ltc3589->variant == LTC3589) { +		descs[LTC3589_LDO3].desc.fixed_uV = 1800000; +		descs[LTC3589_LDO4].desc.volt_table = ltc3589_ldo4; +	} else { +		descs[LTC3589_LDO3].desc.fixed_uV = 2800000; +		descs[LTC3589_LDO4].desc.volt_table = ltc3589_12_ldo4; +	} + +	ltc3589->regmap = devm_regmap_init_i2c(client, <c3589_regmap_config); +	if (IS_ERR(ltc3589->regmap)) { +		ret = PTR_ERR(ltc3589->regmap); +		dev_err(dev, "failed to initialize regmap: %d\n", ret); +		return ret; +	} + +	ret = ltc3589_parse_regulators_dt(ltc3589); +	if (ret) +		return ret; + +	for (i = 0; i < LTC3589_NUM_REGULATORS; i++) { +		struct ltc3589_regulator *rdesc = <c3589->regulator_descs[i]; +		struct regulator_desc *desc = &rdesc->desc; +		struct regulator_init_data *init_data; +		struct regulator_config config = { }; + +		init_data = match_init_data(i); + +		if (i < LTC3589_LDO3) +			ltc3589_apply_fb_voltage_divider(rdesc); + +		config.dev = dev; +		config.init_data = init_data; +		config.driver_data = ltc3589; +		config.of_node = match_of_node(i); + +		ltc3589->regulators[i] = devm_regulator_register(dev, desc, +								 &config); +		if (IS_ERR(ltc3589->regulators[i])) { +			ret = PTR_ERR(ltc3589->regulators[i]); +			dev_err(dev, "failed to register regulator %s: %d\n", +				desc->name, ret); +			return ret; +		} +	} + +	ret = devm_request_threaded_irq(dev, client->irq, NULL, ltc3589_isr, +					IRQF_TRIGGER_LOW | IRQF_ONESHOT, +					client->name, ltc3589); +	if (ret) { +		dev_err(dev, "Failed to request IRQ: %d\n", ret); +		return ret; +	} + +	return 0; +} + +static struct i2c_device_id ltc3589_i2c_id[] = { +	{ "ltc3589",   LTC3589   }, +	{ "ltc3589-1", LTC3589_1 }, +	{ "ltc3589-2", LTC3589_2 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, ltc3589_i2c_id); + +static struct i2c_driver ltc3589_driver = { +	.driver = { +		.name = DRIVER_NAME, +		.owner = THIS_MODULE, +	}, +	.probe = ltc3589_probe, +	.id_table = ltc3589_i2c_id, +}; +module_i2c_driver(ltc3589_driver); + +MODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>"); +MODULE_DESCRIPTION("Regulator driver for Linear Technology LTC3589(-1,2)"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("i2c:ltc3589"); diff --git a/drivers/regulator/max14577.c b/drivers/regulator/max14577.c new file mode 100644 index 00000000000..5d9c605cf53 --- /dev/null +++ b/drivers/regulator/max14577.c @@ -0,0 +1,476 @@ +/* + * max14577.c - Regulator driver for the Maxim 14577/77836 + * + * Copyright (C) 2013,2014 Samsung Electronics + * Krzysztof Kozlowski <k.kozlowski@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/mfd/max14577.h> +#include <linux/mfd/max14577-private.h> +#include <linux/regulator/of_regulator.h> + +/* + * Valid limits of current for max14577 and max77836 chargers. + * They must correspond to MBCICHWRCL and MBCICHWRCH fields in CHGCTRL4 + * register for given chipset. + */ +struct maxim_charger_current { +	/* Minimal current, set in CHGCTRL4/MBCICHWRCL, uA */ +	unsigned int min; +	/* +	 * Minimal current when high setting is active, +	 * set in CHGCTRL4/MBCICHWRCH, uA +	 */ +	unsigned int high_start; +	/* Value of one step in high setting, uA */ +	unsigned int high_step; +	/* Maximum current of high setting, uA */ +	unsigned int max; +}; + +/* Table of valid charger currents for different Maxim chipsets */ +static const struct maxim_charger_current maxim_charger_currents[] = { +	[MAXIM_DEVICE_TYPE_UNKNOWN] = { 0, 0, 0, 0 }, +	[MAXIM_DEVICE_TYPE_MAX14577] = { +		.min		= MAX14577_REGULATOR_CURRENT_LIMIT_MIN, +		.high_start	= MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START, +		.high_step	= MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP, +		.max		= MAX14577_REGULATOR_CURRENT_LIMIT_MAX, +	}, +	[MAXIM_DEVICE_TYPE_MAX77836] = { +		.min		= MAX77836_REGULATOR_CURRENT_LIMIT_MIN, +		.high_start	= MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START, +		.high_step	= MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP, +		.max		= MAX77836_REGULATOR_CURRENT_LIMIT_MAX, +	}, +}; + +static int max14577_reg_is_enabled(struct regulator_dev *rdev) +{ +	int rid = rdev_get_id(rdev); +	struct regmap *rmap = rdev->regmap; +	u8 reg_data; + +	switch (rid) { +	case MAX14577_CHARGER: +		max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL2, ®_data); +		if ((reg_data & CHGCTRL2_MBCHOSTEN_MASK) == 0) +			return 0; +		max14577_read_reg(rmap, MAX14577_CHG_REG_STATUS3, ®_data); +		if ((reg_data & STATUS3_CGMBC_MASK) == 0) +			return 0; +		/* MBCHOSTEN and CGMBC are on */ +		return 1; +	default: +		return -EINVAL; +	} +} + +static int max14577_reg_get_current_limit(struct regulator_dev *rdev) +{ +	u8 reg_data; +	struct regmap *rmap = rdev->regmap; +	struct max14577 *max14577 = rdev_get_drvdata(rdev); +	const struct maxim_charger_current *limits = +		&maxim_charger_currents[max14577->dev_type]; + +	if (rdev_get_id(rdev) != MAX14577_CHARGER) +		return -EINVAL; + +	max14577_read_reg(rmap, MAX14577_CHG_REG_CHG_CTRL4, ®_data); + +	if ((reg_data & CHGCTRL4_MBCICHWRCL_MASK) == 0) +		return limits->min; + +	reg_data = ((reg_data & CHGCTRL4_MBCICHWRCH_MASK) >> +			CHGCTRL4_MBCICHWRCH_SHIFT); +	return limits->high_start + reg_data * limits->high_step; +} + +static int max14577_reg_set_current_limit(struct regulator_dev *rdev, +		int min_uA, int max_uA) +{ +	int i, current_bits = 0xf; +	u8 reg_data; +	struct max14577 *max14577 = rdev_get_drvdata(rdev); +	const struct maxim_charger_current *limits = +		&maxim_charger_currents[max14577->dev_type]; + +	if (rdev_get_id(rdev) != MAX14577_CHARGER) +		return -EINVAL; + +	if (min_uA > limits->max || max_uA < limits->min) +		return -EINVAL; + +	if (max_uA < limits->high_start) { +		/* +		 * Less than high_start, +		 * so set the minimal current (turn only Low Bit off) +		 */ +		u8 reg_data = 0x0 << CHGCTRL4_MBCICHWRCL_SHIFT; +		return max14577_update_reg(rdev->regmap, +				MAX14577_CHG_REG_CHG_CTRL4, +				CHGCTRL4_MBCICHWRCL_MASK, reg_data); +	} + +	/* +	 * max_uA is in range: <high_start, inifinite>, so search for +	 * valid current starting from maximum current. +	 */ +	for (i = limits->max; i >= limits->high_start; i -= limits->high_step) { +		if (i <= max_uA) +			break; +		current_bits--; +	} +	BUG_ON(current_bits < 0); /* Cannot happen */ + +	/* Turn Low Bit on (use range high_start-max)... */ +	reg_data = 0x1 << CHGCTRL4_MBCICHWRCL_SHIFT; +	/* and set proper High Bits */ +	reg_data |= current_bits << CHGCTRL4_MBCICHWRCH_SHIFT; + +	return max14577_update_reg(rdev->regmap, MAX14577_CHG_REG_CHG_CTRL4, +			CHGCTRL4_MBCICHWRCL_MASK | CHGCTRL4_MBCICHWRCH_MASK, +			reg_data); +} + +static struct regulator_ops max14577_safeout_ops = { +	.is_enabled		= regulator_is_enabled_regmap, +	.enable			= regulator_enable_regmap, +	.disable		= regulator_disable_regmap, +	.list_voltage		= regulator_list_voltage_linear, +}; + +static struct regulator_ops max14577_charger_ops = { +	.is_enabled		= max14577_reg_is_enabled, +	.enable			= regulator_enable_regmap, +	.disable		= regulator_disable_regmap, +	.get_current_limit	= max14577_reg_get_current_limit, +	.set_current_limit	= max14577_reg_set_current_limit, +}; + +static const struct regulator_desc max14577_supported_regulators[] = { +	[MAX14577_SAFEOUT] = { +		.name		= "SAFEOUT", +		.id		= MAX14577_SAFEOUT, +		.ops		= &max14577_safeout_ops, +		.type		= REGULATOR_VOLTAGE, +		.owner		= THIS_MODULE, +		.n_voltages	= 1, +		.min_uV		= MAX14577_REGULATOR_SAFEOUT_VOLTAGE, +		.enable_reg	= MAX14577_REG_CONTROL2, +		.enable_mask	= CTRL2_SFOUTORD_MASK, +	}, +	[MAX14577_CHARGER] = { +		.name		= "CHARGER", +		.id		= MAX14577_CHARGER, +		.ops		= &max14577_charger_ops, +		.type		= REGULATOR_CURRENT, +		.owner		= THIS_MODULE, +		.enable_reg	= MAX14577_CHG_REG_CHG_CTRL2, +		.enable_mask	= CHGCTRL2_MBCHOSTEN_MASK, +	}, +}; + +static struct regulator_ops max77836_ldo_ops = { +	.is_enabled		= regulator_is_enabled_regmap, +	.enable			= regulator_enable_regmap, +	.disable		= regulator_disable_regmap, +	.list_voltage		= regulator_list_voltage_linear, +	.map_voltage		= regulator_map_voltage_linear, +	.get_voltage_sel	= regulator_get_voltage_sel_regmap, +	.set_voltage_sel	= regulator_set_voltage_sel_regmap, +	/* TODO: add .set_suspend_mode */ +}; + +static const struct regulator_desc max77836_supported_regulators[] = { +	[MAX14577_SAFEOUT] = { +		.name		= "SAFEOUT", +		.id		= MAX14577_SAFEOUT, +		.ops		= &max14577_safeout_ops, +		.type		= REGULATOR_VOLTAGE, +		.owner		= THIS_MODULE, +		.n_voltages	= 1, +		.min_uV		= MAX14577_REGULATOR_SAFEOUT_VOLTAGE, +		.enable_reg	= MAX14577_REG_CONTROL2, +		.enable_mask	= CTRL2_SFOUTORD_MASK, +	}, +	[MAX14577_CHARGER] = { +		.name		= "CHARGER", +		.id		= MAX14577_CHARGER, +		.ops		= &max14577_charger_ops, +		.type		= REGULATOR_CURRENT, +		.owner		= THIS_MODULE, +		.enable_reg	= MAX14577_CHG_REG_CHG_CTRL2, +		.enable_mask	= CHGCTRL2_MBCHOSTEN_MASK, +	}, +	[MAX77836_LDO1] = { +		.name		= "LDO1", +		.id		= MAX77836_LDO1, +		.ops		= &max77836_ldo_ops, +		.type		= REGULATOR_VOLTAGE, +		.owner		= THIS_MODULE, +		.n_voltages	= MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM, +		.min_uV		= MAX77836_REGULATOR_LDO_VOLTAGE_MIN, +		.uV_step	= MAX77836_REGULATOR_LDO_VOLTAGE_STEP, +		.enable_reg	= MAX77836_LDO_REG_CNFG1_LDO1, +		.enable_mask	= MAX77836_CNFG1_LDO_PWRMD_MASK, +		.vsel_reg	= MAX77836_LDO_REG_CNFG1_LDO1, +		.vsel_mask	= MAX77836_CNFG1_LDO_TV_MASK, +	}, +	[MAX77836_LDO2] = { +		.name		= "LDO2", +		.id		= MAX77836_LDO2, +		.ops		= &max77836_ldo_ops, +		.type		= REGULATOR_VOLTAGE, +		.owner		= THIS_MODULE, +		.n_voltages	= MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM, +		.min_uV		= MAX77836_REGULATOR_LDO_VOLTAGE_MIN, +		.uV_step	= MAX77836_REGULATOR_LDO_VOLTAGE_STEP, +		.enable_reg	= MAX77836_LDO_REG_CNFG1_LDO2, +		.enable_mask	= MAX77836_CNFG1_LDO_PWRMD_MASK, +		.vsel_reg	= MAX77836_LDO_REG_CNFG1_LDO2, +		.vsel_mask	= MAX77836_CNFG1_LDO_TV_MASK, +	}, +}; + +#ifdef CONFIG_OF +static struct of_regulator_match max14577_regulator_matches[] = { +	{ .name	= "SAFEOUT", }, +	{ .name = "CHARGER", }, +}; + +static struct of_regulator_match max77836_regulator_matches[] = { +	{ .name	= "SAFEOUT", }, +	{ .name = "CHARGER", }, +	{ .name = "LDO1", }, +	{ .name = "LDO2", }, +}; + +static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev, +		enum maxim_device_type dev_type) +{ +	int ret; +	struct device_node *np; +	struct of_regulator_match *regulator_matches; +	unsigned int regulator_matches_size; + +	np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); +	if (!np) { +		dev_err(&pdev->dev, "Failed to get child OF node for regulators\n"); +		return -EINVAL; +	} + +	switch (dev_type) { +	case MAXIM_DEVICE_TYPE_MAX77836: +		regulator_matches = max77836_regulator_matches; +		regulator_matches_size = ARRAY_SIZE(max77836_regulator_matches); +		break; +	case MAXIM_DEVICE_TYPE_MAX14577: +	default: +		regulator_matches = max14577_regulator_matches; +		regulator_matches_size = ARRAY_SIZE(max14577_regulator_matches); +	} + +	ret = of_regulator_match(&pdev->dev, np, regulator_matches, +			regulator_matches_size); +	if (ret < 0) +		dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret); +	else +		ret = 0; + +	of_node_put(np); + +	return ret; +} + +static inline struct regulator_init_data *match_init_data(int index, +		enum maxim_device_type dev_type) +{ +	switch (dev_type) { +	case MAXIM_DEVICE_TYPE_MAX77836: +		return max77836_regulator_matches[index].init_data; + +	case MAXIM_DEVICE_TYPE_MAX14577: +	default: +		return max14577_regulator_matches[index].init_data; +	} +} + +static inline struct device_node *match_of_node(int index, +		enum maxim_device_type dev_type) +{ +	switch (dev_type) { +	case MAXIM_DEVICE_TYPE_MAX77836: +		return max77836_regulator_matches[index].of_node; + +	case MAXIM_DEVICE_TYPE_MAX14577: +	default: +		return max14577_regulator_matches[index].of_node; +	} +} +#else /* CONFIG_OF */ +static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev, +		enum maxim_device_type dev_type) +{ +	return 0; +} +static inline struct regulator_init_data *match_init_data(int index, +		enum maxim_device_type dev_type) +{ +	return NULL; +} + +static inline struct device_node *match_of_node(int index, +		enum maxim_device_type dev_type) +{ +	return NULL; +} +#endif /* CONFIG_OF */ + +/** + * Registers for regulators of max77836 use different I2C slave addresses so + * different regmaps must be used for them. + * + * Returns proper regmap for accessing regulator passed by id. + */ +static struct regmap *max14577_get_regmap(struct max14577 *max14577, +		int reg_id) +{ +	switch (max14577->dev_type) { +	case MAXIM_DEVICE_TYPE_MAX77836: +		switch (reg_id) { +		case MAX77836_SAFEOUT ... MAX77836_CHARGER: +			return max14577->regmap; +		default: +			/* MAX77836_LDO1 ... MAX77836_LDO2 */ +			return max14577->regmap_pmic; +		} + +	case MAXIM_DEVICE_TYPE_MAX14577: +	default: +		return max14577->regmap; +	} +} + +static int max14577_regulator_probe(struct platform_device *pdev) +{ +	struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent); +	struct max14577_platform_data *pdata = dev_get_platdata(max14577->dev); +	int i, ret; +	struct regulator_config config = {}; +	const struct regulator_desc *supported_regulators; +	unsigned int supported_regulators_size; +	enum maxim_device_type dev_type = max14577->dev_type; + +	ret = max14577_regulator_dt_parse_pdata(pdev, dev_type); +	if (ret) +		return ret; + +	switch (dev_type) { +	case MAXIM_DEVICE_TYPE_MAX77836: +		supported_regulators = max77836_supported_regulators; +		supported_regulators_size = ARRAY_SIZE(max77836_supported_regulators); +		break; +	case MAXIM_DEVICE_TYPE_MAX14577: +	default: +		supported_regulators = max14577_supported_regulators; +		supported_regulators_size = ARRAY_SIZE(max14577_supported_regulators); +	} + +	config.dev = &pdev->dev; +	config.driver_data = max14577; + +	for (i = 0; i < supported_regulators_size; i++) { +		struct regulator_dev *regulator; +		/* +		 * Index of supported_regulators[] is also the id and must +		 * match index of pdata->regulators[]. +		 */ +		if (pdata && pdata->regulators) { +			config.init_data = pdata->regulators[i].initdata; +			config.of_node = pdata->regulators[i].of_node; +		} else { +			config.init_data = match_init_data(i, dev_type); +			config.of_node = match_of_node(i, dev_type); +		} +		config.regmap = max14577_get_regmap(max14577, +				supported_regulators[i].id); + +		regulator = devm_regulator_register(&pdev->dev, +				&supported_regulators[i], &config); +		if (IS_ERR(regulator)) { +			ret = PTR_ERR(regulator); +			dev_err(&pdev->dev, +					"Regulator init failed for %d/%s with error: %d\n", +					i, supported_regulators[i].name, ret); +			return ret; +		} +	} + +	return ret; +} + +static const struct platform_device_id max14577_regulator_id[] = { +	{ "max14577-regulator", MAXIM_DEVICE_TYPE_MAX14577, }, +	{ "max77836-regulator", MAXIM_DEVICE_TYPE_MAX77836, }, +	{ } +}; +MODULE_DEVICE_TABLE(platform, max14577_regulator_id); + +static struct platform_driver max14577_regulator_driver = { +	.driver = { +		   .owner = THIS_MODULE, +		   .name = "max14577-regulator", +		   }, +	.probe		= max14577_regulator_probe, +	.id_table	= max14577_regulator_id, +}; + +static int __init max14577_regulator_init(void) +{ +	/* Check for valid values for charger */ +	BUILD_BUG_ON(MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_START + +			MAX14577_REGULATOR_CURRENT_LIMIT_HIGH_STEP * 0xf != +			MAX14577_REGULATOR_CURRENT_LIMIT_MAX); +	BUILD_BUG_ON(MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_START + +			MAX77836_REGULATOR_CURRENT_LIMIT_HIGH_STEP * 0xf != +			MAX77836_REGULATOR_CURRENT_LIMIT_MAX); +	/* Valid charger current values must be provided for each chipset */ +	BUILD_BUG_ON(ARRAY_SIZE(maxim_charger_currents) != MAXIM_DEVICE_TYPE_NUM); + +	BUILD_BUG_ON(ARRAY_SIZE(max14577_supported_regulators) != MAX14577_REGULATOR_NUM); +	BUILD_BUG_ON(ARRAY_SIZE(max77836_supported_regulators) != MAX77836_REGULATOR_NUM); + +	BUILD_BUG_ON(MAX77836_REGULATOR_LDO_VOLTAGE_MIN + +			(MAX77836_REGULATOR_LDO_VOLTAGE_STEP * +			  (MAX77836_REGULATOR_LDO_VOLTAGE_STEPS_NUM - 1)) != +			MAX77836_REGULATOR_LDO_VOLTAGE_MAX); + +	return platform_driver_register(&max14577_regulator_driver); +} +subsys_initcall(max14577_regulator_init); + +static void __exit max14577_regulator_exit(void) +{ +	platform_driver_unregister(&max14577_regulator_driver); +} +module_exit(max14577_regulator_exit); + +MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>"); +MODULE_DESCRIPTION("Maxim 14577/77836 regulator driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:max14577-regulator"); diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index 3a599ee0a45..d23d0577754 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -46,8 +46,6 @@ struct max1586_data {  	unsigned int v3_curr_sel;  	unsigned int v6_curr_sel; - -	struct regulator_dev *rdev[0];  };  /* @@ -162,14 +160,12 @@ static struct regulator_desc max1586_reg[] = {  static int max1586_pmic_probe(struct i2c_client *client,  					const struct i2c_device_id *i2c_id)  { -	struct regulator_dev **rdev;  	struct max1586_platform_data *pdata = dev_get_platdata(&client->dev);  	struct regulator_config config = { };  	struct max1586_data *max1586; -	int i, id, ret = -ENOMEM; +	int i, id; -	max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data) + -			sizeof(struct regulator_dev *) * (MAX1586_V6 + 1), +	max1586 = devm_kzalloc(&client->dev, sizeof(struct max1586_data),  			GFP_KERNEL);  	if (!max1586)  		return -ENOMEM; @@ -186,14 +182,15 @@ static int max1586_pmic_probe(struct i2c_client *client,  	max1586->v3_curr_sel = 24; /* 1.3V */  	max1586->v6_curr_sel = 0; -	rdev = max1586->rdev;  	for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) { +		struct regulator_dev *rdev; +  		id = pdata->subdevs[i].id;  		if (!pdata->subdevs[i].platform_data)  			continue;  		if (id < MAX1586_V3 || id > MAX1586_V6) {  			dev_err(&client->dev, "invalid regulator id %d\n", id); -			goto err; +			return -EINVAL;  		}  		if (id == MAX1586_V3) { @@ -207,33 +204,18 @@ static int max1586_pmic_probe(struct i2c_client *client,  		config.init_data = pdata->subdevs[i].platform_data;  		config.driver_data = max1586; -		rdev[i] = regulator_register(&max1586_reg[id], &config); -		if (IS_ERR(rdev[i])) { -			ret = PTR_ERR(rdev[i]); +		rdev = devm_regulator_register(&client->dev, +						  &max1586_reg[id], &config); +		if (IS_ERR(rdev)) {  			dev_err(&client->dev, "failed to register %s\n",  				max1586_reg[id].name); -			goto err; +			return PTR_ERR(rdev);  		}  	}  	i2c_set_clientdata(client, max1586);  	dev_info(&client->dev, "Maxim 1586 regulator driver loaded\n");  	return 0; - -err: -	while (--i >= 0) -		regulator_unregister(rdev[i]); -	return ret; -} - -static int max1586_pmic_remove(struct i2c_client *client) -{ -	struct max1586_data *max1586 = i2c_get_clientdata(client); -	int i; - -	for (i = 0; i <= MAX1586_V6; i++) -		regulator_unregister(max1586->rdev[i]); -	return 0;  }  static const struct i2c_device_id max1586_id[] = { @@ -244,7 +226,6 @@ MODULE_DEVICE_TABLE(i2c, max1586_id);  static struct i2c_driver max1586_pmic_driver = {  	.probe = max1586_pmic_probe, -	.remove = max1586_pmic_remove,  	.driver		= {  		.name	= "max1586",  		.owner	= THIS_MODULE, diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c index f563057e569..ef1af2debbd 100644 --- a/drivers/regulator/max77686.c +++ b/drivers/regulator/max77686.c @@ -65,7 +65,6 @@ enum max77686_ramp_rate {  };  struct max77686_data { -	struct regulator_dev *rdev[MAX77686_REGULATORS];  	unsigned int opmode[MAX77686_REGULATORS];  }; @@ -400,7 +399,7 @@ static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,  	unsigned int i;  	pmic_np = iodev->dev->of_node; -	regulators_np = of_find_node_by_name(pmic_np, "voltage-regulators"); +	regulators_np = of_get_child_by_name(pmic_np, "voltage-regulators");  	if (!regulators_np) {  		dev_err(&pdev->dev, "could not find regulators sub-node\n");  		return -EINVAL; @@ -410,8 +409,7 @@ static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,  	rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *  			     pdata->num_regulators, GFP_KERNEL);  	if (!rdata) { -		dev_err(&pdev->dev, -			"could not allocate memory for regulator data\n"); +		of_node_put(regulators_np);  		return -ENOMEM;  	} @@ -425,6 +423,7 @@ static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,  	}  	pdata->regulators = rdata; +	of_node_put(regulators_np);  	return 0;  } @@ -474,36 +473,22 @@ static int max77686_pmic_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, max77686);  	for (i = 0; i < MAX77686_REGULATORS; i++) { +		struct regulator_dev *rdev; +  		config.init_data = pdata->regulators[i].initdata;  		config.of_node = pdata->regulators[i].of_node;  		max77686->opmode[i] = regulators[i].enable_mask; -		max77686->rdev[i] = regulator_register(®ulators[i], &config); -		if (IS_ERR(max77686->rdev[i])) { -			ret = PTR_ERR(max77686->rdev[i]); +		rdev = devm_regulator_register(&pdev->dev, +						®ulators[i], &config); +		if (IS_ERR(rdev)) {  			dev_err(&pdev->dev,  				"regulator init failed for %d\n", i); -			max77686->rdev[i] = NULL; -			goto err; +			return PTR_ERR(rdev);  		}  	}  	return 0; -err: -	while (--i >= 0) -		regulator_unregister(max77686->rdev[i]); -	return ret; -} - -static int max77686_pmic_remove(struct platform_device *pdev) -{ -	struct max77686_data *max77686 = platform_get_drvdata(pdev); -	int i; - -	for (i = 0; i < MAX77686_REGULATORS; i++) -		regulator_unregister(max77686->rdev[i]); - -	return 0;  }  static const struct platform_device_id max77686_pmic_id[] = { @@ -518,7 +503,6 @@ static struct platform_driver max77686_pmic_driver = {  		.owner = THIS_MODULE,  	},  	.probe = max77686_pmic_probe, -	.remove = max77686_pmic_remove,  	.id_table = max77686_pmic_id,  }; diff --git a/drivers/regulator/max77693.c b/drivers/regulator/max77693.c index ce4b96c15eb..653a58b49cd 100644 --- a/drivers/regulator/max77693.c +++ b/drivers/regulator/max77693.c @@ -34,13 +34,6 @@  #define CHGIN_ILIM_STEP_20mA			20000 -struct max77693_pmic_dev { -	struct device *dev; -	struct max77693_dev *iodev; -	int num_regulators; -	struct regulator_dev **rdev; -}; -  /* CHARGER regulator ops */  /* CHARGER regulator uses two bits for enabling */  static int max77693_chg_is_enabled(struct regulator_dev *rdev) @@ -138,6 +131,7 @@ static struct regulator_ops max77693_charger_ops = {  	.n_voltages	= 4,					\  	.ops		= &max77693_safeout_ops,		\  	.type		= REGULATOR_VOLTAGE,			\ +	.owner		= THIS_MODULE,				\  	.volt_table	= max77693_safeout_table,		\  	.vsel_reg	= MAX77693_CHG_REG_SAFEOUT_CTRL,	\  	.vsel_mask	= SAFEOUT_CTRL_SAFEOUT##_num##_MASK,	\ @@ -169,19 +163,22 @@ static int max77693_pmic_dt_parse_rdata(struct device *dev,  	struct max77693_regulator_data *tmp;  	int i, matched = 0; -	np = of_find_node_by_name(dev->parent->of_node, "regulators"); +	np = of_get_child_by_name(dev->parent->of_node, "regulators");  	if (!np)  		return -EINVAL;  	rmatch = devm_kzalloc(dev,  		 sizeof(*rmatch) * ARRAY_SIZE(regulators), GFP_KERNEL); -	if (!rmatch) +	if (!rmatch) { +		of_node_put(np);  		return -ENOMEM; +	}  	for (i = 0; i < ARRAY_SIZE(regulators); i++)  		rmatch[i].name = regulators[i].name;  	matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(regulators)); +	of_node_put(np);  	if (matched <= 0)  		return matched;  	*rdata = devm_kzalloc(dev, sizeof(**rdata) * matched, GFP_KERNEL); @@ -228,9 +225,8 @@ static int max77693_pmic_init_rdata(struct device *dev,  static int max77693_pmic_probe(struct platform_device *pdev)  {  	struct max77693_dev *iodev = dev_get_drvdata(pdev->dev.parent); -	struct max77693_pmic_dev *max77693_pmic;  	struct max77693_regulator_data *rdata = NULL; -	int num_rdata, i, ret; +	int num_rdata, i;  	struct regulator_config config;  	num_rdata = max77693_pmic_init_rdata(&pdev->dev, &rdata); @@ -239,63 +235,26 @@ static int max77693_pmic_probe(struct platform_device *pdev)  		return -ENODEV;  	} -	max77693_pmic = devm_kzalloc(&pdev->dev, -				sizeof(struct max77693_pmic_dev), -				GFP_KERNEL); -	if (!max77693_pmic) -		return -ENOMEM; - -	max77693_pmic->rdev = devm_kzalloc(&pdev->dev, -				sizeof(struct regulator_dev *) * num_rdata, -				GFP_KERNEL); -	if (!max77693_pmic->rdev) -		return -ENOMEM; - -	max77693_pmic->dev = &pdev->dev; -	max77693_pmic->iodev = iodev; -	max77693_pmic->num_regulators = num_rdata; -  	config.dev = &pdev->dev;  	config.regmap = iodev->regmap; -	config.driver_data = max77693_pmic; -	platform_set_drvdata(pdev, max77693_pmic); -	for (i = 0; i < max77693_pmic->num_regulators; i++) { +	for (i = 0; i < num_rdata; i++) {  		int id = rdata[i].id; +		struct regulator_dev *rdev;  		config.init_data = rdata[i].initdata;  		config.of_node = rdata[i].of_node; -		max77693_pmic->rdev[i] = regulator_register(®ulators[id], -							    &config); -		if (IS_ERR(max77693_pmic->rdev[i])) { -			ret = PTR_ERR(max77693_pmic->rdev[i]); -			dev_err(max77693_pmic->dev, +		rdev = devm_regulator_register(&pdev->dev, +						®ulators[id], &config); +		if (IS_ERR(rdev)) { +			dev_err(&pdev->dev,  				"Failed to initialize regulator-%d\n", id); -			max77693_pmic->rdev[i] = NULL; -			goto err; +			return PTR_ERR(rdev);  		}  	}  	return 0; - err: -	while (--i >= 0) -		regulator_unregister(max77693_pmic->rdev[i]); - -	return ret; -} - -static int max77693_pmic_remove(struct platform_device *pdev) -{ -	struct max77693_pmic_dev *max77693_pmic = platform_get_drvdata(pdev); -	struct regulator_dev **rdev = max77693_pmic->rdev; -	int i; - -	for (i = 0; i < max77693_pmic->num_regulators; i++) -		if (rdev[i]) -			regulator_unregister(rdev[i]); - -	return 0;  }  static const struct platform_device_id max77693_pmic_id[] = { @@ -311,7 +270,6 @@ static struct platform_driver max77693_pmic_driver = {  		   .owner = THIS_MODULE,  		   },  	.probe = max77693_pmic_probe, -	.remove = max77693_pmic_remove,  	.id_table = max77693_pmic_id,  }; diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index 19c6f08eafd..c8bddcc8f91 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -49,7 +49,6 @@  #define MAX8649_RAMP_DOWN	(1 << 1)  struct max8649_regulator_info { -	struct regulator_dev	*regulator;  	struct device		*dev;  	struct regmap		*regmap; @@ -154,6 +153,7 @@ static int max8649_regulator_probe(struct i2c_client *client,  {  	struct max8649_platform_data *pdata = dev_get_platdata(&client->dev);  	struct max8649_regulator_info *info = NULL; +	struct regulator_dev *regulator;  	struct regulator_config config = { };  	unsigned int val;  	unsigned char data; @@ -161,10 +161,8 @@ static int max8649_regulator_probe(struct i2c_client *client,  	info = devm_kzalloc(&client->dev, sizeof(struct max8649_regulator_info),  			    GFP_KERNEL); -	if (!info) { -		dev_err(&client->dev, "No enough memory\n"); +	if (!info)  		return -ENOMEM; -	}  	info->regmap = devm_regmap_init_i2c(client, &max8649_regmap_config);  	if (IS_ERR(info->regmap)) { @@ -234,26 +232,17 @@ static int max8649_regulator_probe(struct i2c_client *client,  	config.driver_data = info;  	config.regmap = info->regmap; -	info->regulator = regulator_register(&dcdc_desc, &config); -	if (IS_ERR(info->regulator)) { +	regulator = devm_regulator_register(&client->dev, &dcdc_desc, +						  &config); +	if (IS_ERR(regulator)) {  		dev_err(info->dev, "failed to register regulator %s\n",  			dcdc_desc.name); -		return PTR_ERR(info->regulator); +		return PTR_ERR(regulator);  	}  	return 0;  } -static int max8649_regulator_remove(struct i2c_client *client) -{ -	struct max8649_regulator_info *info = i2c_get_clientdata(client); - -	if (info) -		regulator_unregister(info->regulator); - -	return 0; -} -  static const struct i2c_device_id max8649_id[] = {  	{ "max8649", 0 },  	{ } @@ -262,7 +251,6 @@ MODULE_DEVICE_TABLE(i2c, max8649_id);  static struct i2c_driver max8649_driver = {  	.probe		= max8649_regulator_probe, -	.remove		= max8649_regulator_remove,  	.driver		= {  		.name	= "max8649",  	}, diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index 144bcacd734..2fc41118879 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -81,16 +81,17 @@ enum {  struct max8660 {  	struct i2c_client *client;  	u8 shadow_regs[MAX8660_N_REGS];		/* as chip is write only */ -	struct regulator_dev *rdev[];  };  static int max8660_write(struct max8660 *max8660, u8 reg, u8 mask, u8 val)  { -	static const u8 max8660_addresses[MAX8660_N_REGS] = -	  { 0x10, 0x12, 0x20, 0x23, 0x24, 0x29, 0x2a, 0x32, 0x33, 0x39, 0x80 }; +	static const u8 max8660_addresses[MAX8660_N_REGS] = { +	 0x10, 0x12, 0x20, 0x23, 0x24, 0x29, 0x2a, 0x32, 0x33, 0x39, 0x80 +	};  	int ret;  	u8 reg_val = (max8660->shadow_regs[reg] & mask) | val; +  	dev_vdbg(&max8660->client->dev, "Writing reg %02x with %02x\n",  			max8660_addresses[reg], reg_val); @@ -112,6 +113,7 @@ static int max8660_dcdc_is_enabled(struct regulator_dev *rdev)  	struct max8660 *max8660 = rdev_get_drvdata(rdev);  	u8 val = max8660->shadow_regs[MAX8660_OVER1];  	u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4; +  	return !!(val & mask);  } @@ -119,6 +121,7 @@ static int max8660_dcdc_enable(struct regulator_dev *rdev)  {  	struct max8660 *max8660 = rdev_get_drvdata(rdev);  	u8 bit = (rdev_get_id(rdev) == MAX8660_V3) ? 1 : 4; +  	return max8660_write(max8660, MAX8660_OVER1, 0xff, bit);  } @@ -126,15 +129,16 @@ static int max8660_dcdc_disable(struct regulator_dev *rdev)  {  	struct max8660 *max8660 = rdev_get_drvdata(rdev);  	u8 mask = (rdev_get_id(rdev) == MAX8660_V3) ? ~1 : ~4; +  	return max8660_write(max8660, MAX8660_OVER1, mask, 0);  }  static int max8660_dcdc_get_voltage_sel(struct regulator_dev *rdev)  {  	struct max8660 *max8660 = rdev_get_drvdata(rdev); -  	u8 reg = (rdev_get_id(rdev) == MAX8660_V3) ? MAX8660_ADTV2 : MAX8660_SDTV2;  	u8 selector = max8660->shadow_regs[reg]; +  	return selector;  } @@ -207,6 +211,7 @@ static int max8660_ldo67_is_enabled(struct regulator_dev *rdev)  	struct max8660 *max8660 = rdev_get_drvdata(rdev);  	u8 val = max8660->shadow_regs[MAX8660_OVER2];  	u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4; +  	return !!(val & mask);  } @@ -214,6 +219,7 @@ static int max8660_ldo67_enable(struct regulator_dev *rdev)  {  	struct max8660 *max8660 = rdev_get_drvdata(rdev);  	u8 bit = (rdev_get_id(rdev) == MAX8660_V6) ? 2 : 4; +  	return max8660_write(max8660, MAX8660_OVER2, 0xff, bit);  } @@ -221,15 +227,16 @@ static int max8660_ldo67_disable(struct regulator_dev *rdev)  {  	struct max8660 *max8660 = rdev_get_drvdata(rdev);  	u8 mask = (rdev_get_id(rdev) == MAX8660_V6) ? ~2 : ~4; +  	return max8660_write(max8660, MAX8660_OVER2, mask, 0);  }  static int max8660_ldo67_get_voltage_sel(struct regulator_dev *rdev)  {  	struct max8660 *max8660 = rdev_get_drvdata(rdev); -  	u8 shift = (rdev_get_id(rdev) == MAX8660_V6) ? 0 : 4;  	u8 selector = (max8660->shadow_regs[MAX8660_L12VCR] >> shift) & 0xf; +  	return selector;  } @@ -330,7 +337,7 @@ static int max8660_pdata_from_dt(struct device *dev,  	struct max8660_subdev_data *sub;  	struct of_regulator_match rmatch[ARRAY_SIZE(max8660_reg)]; -	np = of_find_node_by_name(dev->of_node, "regulators"); +	np = of_get_child_by_name(dev->of_node, "regulators");  	if (!np) {  		dev_err(dev, "missing 'regulators' subnode in DT\n");  		return -EINVAL; @@ -340,6 +347,7 @@ static int max8660_pdata_from_dt(struct device *dev,  		rmatch[i].name = max8660_reg[i].name;  	matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(rmatch)); +	of_node_put(np);  	if (matched <= 0)  		return matched; @@ -373,7 +381,6 @@ static inline int max8660_pdata_from_dt(struct device *dev,  static int max8660_probe(struct i2c_client *client,  				   const struct i2c_device_id *i2c_id)  { -	struct regulator_dev **rdev;  	struct device *dev = &client->dev;  	struct max8660_platform_data *pdata = dev_get_platdata(dev);  	struct regulator_config config = { }; @@ -406,14 +413,11 @@ static int max8660_probe(struct i2c_client *client,  		return -EINVAL;  	} -	max8660 = devm_kzalloc(dev, sizeof(struct max8660) + -			sizeof(struct regulator_dev *) * MAX8660_V_END, -			GFP_KERNEL); +	max8660 = devm_kzalloc(dev, sizeof(struct max8660), GFP_KERNEL);  	if (!max8660)  		return -ENOMEM;  	max8660->client = client; -	rdev = max8660->rdev;  	if (pdata->en34_is_high) {  		/* Simulate always on */ @@ -439,7 +443,7 @@ static int max8660_probe(struct i2c_client *client,  	for (i = 0; i < pdata->num_subdevs; i++) {  		if (!pdata->subdevs[i].platform_data) -			goto err_out; +			return ret;  		boot_on = pdata->subdevs[i].platform_data->constraints.boot_on; @@ -465,7 +469,7 @@ static int max8660_probe(struct i2c_client *client,  		case MAX8660_V7:  			if (type == MAX8661) {  				dev_err(dev, "Regulator not on this chip!\n"); -				goto err_out; +				return -EINVAL;  			}  			if (boot_on) @@ -475,12 +479,13 @@ static int max8660_probe(struct i2c_client *client,  		default:  			dev_err(dev, "invalid regulator %s\n",  				 pdata->subdevs[i].name); -			goto err_out; +			return ret;  		}  	}  	/* Finally register devices */  	for (i = 0; i < pdata->num_subdevs; i++) { +		struct regulator_dev *rdev;  		id = pdata->subdevs[i].id; @@ -489,33 +494,18 @@ static int max8660_probe(struct i2c_client *client,  		config.of_node = of_node[i];  		config.driver_data = max8660; -		rdev[i] = regulator_register(&max8660_reg[id], &config); -		if (IS_ERR(rdev[i])) { -			ret = PTR_ERR(rdev[i]); -			dev_err(dev, "failed to register %s\n", +		rdev = devm_regulator_register(&client->dev, +						  &max8660_reg[id], &config); +		if (IS_ERR(rdev)) { +			ret = PTR_ERR(rdev); +			dev_err(&client->dev, "failed to register %s\n",  				max8660_reg[id].name); -			goto err_unregister; +			return PTR_ERR(rdev);  		}  	}  	i2c_set_clientdata(client, max8660);  	return 0; - -err_unregister: -	while (--i >= 0) -		regulator_unregister(rdev[i]); -err_out: -	return ret; -} - -static int max8660_remove(struct i2c_client *client) -{ -	struct max8660 *max8660 = i2c_get_clientdata(client); -	int i; - -	for (i = 0; i < MAX8660_V_END; i++) -		regulator_unregister(max8660->rdev[i]); -	return 0;  }  static const struct i2c_device_id max8660_id[] = { @@ -527,7 +517,6 @@ MODULE_DEVICE_TABLE(i2c, max8660_id);  static struct i2c_driver max8660_driver = {  	.probe = max8660_probe, -	.remove = max8660_remove,  	.driver		= {  		.name	= "max8660",  		.owner	= THIS_MODULE, diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c index 4568c15fa78..9623e9e290b 100644 --- a/drivers/regulator/max8907-regulator.c +++ b/drivers/regulator/max8907-regulator.c @@ -34,7 +34,6 @@  struct max8907_regulator {  	struct regulator_desc desc[MAX8907_NUM_REGULATORS]; -	struct regulator_dev *rdev[MAX8907_NUM_REGULATORS];  };  #define REG_MBATT() \ @@ -231,7 +230,7 @@ static int max8907_regulator_parse_dt(struct platform_device *pdev)  	if (!np)  		return 0; -	regulators = of_find_node_by_name(np, "regulators"); +	regulators = of_get_child_by_name(np, "regulators");  	if (!regulators) {  		dev_err(&pdev->dev, "regulators node not found\n");  		return -EINVAL; @@ -292,10 +291,9 @@ static int max8907_regulator_probe(struct platform_device *pdev)  		return ret;  	pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); -	if (!pmic) { -		dev_err(&pdev->dev, "Failed to alloc pmic\n"); +	if (!pmic)  		return -ENOMEM; -	} +  	platform_set_drvdata(pdev, pmic);  	memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc)); @@ -311,6 +309,8 @@ static int max8907_regulator_probe(struct platform_device *pdev)  	}  	for (i = 0; i < MAX8907_NUM_REGULATORS; i++) { +		struct regulator_dev *rdev; +  		config.dev = pdev->dev.parent;  		if (pdata)  			idata = pdata->init_data[i]; @@ -350,33 +350,17 @@ static int max8907_regulator_probe(struct platform_device *pdev)  				pmic->desc[i].ops = &max8907_out5v_hwctl_ops;  		} -		pmic->rdev[i] = regulator_register(&pmic->desc[i], &config); -		if (IS_ERR(pmic->rdev[i])) { +		rdev = devm_regulator_register(&pdev->dev, +						&pmic->desc[i], &config); +		if (IS_ERR(rdev)) {  			dev_err(&pdev->dev,  				"failed to register %s regulator\n",  				pmic->desc[i].name); -			ret = PTR_ERR(pmic->rdev[i]); -			goto err_unregister_regulator; +			return PTR_ERR(rdev);  		}  	}  	return 0; - -err_unregister_regulator: -	while (--i >= 0) -		regulator_unregister(pmic->rdev[i]); -	return ret; -} - -static int max8907_regulator_remove(struct platform_device *pdev) -{ -	struct max8907_regulator *pmic = platform_get_drvdata(pdev); -	int i; - -	for (i = 0; i < MAX8907_NUM_REGULATORS; i++) -		regulator_unregister(pmic->rdev[i]); - -	return 0;  }  static struct platform_driver max8907_regulator_driver = { @@ -385,7 +369,6 @@ static struct platform_driver max8907_regulator_driver = {  		   .owner = THIS_MODULE,  		   },  	.probe = max8907_regulator_probe, -	.remove = max8907_regulator_remove,  };  static int __init max8907_regulator_init(void) diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index d80b5fa758a..dad2bcd14e9 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -36,9 +36,7 @@  struct max8925_regulator_info {  	struct regulator_desc	desc; -	struct regulator_dev	*regulator;  	struct i2c_client	*i2c; -	struct max8925_chip	*chip;  	int	vol_reg;  	int	enable_reg; @@ -251,10 +249,11 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,  {  	struct device_node *nproot, *np;  	int rcount; +  	nproot = of_node_get(pdev->dev.parent->of_node);  	if (!nproot)  		return -ENODEV; -	np = of_find_node_by_name(nproot, "regulators"); +	np = of_get_child_by_name(nproot, "regulators");  	if (!np) {  		dev_err(&pdev->dev, "failed to find regulators node\n");  		return -ENODEV; @@ -264,7 +263,7 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,  				&max8925_regulator_matches[ridx], 1);  	of_node_put(np);  	if (rcount < 0) -		return -ENODEV; +		return rcount;  	config->init_data =	max8925_regulator_matches[ridx].init_data;  	config->of_node = max8925_regulator_matches[ridx].of_node; @@ -303,7 +302,6 @@ static int max8925_regulator_probe(struct platform_device *pdev)  		return -EINVAL;  	}  	ri->i2c = chip->i2c; -	ri->chip = chip;  	config.dev = &pdev->dev;  	config.driver_data = ri; @@ -312,7 +310,7 @@ static int max8925_regulator_probe(struct platform_device *pdev)  		if (pdata)  			config.init_data = pdata; -	rdev = regulator_register(&ri->desc, &config); +	rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config);  	if (IS_ERR(rdev)) {  		dev_err(&pdev->dev, "failed to register regulator %s\n",  				ri->desc.name); @@ -323,22 +321,12 @@ static int max8925_regulator_probe(struct platform_device *pdev)  	return 0;  } -static int max8925_regulator_remove(struct platform_device *pdev) -{ -	struct regulator_dev *rdev = platform_get_drvdata(pdev); - -	regulator_unregister(rdev); - -	return 0; -} -  static struct platform_driver max8925_regulator_driver = {  	.driver		= {  		.name	= "max8925-regulator",  		.owner	= THIS_MODULE,  	},  	.probe		= max8925_regulator_probe, -	.remove		= max8925_regulator_remove,  };  static int __init max8925_regulator_init(void) diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 788e5ae2af1..c2792f0271a 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -48,9 +48,7 @@ enum {  struct max8952_data {  	struct i2c_client	*client; -	struct device		*dev;  	struct max8952_platform_data *pdata; -	struct regulator_dev	*rdev;  	bool vid0;  	bool vid1; @@ -59,6 +57,7 @@ struct max8952_data {  static int max8952_read_reg(struct max8952_data *max8952, u8 reg)  {  	int ret = i2c_smbus_read_byte_data(max8952->client, reg); +  	if (ret > 0)  		ret &= 0xff; @@ -130,7 +129,7 @@ static const struct regulator_desc regulator = {  };  #ifdef CONFIG_OF -static struct of_device_id max8952_dt_match[] = { +static const struct of_device_id max8952_dt_match[] = {  	{ .compatible = "maxim,max8952" },  	{},  }; @@ -144,10 +143,8 @@ static struct max8952_platform_data *max8952_parse_dt(struct device *dev)  	int i;  	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); -	if (!pd) { -		dev_err(dev, "Failed to allocate platform data\n"); +	if (!pd)  		return NULL; -	}  	pd->gpio_vid0 = of_get_named_gpio(np, "max8952,vid-gpios", 0);  	pd->gpio_vid1 = of_get_named_gpio(np, "max8952,vid-gpios", 1); @@ -199,6 +196,7 @@ static int max8952_pmic_probe(struct i2c_client *client,  	struct max8952_platform_data *pdata = dev_get_platdata(&client->dev);  	struct regulator_config config = { };  	struct max8952_data *max8952; +	struct regulator_dev *rdev;  	int ret = 0, err = 0; @@ -219,10 +217,9 @@ static int max8952_pmic_probe(struct i2c_client *client,  		return -ENOMEM;  	max8952->client = client; -	max8952->dev = &client->dev;  	max8952->pdata = pdata; -	config.dev = max8952->dev; +	config.dev = &client->dev;  	config.init_data = pdata->reg_data;  	config.driver_data = max8952;  	config.of_node = client->dev.of_node; @@ -231,11 +228,11 @@ static int max8952_pmic_probe(struct i2c_client *client,  	if (pdata->reg_data->constraints.boot_on)  		config.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; -	max8952->rdev = regulator_register(®ulator, &config); +	rdev = devm_regulator_register(&client->dev, ®ulator, &config); -	if (IS_ERR(max8952->rdev)) { -		ret = PTR_ERR(max8952->rdev); -		dev_err(max8952->dev, "regulator init failed (%d)\n", ret); +	if (IS_ERR(rdev)) { +		ret = PTR_ERR(rdev); +		dev_err(&client->dev, "regulator init failed (%d)\n", ret);  		return ret;  	} @@ -263,7 +260,7 @@ static int max8952_pmic_probe(struct i2c_client *client,  		err = 3;  	if (err) { -		dev_warn(max8952->dev, "VID0/1 gpio invalid: " +		dev_warn(&client->dev, "VID0/1 gpio invalid: "  				"DVS not available.\n");  		max8952->vid0 = 0;  		max8952->vid1 = 0; @@ -274,7 +271,7 @@ static int max8952_pmic_probe(struct i2c_client *client,  		/* Disable Pulldown of EN only */  		max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x60); -		dev_err(max8952->dev, "DVS modes disabled because VID0 and VID1" +		dev_err(&client->dev, "DVS modes disabled because VID0 and VID1"  				" do not have proper controls.\n");  	} else {  		/* @@ -321,9 +318,6 @@ static int max8952_pmic_remove(struct i2c_client *client)  {  	struct max8952_data *max8952 = i2c_get_clientdata(client);  	struct max8952_platform_data *pdata = max8952->pdata; -	struct regulator_dev *rdev = max8952->rdev; - -	regulator_unregister(rdev);  	gpio_free(pdata->gpio_vid0);  	gpio_free(pdata->gpio_vid1); diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 5b77ab7762e..dbedf1768db 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -93,7 +93,6 @@  struct max8973_chip {  	struct device *dev;  	struct regulator_desc desc; -	struct regulator_dev *rdev;  	struct regmap *regmap;  	bool enable_external_control;  	int dvs_gpio; @@ -379,10 +378,8 @@ static int max8973_probe(struct i2c_client *client,  	}  	max = devm_kzalloc(&client->dev, sizeof(*max), GFP_KERNEL); -	if (!max) { -		dev_err(&client->dev, "Memory allocation for max failed\n"); +	if (!max)  		return -ENOMEM; -	}  	max->regmap = devm_regmap_init_i2c(client, &max8973_regmap_config);  	if (IS_ERR(max->regmap)) { @@ -467,22 +464,13 @@ static int max8973_probe(struct i2c_client *client,  	config.regmap = max->regmap;  	/* Register the regulators */ -	rdev = regulator_register(&max->desc, &config); +	rdev = devm_regulator_register(&client->dev, &max->desc, &config);  	if (IS_ERR(rdev)) {  		ret = PTR_ERR(rdev);  		dev_err(max->dev, "regulator register failed, err %d\n", ret);  		return ret;  	} -	max->rdev = rdev; -	return 0; -} - -static int max8973_remove(struct i2c_client *client) -{ -	struct max8973_chip *max = i2c_get_clientdata(client); - -	regulator_unregister(max->rdev);  	return 0;  } @@ -499,7 +487,6 @@ static struct i2c_driver max8973_i2c_driver = {  		.owner = THIS_MODULE,  	},  	.probe = max8973_probe, -	.remove = max8973_remove,  	.id_table = max8973_id,  }; diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index df20069f053..90b4c530dee 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -38,7 +38,6 @@ struct max8997_data {  	struct device *dev;  	struct max8997_dev *iodev;  	int num_regulators; -	struct regulator_dev **rdev;  	int ramp_delay; /* in mV/us */  	bool buck1_gpiodvs; @@ -690,8 +689,9 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev,  	if (max8997->ignore_gpiodvs_side_effect == false)  		return -EINVAL; -	dev_warn(&rdev->dev, "MAX8997 GPIO-DVS Side Effect Warning: GPIO SET:" -			" %d -> %d\n", max8997->buck125_gpioindex, tmp_idx); +	dev_warn(&rdev->dev, +		"MAX8997 GPIO-DVS Side Effect Warning: GPIO SET:  %d -> %d\n", +		max8997->buck125_gpioindex, tmp_idx);  out:  	if (new_idx < 0 || new_val < 0) @@ -923,7 +923,7 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,  		return -ENODEV;  	} -	regulators_np = of_find_node_by_name(pmic_np, "regulators"); +	regulators_np = of_get_child_by_name(pmic_np, "regulators");  	if (!regulators_np) {  		dev_err(&pdev->dev, "could not find regulators sub-node\n");  		return -EINVAL; @@ -936,7 +936,6 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,  				pdata->num_regulators, GFP_KERNEL);  	if (!rdata) {  		of_node_put(regulators_np); -		dev_err(&pdev->dev, "could not allocate memory for regulator data\n");  		return -ENOMEM;  	} @@ -1029,10 +1028,10 @@ static int max8997_pmic_probe(struct platform_device *pdev)  	struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);  	struct max8997_platform_data *pdata = iodev->pdata;  	struct regulator_config config = { }; -	struct regulator_dev **rdev; +	struct regulator_dev *rdev;  	struct max8997_data *max8997;  	struct i2c_client *i2c; -	int i, ret, size, nr_dvs; +	int i, ret, nr_dvs;  	u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0;  	if (!pdata) { @@ -1051,12 +1050,6 @@ static int max8997_pmic_probe(struct platform_device *pdev)  	if (!max8997)  		return -ENOMEM; -	size = sizeof(struct regulator_dev *) * pdata->num_regulators; -	max8997->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); -	if (!max8997->rdev) -		return -ENOMEM; - -	rdev = max8997->rdev;  	max8997->dev = &pdev->dev;  	max8997->iodev = iodev;  	max8997->num_regulators = pdata->num_regulators; @@ -1081,7 +1074,7 @@ static int max8997_pmic_probe(struct platform_device *pdev)  					pdata->buck1_voltage[i] +  					buck1245_voltage_map_desc.step);  		if (ret < 0) -			goto err_out; +			return ret;  		max8997->buck2_vol[i] = ret =  			max8997_get_voltage_proper_val( @@ -1090,7 +1083,7 @@ static int max8997_pmic_probe(struct platform_device *pdev)  					pdata->buck2_voltage[i] +  					buck1245_voltage_map_desc.step);  		if (ret < 0) -			goto err_out; +			return ret;  		max8997->buck5_vol[i] = ret =  			max8997_get_voltage_proper_val( @@ -1099,7 +1092,7 @@ static int max8997_pmic_probe(struct platform_device *pdev)  					pdata->buck5_voltage[i] +  					buck1245_voltage_map_desc.step);  		if (ret < 0) -			goto err_out; +			return ret;  		if (max_buck1 < max8997->buck1_vol[i])  			max_buck1 = max8997->buck1_vol[i]; @@ -1143,24 +1136,23 @@ static int max8997_pmic_probe(struct platform_device *pdev)  				!gpio_is_valid(pdata->buck125_gpios[1]) ||  				!gpio_is_valid(pdata->buck125_gpios[2])) {  			dev_err(&pdev->dev, "GPIO NOT VALID\n"); -			ret = -EINVAL; -			goto err_out; +			return -EINVAL;  		}  		ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[0],  					"MAX8997 SET1");  		if (ret) -			goto err_out; +			return ret;  		ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[1],  					"MAX8997 SET2");  		if (ret) -			goto err_out; +			return ret;  		ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[2],  				"MAX8997 SET3");  		if (ret) -			goto err_out; +			return ret;  		gpio_direction_output(pdata->buck125_gpios[0],  				(max8997->buck125_gpioindex >> 2) @@ -1205,33 +1197,16 @@ static int max8997_pmic_probe(struct platform_device *pdev)  		config.driver_data = max8997;  		config.of_node = pdata->regulators[i].reg_node; -		rdev[i] = regulator_register(®ulators[id], &config); -		if (IS_ERR(rdev[i])) { -			ret = PTR_ERR(rdev[i]); +		rdev = devm_regulator_register(&pdev->dev, ®ulators[id], +					       &config); +		if (IS_ERR(rdev)) {  			dev_err(max8997->dev, "regulator init failed for %d\n",  					id); -			rdev[i] = NULL; -			goto err; +			return PTR_ERR(rdev);  		}  	}  	return 0; -err: -	while (--i >= 0) -		regulator_unregister(rdev[i]); -err_out: -	return ret; -} - -static int max8997_pmic_remove(struct platform_device *pdev) -{ -	struct max8997_data *max8997 = platform_get_drvdata(pdev); -	struct regulator_dev **rdev = max8997->rdev; -	int i; - -	for (i = 0; i < max8997->num_regulators; i++) -		regulator_unregister(rdev[i]); -	return 0;  }  static const struct platform_device_id max8997_pmic_id[] = { @@ -1246,7 +1221,6 @@ static struct platform_driver max8997_pmic_driver = {  		.owner = THIS_MODULE,  	},  	.probe = max8997_pmic_probe, -	.remove = max8997_pmic_remove,  	.id_table = max8997_pmic_id,  }; diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index a4c53b2d1aa..961091b4655 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -40,7 +40,6 @@ struct max8998_data {  	struct device		*dev;  	struct max8998_dev	*iodev;  	int			num_regulators; -	struct regulator_dev	**rdev;  	u8                      buck1_vol[4]; /* voltages for selection */  	u8                      buck2_vol[2];  	unsigned int		buck1_idx; /* index to last changed voltage */ @@ -674,8 +673,10 @@ static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev,  	rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) *  				pdata->num_regulators, GFP_KERNEL); -	if (!rdata) +	if (!rdata) { +		of_node_put(regulators_np);  		return -ENOMEM; +	}  	pdata->regulators = rdata;  	for (i = 0; i < ARRAY_SIZE(regulators); ++i) { @@ -692,6 +693,9 @@ static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev,  	}  	pdata->num_regulators = rdata - pdata->regulators; +	of_node_put(reg_np); +	of_node_put(regulators_np); +  	ret = max8998_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np);  	if (ret)  		return -EINVAL; @@ -741,10 +745,10 @@ static int max8998_pmic_probe(struct platform_device *pdev)  	struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);  	struct max8998_platform_data *pdata = iodev->pdata;  	struct regulator_config config = { }; -	struct regulator_dev **rdev; +	struct regulator_dev *rdev;  	struct max8998_data *max8998;  	struct i2c_client *i2c; -	int i, ret, size; +	int i, ret;  	unsigned int v;  	if (!pdata) { @@ -763,12 +767,6 @@ static int max8998_pmic_probe(struct platform_device *pdev)  	if (!max8998)  		return -ENOMEM; -	size = sizeof(struct regulator_dev *) * pdata->num_regulators; -	max8998->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); -	if (!max8998->rdev) -		return -ENOMEM; - -	rdev = max8998->rdev;  	max8998->dev = &pdev->dev;  	max8998->iodev = iodev;  	max8998->num_regulators = pdata->num_regulators; @@ -790,16 +788,14 @@ static int max8998_pmic_probe(struct platform_device *pdev)  			dev_err(&pdev->dev,  				"MAX8998 SET1 GPIO defined as 0 !\n");  			WARN_ON(!pdata->buck1_set1); -			ret = -EIO; -			goto err_out; +			return -EIO;  		}  		/* Check if SET2 is not equal to 0 */  		if (!pdata->buck1_set2) {  			dev_err(&pdev->dev,  				"MAX8998 SET2 GPIO defined as 0 !\n");  			WARN_ON(!pdata->buck1_set2); -			ret = -EIO; -			goto err_out; +			return -EIO;  		}  		gpio_request(pdata->buck1_set1, "MAX8998 BUCK1_SET1"); @@ -823,7 +819,7 @@ static int max8998_pmic_probe(struct platform_device *pdev)  			ret = max8998_write_reg(i2c,  					MAX8998_REG_BUCK1_VOLTAGE1 + v, i);  			if (ret) -				goto err_out; +				return ret;  		}  	} @@ -833,8 +829,7 @@ static int max8998_pmic_probe(struct platform_device *pdev)  			dev_err(&pdev->dev,  				"MAX8998 SET3 GPIO defined as 0 !\n");  			WARN_ON(!pdata->buck2_set3); -			ret = -EIO; -			goto err_out; +			return -EIO;  		}  		gpio_request(pdata->buck2_set3, "MAX8998 BUCK2_SET3");  		gpio_direction_output(pdata->buck2_set3, @@ -852,7 +847,7 @@ static int max8998_pmic_probe(struct platform_device *pdev)  			ret = max8998_write_reg(i2c,  					MAX8998_REG_BUCK2_VOLTAGE1 + v, i);  			if (ret) -				goto err_out; +				return ret;  		}  	} @@ -875,34 +870,18 @@ static int max8998_pmic_probe(struct platform_device *pdev)  		config.init_data = pdata->regulators[i].initdata;  		config.driver_data = max8998; -		rdev[i] = regulator_register(®ulators[index], &config); -		if (IS_ERR(rdev[i])) { -			ret = PTR_ERR(rdev[i]); +		rdev = devm_regulator_register(&pdev->dev, ®ulators[index], +					       &config); +		if (IS_ERR(rdev)) { +			ret = PTR_ERR(rdev);  			dev_err(max8998->dev, "regulator %s init failed (%d)\n",  						regulators[index].name, ret); -			rdev[i] = NULL; -			goto err; +			return ret;  		}  	}  	return 0; -err: -	while (--i >= 0) -		regulator_unregister(rdev[i]); -err_out: -	return ret; -} - -static int max8998_pmic_remove(struct platform_device *pdev) -{ -	struct max8998_data *max8998 = platform_get_drvdata(pdev); -	struct regulator_dev **rdev = max8998->rdev; -	int i; - -	for (i = 0; i < max8998->num_regulators; i++) -		regulator_unregister(rdev[i]); -	return 0;  }  static const struct platform_device_id max8998_pmic_id[] = { @@ -918,7 +897,6 @@ static struct platform_driver max8998_pmic_driver = {  		.owner = THIS_MODULE,  	},  	.probe = max8998_pmic_probe, -	.remove = max8998_pmic_remove,  	.id_table = max8998_pmic_id,  }; diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 5ff99d2703d..7f4a67edf78 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -258,34 +258,34 @@ static struct mc13xxx_regulator mc13783_regulators[] = {  	MC13783_FIXED_DEFINE(REG, VAUDIO, REGULATORMODE0, mc13783_vaudio_val),  	MC13783_FIXED_DEFINE(REG, VIOHI, REGULATORMODE0, mc13783_viohi_val), -	MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0, REGULATORSETTING0,	\ +	MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0, REGULATORSETTING0,  			    mc13783_violo_val), -	MC13783_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0,	\ +	MC13783_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0,  			    mc13783_vdig_val), -	MC13783_DEFINE_REGU(VGEN, REGULATORMODE0, REGULATORSETTING0,	\ +	MC13783_DEFINE_REGU(VGEN, REGULATORMODE0, REGULATORSETTING0,  			    mc13783_vgen_val), -	MC13783_DEFINE_REGU(VRFDIG, REGULATORMODE0, REGULATORSETTING0,	\ +	MC13783_DEFINE_REGU(VRFDIG, REGULATORMODE0, REGULATORSETTING0,  			    mc13783_vrfdig_val), -	MC13783_DEFINE_REGU(VRFREF, REGULATORMODE0, REGULATORSETTING0,	\ +	MC13783_DEFINE_REGU(VRFREF, REGULATORMODE0, REGULATORSETTING0,  			    mc13783_vrfref_val), -	MC13783_DEFINE_REGU(VRFCP, REGULATORMODE0, REGULATORSETTING0,	\ +	MC13783_DEFINE_REGU(VRFCP, REGULATORMODE0, REGULATORSETTING0,  			    mc13783_vrfcp_val), -	MC13783_DEFINE_REGU(VSIM, REGULATORMODE1, REGULATORSETTING0,	\ +	MC13783_DEFINE_REGU(VSIM, REGULATORMODE1, REGULATORSETTING0,  			    mc13783_vsim_val), -	MC13783_DEFINE_REGU(VESIM, REGULATORMODE1, REGULATORSETTING0,	\ +	MC13783_DEFINE_REGU(VESIM, REGULATORMODE1, REGULATORSETTING0,  			    mc13783_vesim_val), -	MC13783_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0,	\ +	MC13783_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0,  			    mc13783_vcam_val),  	MC13783_FIXED_DEFINE(REG, VRFBG, REGULATORMODE1, mc13783_vrfbg_val), -	MC13783_DEFINE_REGU(VVIB, REGULATORMODE1, REGULATORSETTING1,	\ +	MC13783_DEFINE_REGU(VVIB, REGULATORMODE1, REGULATORSETTING1,  			    mc13783_vvib_val), -	MC13783_DEFINE_REGU(VRF1, REGULATORMODE1, REGULATORSETTING1,	\ +	MC13783_DEFINE_REGU(VRF1, REGULATORMODE1, REGULATORSETTING1,  			    mc13783_vrf_val), -	MC13783_DEFINE_REGU(VRF2, REGULATORMODE1, REGULATORSETTING1,	\ +	MC13783_DEFINE_REGU(VRF2, REGULATORMODE1, REGULATORSETTING1,  			    mc13783_vrf_val), -	MC13783_DEFINE_REGU(VMMC1, REGULATORMODE1, REGULATORSETTING1,	\ +	MC13783_DEFINE_REGU(VMMC1, REGULATORMODE1, REGULATORSETTING1,  			    mc13783_vmmc_val), -	MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1, REGULATORSETTING1,	\ +	MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1, REGULATORSETTING1,  			    mc13783_vmmc_val),  	MC13783_GPO_DEFINE(REG, GPO1, POWERMISC, mc13783_gpo_val),  	MC13783_GPO_DEFINE(REG, GPO2, POWERMISC, mc13783_gpo_val), @@ -400,7 +400,7 @@ static int mc13783_regulator_probe(struct platform_device *pdev)  		dev_get_platdata(&pdev->dev);  	struct mc13xxx_regulator_init_data *mc13xxx_data;  	struct regulator_config config = { }; -	int i, ret, num_regulators; +	int i, num_regulators;  	num_regulators = mc13xxx_get_num_regulators_dt(pdev); @@ -444,32 +444,16 @@ static int mc13783_regulator_probe(struct platform_device *pdev)  		config.driver_data = priv;  		config.of_node = node; -		priv->regulators[i] = regulator_register(desc, &config); +		priv->regulators[i] = devm_regulator_register(&pdev->dev, desc, +							      &config);  		if (IS_ERR(priv->regulators[i])) {  			dev_err(&pdev->dev, "failed to register regulator %s\n",  				mc13783_regulators[i].desc.name); -			ret = PTR_ERR(priv->regulators[i]); -			goto err; +			return PTR_ERR(priv->regulators[i]);  		}  	}  	return 0; -err: -	while (--i >= 0) -		regulator_unregister(priv->regulators[i]); - -	return ret; -} - -static int mc13783_regulator_remove(struct platform_device *pdev) -{ -	struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); -	int i; - -	for (i = 0; i < priv->num_regulators; i++) -		regulator_unregister(priv->regulators[i]); - -	return 0;  }  static struct platform_driver mc13783_regulator_driver = { @@ -477,7 +461,6 @@ static struct platform_driver mc13783_regulator_driver = {  		.name	= "mc13783-regulator",  		.owner	= THIS_MODULE,  	}, -	.remove		= mc13783_regulator_remove,  	.probe		= mc13783_regulator_probe,  }; diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index 1037e07937c..f374fa57220 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -274,25 +274,25 @@ static struct mc13xxx_regulator mc13892_regulators[] = {  	MC13892_SW_DEFINE(SW4, SWITCHERS3, SWITCHERS3, mc13892_sw),  	MC13892_FIXED_DEFINE(SWBST, SWITCHERS5, mc13892_swbst),  	MC13892_FIXED_DEFINE(VIOHI, REGULATORMODE0, mc13892_viohi), -	MC13892_DEFINE_REGU(VPLL, REGULATORMODE0, REGULATORSETTING0,	\ +	MC13892_DEFINE_REGU(VPLL, REGULATORMODE0, REGULATORSETTING0,  		mc13892_vpll), -	MC13892_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0,	\ +	MC13892_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0,  		mc13892_vdig), -	MC13892_DEFINE_REGU(VSD, REGULATORMODE1, REGULATORSETTING1,	\ +	MC13892_DEFINE_REGU(VSD, REGULATORMODE1, REGULATORSETTING1,  		mc13892_vsd), -	MC13892_DEFINE_REGU(VUSB2, REGULATORMODE0, REGULATORSETTING0,	\ +	MC13892_DEFINE_REGU(VUSB2, REGULATORMODE0, REGULATORSETTING0,  		mc13892_vusb2), -	MC13892_DEFINE_REGU(VVIDEO, REGULATORMODE1, REGULATORSETTING1,	\ +	MC13892_DEFINE_REGU(VVIDEO, REGULATORMODE1, REGULATORSETTING1,  		mc13892_vvideo), -	MC13892_DEFINE_REGU(VAUDIO, REGULATORMODE1, REGULATORSETTING1,	\ +	MC13892_DEFINE_REGU(VAUDIO, REGULATORMODE1, REGULATORSETTING1,  		mc13892_vaudio), -	MC13892_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0,	\ +	MC13892_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0,  		mc13892_vcam), -	MC13892_DEFINE_REGU(VGEN1, REGULATORMODE0, REGULATORSETTING0,	\ +	MC13892_DEFINE_REGU(VGEN1, REGULATORMODE0, REGULATORSETTING0,  		mc13892_vgen1), -	MC13892_DEFINE_REGU(VGEN2, REGULATORMODE0, REGULATORSETTING0,	\ +	MC13892_DEFINE_REGU(VGEN2, REGULATORMODE0, REGULATORSETTING0,  		mc13892_vgen2), -	MC13892_DEFINE_REGU(VGEN3, REGULATORMODE1, REGULATORSETTING0,	\ +	MC13892_DEFINE_REGU(VGEN3, REGULATORMODE1, REGULATORSETTING0,  		mc13892_vgen3),  	MC13892_FIXED_DEFINE(VUSB, USB1, mc13892_vusb),  	MC13892_GPO_DEFINE(GPO1, POWERMISC, mc13892_gpo), @@ -476,8 +476,8 @@ static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev,  	}  	mc13xxx_lock(priv->mc13xxx); -	ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg, mask, -			      reg_value); +	ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg, +			      mask, reg_value);  	mc13xxx_unlock(priv->mc13xxx);  	return ret; @@ -611,43 +611,27 @@ static int mc13892_regulator_probe(struct platform_device *pdev)  		config.driver_data = priv;  		config.of_node = node; -		priv->regulators[i] = regulator_register(desc, &config); +		priv->regulators[i] = devm_regulator_register(&pdev->dev, desc, +							      &config);  		if (IS_ERR(priv->regulators[i])) {  			dev_err(&pdev->dev, "failed to register regulator %s\n",  				mc13892_regulators[i].desc.name); -			ret = PTR_ERR(priv->regulators[i]); -			goto err; +			return PTR_ERR(priv->regulators[i]);  		}  	}  	return 0; -err: -	while (--i >= 0) -		regulator_unregister(priv->regulators[i]); -	return ret;  err_unlock:  	mc13xxx_unlock(mc13892);  	return ret;  } -static int mc13892_regulator_remove(struct platform_device *pdev) -{ -	struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); -	int i; - -	for (i = 0; i < priv->num_regulators; i++) -		regulator_unregister(priv->regulators[i]); - -	return 0; -} -  static struct platform_driver mc13892_regulator_driver = {  	.driver	= {  		.name	= "mc13892-regulator",  		.owner	= THIS_MODULE,  	}, -	.remove	= mc13892_regulator_remove,  	.probe	= mc13892_regulator_probe,  }; diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index da485928230..05b971726ff 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -167,8 +167,10 @@ int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)  	struct device_node *parent;  	int num; -	of_node_get(pdev->dev.parent->of_node); -	parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); +	if (!pdev->dev.parent->of_node) +		return -ENODEV; + +	parent = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");  	if (!parent)  		return -ENODEV; @@ -187,8 +189,10 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(  	struct device_node *parent, *child;  	int i, parsed = 0; -	of_node_get(pdev->dev.parent->of_node); -	parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); +	if (!pdev->dev.parent->of_node) +		return NULL; + +	parent = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");  	if (!parent)  		return NULL; diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 7827384680d..ee5e67bc8d5 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -19,10 +19,10 @@  static void of_get_regulation_constraints(struct device_node *np,  					struct regulator_init_data **init_data)  { -	const __be32 *min_uV, *max_uV, *uV_offset; -	const __be32 *min_uA, *max_uA, *ramp_delay; -	struct property *prop; +	const __be32 *min_uV, *max_uV;  	struct regulation_constraints *constraints = &(*init_data)->constraints; +	int ret; +	u32 pval;  	constraints->name = of_get_property(np, "regulator-name", NULL); @@ -40,39 +40,36 @@ static void of_get_regulation_constraints(struct device_node *np,  	if (min_uV && max_uV && constraints->min_uV == constraints->max_uV)  		constraints->apply_uV = true; -	uV_offset = of_get_property(np, "regulator-microvolt-offset", NULL); -	if (uV_offset) -		constraints->uV_offset = be32_to_cpu(*uV_offset); -	min_uA = of_get_property(np, "regulator-min-microamp", NULL); -	if (min_uA) -		constraints->min_uA = be32_to_cpu(*min_uA); -	max_uA = of_get_property(np, "regulator-max-microamp", NULL); -	if (max_uA) -		constraints->max_uA = be32_to_cpu(*max_uA); +	if (!of_property_read_u32(np, "regulator-microvolt-offset", &pval)) +		constraints->uV_offset = pval; +	if (!of_property_read_u32(np, "regulator-min-microamp", &pval)) +		constraints->min_uA = pval; +	if (!of_property_read_u32(np, "regulator-max-microamp", &pval)) +		constraints->max_uA = pval;  	/* Current change possible? */  	if (constraints->min_uA != constraints->max_uA)  		constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT; -	if (of_find_property(np, "regulator-boot-on", NULL)) -		constraints->boot_on = true; - -	if (of_find_property(np, "regulator-always-on", NULL)) -		constraints->always_on = true; -	else /* status change should be possible if not always on. */ +	constraints->boot_on = of_property_read_bool(np, "regulator-boot-on"); +	constraints->always_on = of_property_read_bool(np, "regulator-always-on"); +	if (!constraints->always_on) /* status change should be possible. */  		constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;  	if (of_property_read_bool(np, "regulator-allow-bypass"))  		constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS; -	prop = of_find_property(np, "regulator-ramp-delay", NULL); -	if (prop && prop->value) { -		ramp_delay = prop->value; -		if (*ramp_delay) -			constraints->ramp_delay = be32_to_cpu(*ramp_delay); +	ret = of_property_read_u32(np, "regulator-ramp-delay", &pval); +	if (!ret) { +		if (pval) +			constraints->ramp_delay = pval;  		else  			constraints->ramp_disable = true;  	} + +	ret = of_property_read_u32(np, "regulator-enable-ramp-delay", &pval); +	if (!ret) +		constraints->enable_time = pval;  }  /** @@ -100,6 +97,20 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev,  }  EXPORT_SYMBOL_GPL(of_get_regulator_init_data); +struct devm_of_regulator_matches { +	struct of_regulator_match *matches; +	unsigned int num_matches; +}; + +static void devm_of_regulator_put_matches(struct device *dev, void *res) +{ +	struct devm_of_regulator_matches *devm_matches = res; +	int i; + +	for (i = 0; i < devm_matches->num_matches; i++) +		of_node_put(devm_matches->matches[i].of_node); +} +  /**   * of_regulator_match - extract multiple regulator init data from device tree.   * @dev: device requesting the data @@ -113,7 +124,8 @@ EXPORT_SYMBOL_GPL(of_get_regulator_init_data);   * regulator. The data parsed from a child node will be matched to a regulator   * based on either the deprecated property regulator-compatible if present,   * or otherwise the child node's name. Note that the match table is modified - * in place. + * in place and an additional of_node reference is taken for each matched + * regulator.   *   * Returns the number of matches found or a negative error code on failure.   */ @@ -125,10 +137,22 @@ int of_regulator_match(struct device *dev, struct device_node *node,  	unsigned int i;  	const char *name;  	struct device_node *child; +	struct devm_of_regulator_matches *devm_matches;  	if (!dev || !node)  		return -EINVAL; +	devm_matches = devres_alloc(devm_of_regulator_put_matches, +				    sizeof(struct devm_of_regulator_matches), +				    GFP_KERNEL); +	if (!devm_matches) +		return -ENOMEM; + +	devm_matches->matches = matches; +	devm_matches->num_matches = num_matches; + +	devres_add(dev, devm_matches); +  	for (i = 0; i < num_matches; i++) {  		struct of_regulator_match *match = &matches[i];  		match->init_data = NULL; @@ -156,7 +180,7 @@ int of_regulator_match(struct device *dev, struct device_node *node,  					child->name);  				return -EINVAL;  			} -			match->of_node = child; +			match->of_node = of_node_get(child);  			count++;  			break;  		} diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 488dfe7ce9a..93b4ad84290 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -33,6 +33,21 @@ struct regs_info {  	u8	vsel_addr;  	u8	ctrl_addr;  	u8	tstep_addr; +	int	sleep_id; +}; + +static const struct regulator_linear_range smps_low_ranges[] = { +	REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0), +	REGULATOR_LINEAR_RANGE(500000, 0x1, 0x6, 0), +	REGULATOR_LINEAR_RANGE(510000, 0x7, 0x79, 10000), +	REGULATOR_LINEAR_RANGE(1650000, 0x7A, 0x7f, 0), +}; + +static const struct regulator_linear_range smps_high_ranges[] = { +	REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0), +	REGULATOR_LINEAR_RANGE(1000000, 0x1, 0x6, 0), +	REGULATOR_LINEAR_RANGE(1020000, 0x7, 0x79, 20000), +	REGULATOR_LINEAR_RANGE(3300000, 0x7A, 0x7f, 0),  };  static const struct regs_info palmas_regs_info[] = { @@ -42,6 +57,7 @@ static const struct regs_info palmas_regs_info[] = {  		.vsel_addr	= PALMAS_SMPS12_VOLTAGE,  		.ctrl_addr	= PALMAS_SMPS12_CTRL,  		.tstep_addr	= PALMAS_SMPS12_TSTEP, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_SMPS12,  	},  	{  		.name		= "SMPS123", @@ -49,12 +65,14 @@ static const struct regs_info palmas_regs_info[] = {  		.vsel_addr	= PALMAS_SMPS12_VOLTAGE,  		.ctrl_addr	= PALMAS_SMPS12_CTRL,  		.tstep_addr	= PALMAS_SMPS12_TSTEP, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_SMPS12,  	},  	{  		.name		= "SMPS3",  		.sname		= "smps3-in",  		.vsel_addr	= PALMAS_SMPS3_VOLTAGE,  		.ctrl_addr	= PALMAS_SMPS3_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_SMPS3,  	},  	{  		.name		= "SMPS45", @@ -62,6 +80,7 @@ static const struct regs_info palmas_regs_info[] = {  		.vsel_addr	= PALMAS_SMPS45_VOLTAGE,  		.ctrl_addr	= PALMAS_SMPS45_CTRL,  		.tstep_addr	= PALMAS_SMPS45_TSTEP, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_SMPS45,  	},  	{  		.name		= "SMPS457", @@ -69,6 +88,7 @@ static const struct regs_info palmas_regs_info[] = {  		.vsel_addr	= PALMAS_SMPS45_VOLTAGE,  		.ctrl_addr	= PALMAS_SMPS45_CTRL,  		.tstep_addr	= PALMAS_SMPS45_TSTEP, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_SMPS45,  	},  	{  		.name		= "SMPS6", @@ -76,12 +96,14 @@ static const struct regs_info palmas_regs_info[] = {  		.vsel_addr	= PALMAS_SMPS6_VOLTAGE,  		.ctrl_addr	= PALMAS_SMPS6_CTRL,  		.tstep_addr	= PALMAS_SMPS6_TSTEP, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_SMPS6,  	},  	{  		.name		= "SMPS7",  		.sname		= "smps7-in",  		.vsel_addr	= PALMAS_SMPS7_VOLTAGE,  		.ctrl_addr	= PALMAS_SMPS7_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_SMPS7,  	},  	{  		.name		= "SMPS8", @@ -89,108 +111,128 @@ static const struct regs_info palmas_regs_info[] = {  		.vsel_addr	= PALMAS_SMPS8_VOLTAGE,  		.ctrl_addr	= PALMAS_SMPS8_CTRL,  		.tstep_addr	= PALMAS_SMPS8_TSTEP, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_SMPS8,  	},  	{  		.name		= "SMPS9",  		.sname		= "smps9-in",  		.vsel_addr	= PALMAS_SMPS9_VOLTAGE,  		.ctrl_addr	= PALMAS_SMPS9_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_SMPS9,  	},  	{  		.name		= "SMPS10_OUT2",  		.sname		= "smps10-in",  		.ctrl_addr	= PALMAS_SMPS10_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_SMPS10,  	},  	{  		.name		= "SMPS10_OUT1",  		.sname		= "smps10-out2",  		.ctrl_addr	= PALMAS_SMPS10_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_SMPS10,  	},  	{  		.name		= "LDO1",  		.sname		= "ldo1-in",  		.vsel_addr	= PALMAS_LDO1_VOLTAGE,  		.ctrl_addr	= PALMAS_LDO1_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_LDO1,  	},  	{  		.name		= "LDO2",  		.sname		= "ldo2-in",  		.vsel_addr	= PALMAS_LDO2_VOLTAGE,  		.ctrl_addr	= PALMAS_LDO2_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_LDO2,  	},  	{  		.name		= "LDO3",  		.sname		= "ldo3-in",  		.vsel_addr	= PALMAS_LDO3_VOLTAGE,  		.ctrl_addr	= PALMAS_LDO3_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_LDO3,  	},  	{  		.name		= "LDO4",  		.sname		= "ldo4-in",  		.vsel_addr	= PALMAS_LDO4_VOLTAGE,  		.ctrl_addr	= PALMAS_LDO4_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_LDO4,  	},  	{  		.name		= "LDO5",  		.sname		= "ldo5-in",  		.vsel_addr	= PALMAS_LDO5_VOLTAGE,  		.ctrl_addr	= PALMAS_LDO5_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_LDO5,  	},  	{  		.name		= "LDO6",  		.sname		= "ldo6-in",  		.vsel_addr	= PALMAS_LDO6_VOLTAGE,  		.ctrl_addr	= PALMAS_LDO6_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_LDO6,  	},  	{  		.name		= "LDO7",  		.sname		= "ldo7-in",  		.vsel_addr	= PALMAS_LDO7_VOLTAGE,  		.ctrl_addr	= PALMAS_LDO7_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_LDO7,  	},  	{  		.name		= "LDO8",  		.sname		= "ldo8-in",  		.vsel_addr	= PALMAS_LDO8_VOLTAGE,  		.ctrl_addr	= PALMAS_LDO8_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_LDO8,  	},  	{  		.name		= "LDO9",  		.sname		= "ldo9-in",  		.vsel_addr	= PALMAS_LDO9_VOLTAGE,  		.ctrl_addr	= PALMAS_LDO9_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_LDO9,  	},  	{  		.name		= "LDOLN",  		.sname		= "ldoln-in",  		.vsel_addr	= PALMAS_LDOLN_VOLTAGE,  		.ctrl_addr	= PALMAS_LDOLN_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_LDOLN,  	},  	{  		.name		= "LDOUSB",  		.sname		= "ldousb-in",  		.vsel_addr	= PALMAS_LDOUSB_VOLTAGE,  		.ctrl_addr	= PALMAS_LDOUSB_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_LDOUSB,  	},  	{  		.name		= "REGEN1",  		.ctrl_addr	= PALMAS_REGEN1_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_REGEN1,  	},  	{  		.name		= "REGEN2",  		.ctrl_addr	= PALMAS_REGEN2_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_REGEN2,  	},  	{  		.name		= "REGEN3",  		.ctrl_addr	= PALMAS_REGEN3_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_REGEN3,  	},  	{  		.name		= "SYSEN1",  		.ctrl_addr	= PALMAS_SYSEN1_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_SYSEN1,  	},  	{  		.name		= "SYSEN2",  		.ctrl_addr	= PALMAS_SYSEN2_CTRL, +		.sleep_id	= PALMAS_EXTERNAL_REQSTR_ID_SYSEN2,  	},  }; @@ -201,13 +243,7 @@ static unsigned int palmas_smps_ramp_delay[4] = {0, 10000, 5000, 2500};  #define SMPS_CTRL_MODE_ECO		0x02  #define SMPS_CTRL_MODE_PWM		0x03 -/* These values are derived from the data sheet. And are the number of steps - * where there is a voltage change, the ranges at beginning and end of register - * max/min values where there are no change are ommitted. - * - * So they are basically (maxV-minV)/stepV - */ -#define PALMAS_SMPS_NUM_VOLTAGES	117 +#define PALMAS_SMPS_NUM_VOLTAGES	122  #define PALMAS_SMPS10_NUM_VOLTAGES	2  #define PALMAS_LDO_NUM_VOLTAGES		50 @@ -258,54 +294,6 @@ static int palmas_ldo_write(struct palmas *palmas, unsigned int reg,  	return regmap_write(palmas->regmap[REGULATOR_SLAVE], addr, value);  } -static int palmas_is_enabled_smps(struct regulator_dev *dev) -{ -	struct palmas_pmic *pmic = rdev_get_drvdata(dev); -	int id = rdev_get_id(dev); -	unsigned int reg; - -	palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); - -	reg &= PALMAS_SMPS12_CTRL_STATUS_MASK; -	reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT; - -	return !!(reg); -} - -static int palmas_enable_smps(struct regulator_dev *dev) -{ -	struct palmas_pmic *pmic = rdev_get_drvdata(dev); -	int id = rdev_get_id(dev); -	unsigned int reg; - -	palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); - -	reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; -	if (pmic->current_reg_mode[id]) -		reg |= pmic->current_reg_mode[id]; -	else -		reg |= SMPS_CTRL_MODE_ON; - -	palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg); - -	return 0; -} - -static int palmas_disable_smps(struct regulator_dev *dev) -{ -	struct palmas_pmic *pmic = rdev_get_drvdata(dev); -	int id = rdev_get_id(dev); -	unsigned int reg; - -	palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®); - -	reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; - -	palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg); - -	return 0; -} -  static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode)  {  	struct palmas_pmic *pmic = rdev_get_drvdata(dev); @@ -337,6 +325,10 @@ static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode)  	if (rail_enable)  		palmas_smps_write(pmic->palmas,  			palmas_regs_info[id].ctrl_addr, reg); + +	/* Switch the enable value to ensure this is used for enable */ +	pmic->desc[id].enable_val = pmic->current_reg_mode[id]; +  	return 0;  } @@ -360,81 +352,6 @@ static unsigned int palmas_get_mode_smps(struct regulator_dev *dev)  	return 0;  } -static int palmas_list_voltage_smps(struct regulator_dev *dev, -					unsigned selector) -{ -	struct palmas_pmic *pmic = rdev_get_drvdata(dev); -	int id = rdev_get_id(dev); -	int mult = 1; - -	/* Read the multiplier set in VSEL register to return -	 * the correct voltage. -	 */ -	if (pmic->range[id]) -		mult = 2; - -	if (selector == 0) -		return 0; -	else if (selector < 6) -		return 500000 * mult; -	else -		/* Voltage is linear mapping starting from selector 6, -		 * volt = (0.49V + ((selector - 5) * 0.01V)) * RANGE -		 * RANGE is either x1 or x2 -		 */ -		return (490000 + ((selector - 5) * 10000)) * mult; -} - -static int palmas_map_voltage_smps(struct regulator_dev *rdev, -		int min_uV, int max_uV) -{ -	struct palmas_pmic *pmic = rdev_get_drvdata(rdev); -	int id = rdev_get_id(rdev); -	int ret, voltage; - -	if (min_uV == 0) -		return 0; - -	if (pmic->range[id]) { /* RANGE is x2 */ -		if (min_uV < 1000000) -			min_uV = 1000000; -		ret = DIV_ROUND_UP(min_uV - 1000000, 20000) + 6; -	} else {		/* RANGE is x1 */ -		if (min_uV < 500000) -			min_uV = 500000; -		ret = DIV_ROUND_UP(min_uV - 500000, 10000) + 6; -	} - -	/* Map back into a voltage to verify we're still in bounds */ -	voltage = palmas_list_voltage_smps(rdev, ret); -	if (voltage < min_uV || voltage > max_uV) -		return -EINVAL; - -	return ret; -} - -static int palma_smps_set_voltage_smps_time_sel(struct regulator_dev *rdev, -	unsigned int old_selector, unsigned int new_selector) -{ -	struct palmas_pmic *pmic = rdev_get_drvdata(rdev); -	int id = rdev_get_id(rdev); -	int old_uv, new_uv; -	unsigned int ramp_delay = pmic->ramp_delay[id]; - -	if (!ramp_delay) -		return 0; - -	old_uv = palmas_list_voltage_smps(rdev, old_selector); -	if (old_uv < 0) -		return old_uv; - -	new_uv = palmas_list_voltage_smps(rdev, new_selector); -	if (new_uv < 0) -		return new_uv; - -	return DIV_ROUND_UP(abs(old_uv - new_uv), ramp_delay); -} -  static int palmas_smps_set_ramp_delay(struct regulator_dev *rdev,  		 int ramp_delay)  { @@ -471,16 +388,27 @@ static int palmas_smps_set_ramp_delay(struct regulator_dev *rdev,  }  static struct regulator_ops palmas_ops_smps = { -	.is_enabled		= palmas_is_enabled_smps, -	.enable			= palmas_enable_smps, -	.disable		= palmas_disable_smps, +	.is_enabled		= regulator_is_enabled_regmap, +	.enable			= regulator_enable_regmap, +	.disable		= regulator_disable_regmap, +	.set_mode		= palmas_set_mode_smps, +	.get_mode		= palmas_get_mode_smps, +	.get_voltage_sel	= regulator_get_voltage_sel_regmap, +	.set_voltage_sel	= regulator_set_voltage_sel_regmap, +	.list_voltage		= regulator_list_voltage_linear_range, +	.map_voltage		= regulator_map_voltage_linear_range, +	.set_voltage_time_sel	= regulator_set_voltage_time_sel, +	.set_ramp_delay		= palmas_smps_set_ramp_delay, +}; + +static struct regulator_ops palmas_ops_ext_control_smps = {  	.set_mode		= palmas_set_mode_smps,  	.get_mode		= palmas_get_mode_smps,  	.get_voltage_sel	= regulator_get_voltage_sel_regmap,  	.set_voltage_sel	= regulator_set_voltage_sel_regmap, -	.list_voltage		= palmas_list_voltage_smps, -	.map_voltage		= palmas_map_voltage_smps, -	.set_voltage_time_sel	= palma_smps_set_voltage_smps_time_sel, +	.list_voltage		= regulator_list_voltage_linear_range, +	.map_voltage		= regulator_map_voltage_linear_range, +	.set_voltage_time_sel	= regulator_set_voltage_time_sel,  	.set_ramp_delay		= palmas_smps_set_ramp_delay,  }; @@ -519,12 +447,37 @@ static struct regulator_ops palmas_ops_ldo = {  	.map_voltage		= regulator_map_voltage_linear,  }; +static struct regulator_ops palmas_ops_ext_control_ldo = { +	.get_voltage_sel	= regulator_get_voltage_sel_regmap, +	.set_voltage_sel	= regulator_set_voltage_sel_regmap, +	.list_voltage		= regulator_list_voltage_linear, +	.map_voltage		= regulator_map_voltage_linear, +}; +  static struct regulator_ops palmas_ops_extreg = {  	.is_enabled		= regulator_is_enabled_regmap,  	.enable			= regulator_enable_regmap,  	.disable		= regulator_disable_regmap,  }; +static struct regulator_ops palmas_ops_ext_control_extreg = { +}; + +static int palmas_regulator_config_external(struct palmas *palmas, int id, +		struct palmas_reg_init *reg_init) +{ +	int sleep_id = palmas_regs_info[id].sleep_id; +	int ret; + +	ret = palmas_ext_control_req_config(palmas, sleep_id, +					reg_init->roof_floor, true); +	if (ret < 0) +		dev_err(palmas->dev, +			"Ext control config for regulator %d failed %d\n", +			id, ret); +	return ret; +} +  /*   * setup the hardware based sleep configuration of the SMPS/LDO regulators   * from the platform data. This is different to the software based control @@ -583,7 +536,22 @@ static int palmas_smps_init(struct palmas *palmas, int id,  			return ret;  	} +	if (reg_init->roof_floor && (id != PALMAS_REG_SMPS10_OUT1) && +			(id != PALMAS_REG_SMPS10_OUT2)) { +		/* Enable externally controlled regulator */ +		addr = palmas_regs_info[id].ctrl_addr; +		ret = palmas_smps_read(palmas, addr, ®); +		if (ret < 0) +			return ret; +		if (!(reg & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK)) { +			reg |= SMPS_CTRL_MODE_ON; +			ret = palmas_smps_write(palmas, addr, reg); +			if (ret < 0) +				return ret; +		} +		return palmas_regulator_config_external(palmas, id, reg_init); +	}  	return 0;  } @@ -614,6 +582,20 @@ static int palmas_ldo_init(struct palmas *palmas, int id,  	if (ret)  		return ret; +	if (reg_init->roof_floor) { +		/* Enable externally controlled regulator */ +		addr = palmas_regs_info[id].ctrl_addr; +		ret = palmas_update_bits(palmas, PALMAS_LDO_BASE, +				addr, PALMAS_LDO1_CTRL_MODE_ACTIVE, +				PALMAS_LDO1_CTRL_MODE_ACTIVE); +		if (ret < 0) { +			dev_err(palmas->dev, +				"LDO Register 0x%02x update failed %d\n", +				addr, ret); +			return ret; +		} +		return palmas_regulator_config_external(palmas, id, reg_init); +	}  	return 0;  } @@ -636,6 +618,21 @@ static int palmas_extreg_init(struct palmas *palmas, int id,  			addr, ret);  		return ret;  	} + +	if (reg_init->roof_floor) { +		/* Enable externally controlled regulator */ +		addr = palmas_regs_info[id].ctrl_addr; +		ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE, +				addr, PALMAS_REGEN1_CTRL_MODE_ACTIVE, +				PALMAS_REGEN1_CTRL_MODE_ACTIVE); +		if (ret < 0) { +			dev_err(palmas->dev, +				"Resource Register 0x%02x update failed %d\n", +				addr, ret); +			return ret; +		} +		return palmas_regulator_config_external(palmas, id, reg_init); +	}  	return 0;  } @@ -718,7 +715,7 @@ static void palmas_dt_to_pdata(struct device *dev,  	int idx, ret;  	node = of_node_get(node); -	regulators = of_find_node_by_name(node, "regulators"); +	regulators = of_get_child_by_name(node, "regulators");  	if (!regulators) {  		dev_info(dev, "regulator node not found\n");  		return; @@ -746,9 +743,35 @@ static void palmas_dt_to_pdata(struct device *dev,  			of_property_read_bool(palmas_matches[idx].of_node,  					     "ti,warm-reset"); -		pdata->reg_init[idx]->roof_floor = -			of_property_read_bool(palmas_matches[idx].of_node, -					      "ti,roof-floor"); +		ret = of_property_read_u32(palmas_matches[idx].of_node, +					      "ti,roof-floor", &prop); +		/* EINVAL: Property not found */ +		if (ret != -EINVAL) { +			int econtrol; + +			/* use default value, when no value is specified */ +			econtrol = PALMAS_EXT_CONTROL_NSLEEP; +			if (!ret) { +				switch (prop) { +				case 1: +					econtrol = PALMAS_EXT_CONTROL_ENABLE1; +					break; +				case 2: +					econtrol = PALMAS_EXT_CONTROL_ENABLE2; +					break; +				case 3: +					econtrol = PALMAS_EXT_CONTROL_NSLEEP; +					break; +				default: +					WARN_ON(1); +					dev_warn(dev, +					"%s: Invalid roof-floor option: %u\n", +					     palmas_matches[idx].name, prop); +					break; +				} +			} +			pdata->reg_init[idx]->roof_floor = econtrol; +		}  		ret = of_property_read_u32(palmas_matches[idx].of_node,  				"ti,mode-sleep", &prop); @@ -862,7 +885,7 @@ static int palmas_regulators_probe(struct platform_device *pdev)  			if (ret < 0) {  				dev_err(&pdev->dev,  					"reading TSTEP reg failed: %d\n", ret); -				goto err_unregister_regulator; +				return ret;  			}  			pmic->desc[id].ramp_delay =  					palmas_smps_ramp_delay[reg & 0x3]; @@ -874,7 +897,9 @@ static int palmas_regulators_probe(struct platform_device *pdev)  			reg_init = pdata->reg_init[id];  			ret = palmas_smps_init(palmas, id, reg_init);  			if (ret) -				goto err_unregister_regulator; +				return ret; +		} else { +			reg_init = NULL;  		}  		/* Register the regulators */ @@ -912,14 +937,23 @@ static int palmas_regulators_probe(struct platform_device *pdev)  			 * ranges. Read the current smps mode for later use.  			 */  			addr = palmas_regs_info[id].vsel_addr; +			pmic->desc[id].n_linear_ranges = 3;  			ret = palmas_smps_read(pmic->palmas, addr, ®);  			if (ret) -				goto err_unregister_regulator; +				return ret;  			if (reg & PALMAS_SMPS12_VOLTAGE_RANGE)  				pmic->range[id] = 1; +			if (pmic->range[id]) +				pmic->desc[id].linear_ranges = smps_high_ranges; +			else +				pmic->desc[id].linear_ranges = smps_low_ranges; -			pmic->desc[id].ops = &palmas_ops_smps; +			if (reg_init && reg_init->roof_floor) +				pmic->desc[id].ops = +						&palmas_ops_ext_control_smps; +			else +				pmic->desc[id].ops = &palmas_ops_smps;  			pmic->desc[id].n_voltages = PALMAS_SMPS_NUM_VOLTAGES;  			pmic->desc[id].vsel_reg =  					PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, @@ -931,9 +965,17 @@ static int palmas_regulators_probe(struct platform_device *pdev)  			addr = palmas_regs_info[id].ctrl_addr;  			ret = palmas_smps_read(pmic->palmas, addr, ®);  			if (ret) -				goto err_unregister_regulator; +				return ret;  			pmic->current_reg_mode[id] = reg &  					PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; + +			pmic->desc[id].enable_reg = +					PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, +						palmas_regs_info[id].ctrl_addr); +			pmic->desc[id].enable_mask = +					PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; +			/* set_mode overrides this value */ +			pmic->desc[id].enable_val = SMPS_CTRL_MODE_ON;  		}  		pmic->desc[id].type = REGULATOR_VOLTAGE; @@ -947,13 +989,13 @@ static int palmas_regulators_probe(struct platform_device *pdev)  		pmic->desc[id].supply_name = palmas_regs_info[id].sname;  		config.of_node = palmas_matches[id].of_node; -		rdev = regulator_register(&pmic->desc[id], &config); +		rdev = devm_regulator_register(&pdev->dev, &pmic->desc[id], +					       &config);  		if (IS_ERR(rdev)) {  			dev_err(&pdev->dev,  				"failed to register %s regulator\n",  				pdev->name); -			ret = PTR_ERR(rdev); -			goto err_unregister_regulator; +			return PTR_ERR(rdev);  		}  		/* Save regulator for cleanup */ @@ -962,6 +1004,10 @@ static int palmas_regulators_probe(struct platform_device *pdev)  	/* Start this loop from the id left from previous loop */  	for (; id < PALMAS_NUM_REGS; id++) { +		if (pdata && pdata->reg_init[id]) +			reg_init = pdata->reg_init[id]; +		else +			reg_init = NULL;  		/* Miss out regulators which are not available due  		 * to alternate functions. @@ -975,10 +1021,15 @@ static int palmas_regulators_probe(struct platform_device *pdev)  		if (id < PALMAS_REG_REGEN1) {  			pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES; -			pmic->desc[id].ops = &palmas_ops_ldo; +			if (reg_init && reg_init->roof_floor) +				pmic->desc[id].ops = +					&palmas_ops_ext_control_ldo; +			else +				pmic->desc[id].ops = &palmas_ops_ldo;  			pmic->desc[id].min_uV = 900000;  			pmic->desc[id].uV_step = 50000;  			pmic->desc[id].linear_min_sel = 1; +			pmic->desc[id].enable_time = 500;  			pmic->desc[id].vsel_reg =  					PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,  						palmas_regs_info[id].vsel_addr); @@ -997,9 +1048,18 @@ static int palmas_regulators_probe(struct platform_device *pdev)  				pmic->desc[id].min_uV = 450000;  				pmic->desc[id].uV_step = 25000;  			} + +			/* LOD6 in vibrator mode will have enable time 2000us */ +			if (pdata && pdata->ldo6_vibrator && +				(id == PALMAS_REG_LDO6)) +				pmic->desc[id].enable_time = 2000;  		} else {  			pmic->desc[id].n_voltages = 1; -			pmic->desc[id].ops = &palmas_ops_extreg; +			if (reg_init && reg_init->roof_floor) +				pmic->desc[id].ops = +					&palmas_ops_ext_control_extreg; +			else +				pmic->desc[id].ops = &palmas_ops_extreg;  			pmic->desc[id].enable_reg =  					PALMAS_BASE_TO_REG(PALMAS_RESOURCE_BASE,  						palmas_regs_info[id].ctrl_addr); @@ -1015,13 +1075,13 @@ static int palmas_regulators_probe(struct platform_device *pdev)  		pmic->desc[id].supply_name = palmas_regs_info[id].sname;  		config.of_node = palmas_matches[id].of_node; -		rdev = regulator_register(&pmic->desc[id], &config); +		rdev = devm_regulator_register(&pdev->dev, &pmic->desc[id], +					       &config);  		if (IS_ERR(rdev)) {  			dev_err(&pdev->dev,  				"failed to register %s regulator\n",  				pdev->name); -			ret = PTR_ERR(rdev); -			goto err_unregister_regulator; +			return PTR_ERR(rdev);  		}  		/* Save regulator for cleanup */ @@ -1037,34 +1097,17 @@ static int palmas_regulators_probe(struct platform_device *pdev)  				else  					ret = palmas_extreg_init(palmas,  							id, reg_init); -				if (ret) { -					regulator_unregister(pmic->rdev[id]); -					goto err_unregister_regulator; -				} +				if (ret) +					return ret;  			}  		}  	}  	return 0; - -err_unregister_regulator: -	while (--id >= 0) -		regulator_unregister(pmic->rdev[id]); -	return ret; -} - -static int palmas_regulators_remove(struct platform_device *pdev) -{ -	struct palmas_pmic *pmic = platform_get_drvdata(pdev); -	int id; - -	for (id = 0; id < PALMAS_NUM_REGS; id++) -		regulator_unregister(pmic->rdev[id]); -	return 0;  } -static struct of_device_id of_palmas_match_tbl[] = { +static const struct of_device_id of_palmas_match_tbl[] = {  	{ .compatible = "ti,palmas-pmic", },  	{ .compatible = "ti,twl6035-pmic", },  	{ .compatible = "ti,twl6036-pmic", }, @@ -1083,7 +1126,6 @@ static struct platform_driver palmas_driver = {  		.owner = THIS_MODULE,  	},  	.probe = palmas_regulators_probe, -	.remove = palmas_regulators_remove,  };  static int __init palmas_init(void) diff --git a/drivers/regulator/pbias-regulator.c b/drivers/regulator/pbias-regulator.c new file mode 100644 index 00000000000..6d02d68dfb4 --- /dev/null +++ b/drivers/regulator/pbias-regulator.c @@ -0,0 +1,198 @@ +/* + * pbias-regulator.c + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * Author: Balaji T K <balajitk@ti.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/mfd/syscon.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_device.h> + +struct pbias_reg_info { +	u32 enable; +	u32 enable_mask; +	u32 vmode; +	unsigned int enable_time; +	char *name; +}; + +struct pbias_regulator_data { +	struct regulator_desc desc; +	void __iomem *pbias_addr; +	struct regulator_dev *dev; +	struct regmap *syscon; +	const struct pbias_reg_info *info; +	int voltage; +}; + +static const unsigned int pbias_volt_table[] = { +	1800000, +	3000000 +}; + +static struct regulator_ops pbias_regulator_voltage_ops = { +	.list_voltage = regulator_list_voltage_table, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +	.enable = regulator_enable_regmap, +	.disable = regulator_disable_regmap, +	.is_enabled = regulator_is_enabled_regmap, +}; + +static const struct pbias_reg_info pbias_mmc_omap2430 = { +	.enable = BIT(1), +	.enable_mask = BIT(1), +	.vmode = BIT(0), +	.enable_time = 100, +	.name = "pbias_mmc_omap2430" +}; + +static const struct pbias_reg_info pbias_sim_omap3 = { +	.enable = BIT(9), +	.enable_mask = BIT(9), +	.vmode = BIT(8), +	.enable_time = 100, +	.name = "pbias_sim_omap3" +}; + +static const struct pbias_reg_info pbias_mmc_omap4 = { +	.enable = BIT(26) | BIT(22), +	.enable_mask = BIT(26) | BIT(25) | BIT(22), +	.vmode = BIT(21), +	.enable_time = 100, +	.name = "pbias_mmc_omap4" +}; + +static const struct pbias_reg_info pbias_mmc_omap5 = { +	.enable = BIT(27) | BIT(26), +	.enable_mask = BIT(27) | BIT(25) | BIT(26), +	.vmode = BIT(21), +	.enable_time = 100, +	.name = "pbias_mmc_omap5" +}; + +static struct of_regulator_match pbias_matches[] = { +	{ .name = "pbias_mmc_omap2430", .driver_data = (void *)&pbias_mmc_omap2430}, +	{ .name = "pbias_sim_omap3", .driver_data = (void *)&pbias_sim_omap3}, +	{ .name = "pbias_mmc_omap4", .driver_data = (void *)&pbias_mmc_omap4}, +	{ .name = "pbias_mmc_omap5", .driver_data = (void *)&pbias_mmc_omap5}, +}; +#define PBIAS_NUM_REGS	ARRAY_SIZE(pbias_matches) + +static const struct of_device_id pbias_of_match[] = { +	{ .compatible = "ti,pbias-omap", }, +	{}, +}; +MODULE_DEVICE_TABLE(of, pbias_of_match); + +static int pbias_regulator_probe(struct platform_device *pdev) +{ +	struct device_node *np = pdev->dev.of_node; +	struct pbias_regulator_data *drvdata; +	struct resource *res; +	struct regulator_config cfg = { }; +	struct regmap *syscon; +	const struct pbias_reg_info *info; +	int ret = 0; +	int count, idx, data_idx = 0; + +	count = of_regulator_match(&pdev->dev, np, pbias_matches, +						PBIAS_NUM_REGS); +	if (count < 0) +		return count; + +	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct pbias_regulator_data) +			       * count, GFP_KERNEL); +	if (!drvdata) +		return -ENOMEM; + +	syscon = syscon_regmap_lookup_by_phandle(np, "syscon"); +	if (IS_ERR(syscon)) +		return PTR_ERR(syscon); + +	cfg.regmap = syscon; +	cfg.dev = &pdev->dev; + +	for (idx = 0; idx < PBIAS_NUM_REGS && data_idx < count; idx++) { +		if (!pbias_matches[idx].init_data || +			!pbias_matches[idx].of_node) +			continue; + +		info = pbias_matches[idx].driver_data; +		if (!info) +			return -ENODEV; + +		res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +		if (!res) +			return -EINVAL; + +		drvdata[data_idx].syscon = syscon; +		drvdata[data_idx].info = info; +		drvdata[data_idx].desc.name = info->name; +		drvdata[data_idx].desc.owner = THIS_MODULE; +		drvdata[data_idx].desc.type = REGULATOR_VOLTAGE; +		drvdata[data_idx].desc.ops = &pbias_regulator_voltage_ops; +		drvdata[data_idx].desc.volt_table = pbias_volt_table; +		drvdata[data_idx].desc.n_voltages = 2; +		drvdata[data_idx].desc.enable_time = info->enable_time; +		drvdata[data_idx].desc.vsel_reg = res->start; +		drvdata[data_idx].desc.vsel_mask = info->vmode; +		drvdata[data_idx].desc.enable_reg = res->start; +		drvdata[data_idx].desc.enable_mask = info->enable_mask; +		drvdata[data_idx].desc.enable_val = info->enable; + +		cfg.init_data = pbias_matches[idx].init_data; +		cfg.driver_data = &drvdata[data_idx]; +		cfg.of_node = pbias_matches[idx].of_node; + +		drvdata[data_idx].dev = devm_regulator_register(&pdev->dev, +					&drvdata[data_idx].desc, &cfg); +		if (IS_ERR(drvdata[data_idx].dev)) { +			ret = PTR_ERR(drvdata[data_idx].dev); +			dev_err(&pdev->dev, +				"Failed to register regulator: %d\n", ret); +			goto err_regulator; +		} +		data_idx++; +	} + +	platform_set_drvdata(pdev, drvdata); + +err_regulator: +	return ret; +} + +static struct platform_driver pbias_regulator_driver = { +	.probe		= pbias_regulator_probe, +	.driver		= { +		.name		= "pbias-regulator", +		.owner		= THIS_MODULE, +		.of_match_table = of_match_ptr(pbias_of_match), +	}, +}; + +module_platform_driver(pbias_regulator_driver); + +MODULE_AUTHOR("Balaji T K <balajitk@ti.com>"); +MODULE_DESCRIPTION("pbias voltage regulator"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pbias-regulator"); diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c index b49eaeedea8..3727b7d0e9a 100644 --- a/drivers/regulator/pcap-regulator.c +++ b/drivers/regulator/pcap-regulator.c @@ -246,7 +246,8 @@ static int pcap_regulator_probe(struct platform_device *pdev)  	config.init_data = dev_get_platdata(&pdev->dev);  	config.driver_data = pcap; -	rdev = regulator_register(&pcap_regulators[pdev->id], &config); +	rdev = devm_regulator_register(&pdev->dev, &pcap_regulators[pdev->id], +				       &config);  	if (IS_ERR(rdev))  		return PTR_ERR(rdev); @@ -255,22 +256,12 @@ static int pcap_regulator_probe(struct platform_device *pdev)  	return 0;  } -static int pcap_regulator_remove(struct platform_device *pdev) -{ -	struct regulator_dev *rdev = platform_get_drvdata(pdev); - -	regulator_unregister(rdev); - -	return 0; -} -  static struct platform_driver pcap_regulator_driver = {  	.driver = {  		.name	= "pcap-regulator",  		.owner	= THIS_MODULE,  	},  	.probe	= pcap_regulator_probe, -	.remove	= pcap_regulator_remove,  };  static int __init pcap_regulator_init(void) diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index 0f3576d48ab..134f90ec9ca 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -90,7 +90,8 @@ static int pcf50633_regulator_probe(struct platform_device *pdev)  	config.driver_data = pcf;  	config.regmap = pcf->regmap; -	rdev = regulator_register(®ulators[pdev->id], &config); +	rdev = devm_regulator_register(&pdev->dev, ®ulators[pdev->id], +				       &config);  	if (IS_ERR(rdev))  		return PTR_ERR(rdev); @@ -102,21 +103,11 @@ static int pcf50633_regulator_probe(struct platform_device *pdev)  	return 0;  } -static int pcf50633_regulator_remove(struct platform_device *pdev) -{ -	struct regulator_dev *rdev = platform_get_drvdata(pdev); - -	regulator_unregister(rdev); - -	return 0; -} -  static struct platform_driver pcf50633_regulator_driver = {  	.driver = { -		.name = "pcf50633-regltr", +		.name = "pcf50633-regulator",  	},  	.probe = pcf50633_regulator_probe, -	.remove = pcf50633_regulator_remove,  };  static int __init pcf50633_regulator_init(void) diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index ba67b2c4e2e..c879dff597e 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -38,7 +38,7 @@  #define PFUZE100_DEVICEID	0x0  #define PFUZE100_REVID		0x3 -#define PFUZE100_FABID		0x3 +#define PFUZE100_FABID		0x4  #define PFUZE100_SW1ABVOL	0x20  #define PFUZE100_SW1CVOL	0x2e @@ -56,6 +56,8 @@  #define PFUZE100_VGEN5VOL	0x70  #define PFUZE100_VGEN6VOL	0x71 +enum chips { PFUZE100, PFUZE200 }; +  struct pfuze_regulator {  	struct regulator_desc desc;  	unsigned char stby_reg; @@ -63,6 +65,7 @@ struct pfuze_regulator {  };  struct pfuze_chip { +	int	chip_id;  	struct regmap *regmap;  	struct device *dev;  	struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR]; @@ -78,21 +81,23 @@ static const int pfuze100_vsnvs[] = {  };  static const struct i2c_device_id pfuze_device_id[] = { -	{.name = "pfuze100"}, -	{}, +	{.name = "pfuze100", .driver_data = PFUZE100}, +	{.name = "pfuze200", .driver_data = PFUZE200}, +	{ }  };  MODULE_DEVICE_TABLE(i2c, pfuze_device_id);  static const struct of_device_id pfuze_dt_ids[] = { -	{ .compatible = "fsl,pfuze100" }, -	{}, +	{ .compatible = "fsl,pfuze100", .data = (void *)PFUZE100}, +	{ .compatible = "fsl,pfuze200", .data = (void *)PFUZE200}, +	{ }  };  MODULE_DEVICE_TABLE(of, pfuze_dt_ids);  static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)  {  	struct pfuze_chip *pfuze100 = rdev_get_drvdata(rdev); -	int id = rdev->desc->id; +	int id = rdev_get_id(rdev);  	unsigned int ramp_bits;  	int ret; @@ -120,6 +125,9 @@ static struct regulator_ops pfuze100_ldo_regulator_ops = {  };  static struct regulator_ops pfuze100_fixed_regulator_ops = { +	.enable = regulator_enable_regmap, +	.disable = regulator_disable_regmap, +	.is_enabled = regulator_is_enabled_regmap,  	.list_voltage = regulator_list_voltage_linear,  }; @@ -132,6 +140,8 @@ static struct regulator_ops pfuze100_sw_regulator_ops = {  };  static struct regulator_ops pfuze100_swb_regulator_ops = { +	.enable = regulator_enable_regmap, +	.disable = regulator_disable_regmap,  	.list_voltage = regulator_list_voltage_table,  	.map_voltage = regulator_map_voltage_ascend,  	.set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -139,14 +149,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {  }; -#define PFUZE100_FIXED_REG(_name, base, voltage)	\ -	[PFUZE100_ ## _name] = {	\ +#define PFUZE100_FIXED_REG(_chip, _name, base, voltage)	\ +	[_chip ## _ ## _name] = {	\  		.desc = {	\  			.name = #_name,	\  			.n_voltages = 1,	\  			.ops = &pfuze100_fixed_regulator_ops,	\  			.type = REGULATOR_VOLTAGE,	\ -			.id = PFUZE100_ ## _name,	\ +			.id = _chip ## _ ## _name,	\  			.owner = THIS_MODULE,	\  			.min_uV = (voltage),	\  			.enable_reg = (base),	\ @@ -154,14 +164,14 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {  		},	\  	} -#define PFUZE100_SW_REG(_name, base, min, max, step)	\ -	[PFUZE100_ ## _name] = {	\ +#define PFUZE100_SW_REG(_chip, _name, base, min, max, step)	\ +	[_chip ## _ ## _name] = {	\  		.desc = {	\  			.name = #_name,\  			.n_voltages = ((max) - (min)) / (step) + 1,	\  			.ops = &pfuze100_sw_regulator_ops,	\  			.type = REGULATOR_VOLTAGE,	\ -			.id = PFUZE100_ ## _name,	\ +			.id = _chip ## _ ## _name,	\  			.owner = THIS_MODULE,	\  			.min_uV = (min),	\  			.uV_step = (step),	\ @@ -172,29 +182,31 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {  		.stby_mask = 0x3f,	\  	} -#define PFUZE100_SWB_REG(_name, base, mask, voltages)	\ -	[PFUZE100_ ## _name] = {	\ +#define PFUZE100_SWB_REG(_chip, _name, base, mask, voltages)	\ +	[_chip ## _ ##  _name] = {	\  		.desc = {	\  			.name = #_name,	\  			.n_voltages = ARRAY_SIZE(voltages),	\  			.ops = &pfuze100_swb_regulator_ops,	\  			.type = REGULATOR_VOLTAGE,	\ -			.id = PFUZE100_ ## _name,	\ +			.id = _chip ## _ ## _name,	\  			.owner = THIS_MODULE,	\  			.volt_table = voltages,	\  			.vsel_reg = (base),	\  			.vsel_mask = (mask),	\ +			.enable_reg = (base),	\ +			.enable_mask = 0x48,	\  		},	\  	} -#define PFUZE100_VGEN_REG(_name, base, min, max, step)	\ -	[PFUZE100_ ## _name] = {	\ +#define PFUZE100_VGEN_REG(_chip, _name, base, min, max, step)	\ +	[_chip ## _ ## _name] = {	\  		.desc = {	\  			.name = #_name,	\  			.n_voltages = ((max) - (min)) / (step) + 1,	\  			.ops = &pfuze100_ldo_regulator_ops,	\  			.type = REGULATOR_VOLTAGE,	\ -			.id = PFUZE100_ ## _name,	\ +			.id = _chip ## _ ## _name,	\  			.owner = THIS_MODULE,	\  			.min_uV = (min),	\  			.uV_step = (step),	\ @@ -207,25 +219,45 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {  		.stby_mask = 0x20,	\  	} +/* PFUZE100 */  static struct pfuze_regulator pfuze100_regulators[] = { -	PFUZE100_SW_REG(SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), -	PFUZE100_SW_REG(SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000), -	PFUZE100_SW_REG(SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000), -	PFUZE100_SW_REG(SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000), -	PFUZE100_SW_REG(SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000), -	PFUZE100_SW_REG(SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000), -	PFUZE100_SWB_REG(SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst), -	PFUZE100_SWB_REG(VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), -	PFUZE100_FIXED_REG(VREFDDR, PFUZE100_VREFDDRCON, 750000), -	PFUZE100_VGEN_REG(VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000), -	PFUZE100_VGEN_REG(VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), -	PFUZE100_VGEN_REG(VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000), -	PFUZE100_VGEN_REG(VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000), -	PFUZE100_VGEN_REG(VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), -	PFUZE100_VGEN_REG(VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), +	PFUZE100_SW_REG(PFUZE100, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), +	PFUZE100_SW_REG(PFUZE100, SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000), +	PFUZE100_SW_REG(PFUZE100, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000), +	PFUZE100_SW_REG(PFUZE100, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000), +	PFUZE100_SW_REG(PFUZE100, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000), +	PFUZE100_SW_REG(PFUZE100, SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000), +	PFUZE100_SWB_REG(PFUZE100, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst), +	PFUZE100_SWB_REG(PFUZE100, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), +	PFUZE100_FIXED_REG(PFUZE100, VREFDDR, PFUZE100_VREFDDRCON, 750000), +	PFUZE100_VGEN_REG(PFUZE100, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000), +	PFUZE100_VGEN_REG(PFUZE100, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), +	PFUZE100_VGEN_REG(PFUZE100, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000), +	PFUZE100_VGEN_REG(PFUZE100, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000), +	PFUZE100_VGEN_REG(PFUZE100, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), +	PFUZE100_VGEN_REG(PFUZE100, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), +}; + +static struct pfuze_regulator pfuze200_regulators[] = { +	PFUZE100_SW_REG(PFUZE200, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000), +	PFUZE100_SW_REG(PFUZE200, SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000), +	PFUZE100_SW_REG(PFUZE200, SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000), +	PFUZE100_SW_REG(PFUZE200, SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000), +	PFUZE100_SWB_REG(PFUZE200, SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst), +	PFUZE100_SWB_REG(PFUZE200, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), +	PFUZE100_FIXED_REG(PFUZE200, VREFDDR, PFUZE100_VREFDDRCON, 750000), +	PFUZE100_VGEN_REG(PFUZE200, VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000), +	PFUZE100_VGEN_REG(PFUZE200, VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), +	PFUZE100_VGEN_REG(PFUZE200, VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000), +	PFUZE100_VGEN_REG(PFUZE200, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000), +	PFUZE100_VGEN_REG(PFUZE200, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), +	PFUZE100_VGEN_REG(PFUZE200, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),  }; +static struct pfuze_regulator *pfuze_regulators; +  #ifdef CONFIG_OF +/* PFUZE100 */  static struct of_regulator_match pfuze100_matches[] = {  	{ .name = "sw1ab",	},  	{ .name = "sw1c",	}, @@ -244,24 +276,56 @@ static struct of_regulator_match pfuze100_matches[] = {  	{ .name = "vgen6",	},  }; +/* PFUZE200 */ +static struct of_regulator_match pfuze200_matches[] = { + +	{ .name = "sw1ab",	}, +	{ .name = "sw2",	}, +	{ .name = "sw3a",	}, +	{ .name = "sw3b",	}, +	{ .name = "swbst",	}, +	{ .name = "vsnvs",	}, +	{ .name = "vrefddr",	}, +	{ .name = "vgen1",	}, +	{ .name = "vgen2",	}, +	{ .name = "vgen3",	}, +	{ .name = "vgen4",	}, +	{ .name = "vgen5",	}, +	{ .name = "vgen6",	}, +}; + +static struct of_regulator_match *pfuze_matches; +  static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)  {  	struct device *dev = chip->dev;  	struct device_node *np, *parent;  	int ret; -	np = of_node_get(dev->parent->of_node); +	np = of_node_get(dev->of_node);  	if (!np) -		return 0; +		return -EINVAL; -	parent = of_find_node_by_name(np, "regulators"); +	parent = of_get_child_by_name(np, "regulators");  	if (!parent) {  		dev_err(dev, "regulators node not found\n");  		return -EINVAL;  	} -	ret = of_regulator_match(dev, parent, pfuze100_matches, -				 ARRAY_SIZE(pfuze100_matches)); +	switch (chip->chip_id) { +	case PFUZE200: +		pfuze_matches = pfuze200_matches; +		ret = of_regulator_match(dev, parent, pfuze200_matches, +					 ARRAY_SIZE(pfuze200_matches)); +		break; + +	case PFUZE100: +	default: +		pfuze_matches = pfuze100_matches; +		ret = of_regulator_match(dev, parent, pfuze100_matches, +					 ARRAY_SIZE(pfuze100_matches)); +		break; +	}  	of_node_put(parent);  	if (ret < 0) { @@ -275,12 +339,12 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)  static inline struct regulator_init_data *match_init_data(int index)  { -	return pfuze100_matches[index].init_data; +	return pfuze_matches[index].init_data;  }  static inline struct device_node *match_of_node(int index)  { -	return pfuze100_matches[index].of_node; +	return pfuze_matches[index].of_node;  }  #else  static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) @@ -308,7 +372,14 @@ static int pfuze_identify(struct pfuze_chip *pfuze_chip)  	if (ret)  		return ret; -	if (value & 0x0f) { +	if (((value & 0x0f) == 0x8) && (pfuze_chip->chip_id == PFUZE100)) { +		/* +		 * Freescale misprogrammed 1-3% of parts prior to week 8 of 2013 +		 * as ID=8 in PFUZE100 +		 */ +		dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8"); +	} else if ((value & 0x0f) != pfuze_chip->chip_id) { +		/* device id NOT match with your setting */  		dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value);  		return -ENODEV;  	} @@ -317,7 +388,7 @@ static int pfuze_identify(struct pfuze_chip *pfuze_chip)  	if (ret)  		return ret;  	dev_info(pfuze_chip->dev, -		 "Full lay: %x, Metal lay: %x\n", +		 "Full layer: %x, Metal layer: %x\n",  		 (value & 0xf0) >> 4, value & 0x0f);  	ret = regmap_read(pfuze_chip->regmap, PFUZE100_FABID, &value); @@ -344,17 +415,31 @@ static int pfuze100_regulator_probe(struct i2c_client *client,  	    dev_get_platdata(&client->dev);  	struct regulator_config config = { };  	int i, ret; +	const struct of_device_id *match; +	u32 regulator_num; +	u32 sw_check_start, sw_check_end;  	pfuze_chip = devm_kzalloc(&client->dev, sizeof(*pfuze_chip),  			GFP_KERNEL);  	if (!pfuze_chip)  		return -ENOMEM; -	i2c_set_clientdata(client, pfuze_chip); - -	memcpy(pfuze_chip->regulator_descs, pfuze100_regulators, -		sizeof(pfuze_chip->regulator_descs)); +	if (client->dev.of_node) { +		match = of_match_device(of_match_ptr(pfuze_dt_ids), +				&client->dev); +		if (!match) { +			dev_err(&client->dev, "Error: No device match found\n"); +			return -ENODEV; +		} +		pfuze_chip->chip_id = (int)(long)match->data; +	} else if (id) { +		pfuze_chip->chip_id = id->driver_data; +	} else { +		dev_err(&client->dev, "No dts match or id table match found\n"); +		return -ENODEV; +	} +	i2c_set_clientdata(client, pfuze_chip);  	pfuze_chip->dev = &client->dev;  	pfuze_chip->regmap = devm_regmap_init_i2c(client, &pfuze_regmap_config); @@ -371,11 +456,34 @@ static int pfuze100_regulator_probe(struct i2c_client *client,  		return ret;  	} +	/* use the right regulators after identify the right device */ +	switch (pfuze_chip->chip_id) { +	case PFUZE200: +		pfuze_regulators = pfuze200_regulators; +		regulator_num = ARRAY_SIZE(pfuze200_regulators); +		sw_check_start = PFUZE200_SW2; +		sw_check_end = PFUZE200_SW3B; +		break; + +	case PFUZE100: +	default: +		pfuze_regulators = pfuze100_regulators; +		regulator_num = ARRAY_SIZE(pfuze100_regulators); +		sw_check_start = PFUZE100_SW2; +		sw_check_end = PFUZE100_SW4; +		break; +	} +	dev_info(&client->dev, "pfuze%s found.\n", +		(pfuze_chip->chip_id == PFUZE100) ? "100" : "200"); + +	memcpy(pfuze_chip->regulator_descs, pfuze_regulators, +		sizeof(pfuze_chip->regulator_descs)); +  	ret = pfuze_parse_regulators_dt(pfuze_chip);  	if (ret)  		return ret; -	for (i = 0; i < PFUZE100_MAX_REGULATOR; i++) { +	for (i = 0; i < regulator_num; i++) {  		struct regulator_init_data *init_data;  		struct regulator_desc *desc;  		int val; @@ -388,7 +496,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client,  			init_data = match_init_data(i);  		/* SW2~SW4 high bit check and modify the voltage value table */ -		if (i > PFUZE100_SW1C && i < PFUZE100_SWBST) { +		if (i >= sw_check_start && i <= sw_check_end) {  			regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val);  			if (val & 0x40) {  				desc->min_uV = 800000; @@ -401,32 +509,20 @@ static int pfuze100_regulator_probe(struct i2c_client *client,  		config.init_data = init_data;  		config.driver_data = pfuze_chip;  		config.of_node = match_of_node(i); +		config.ena_gpio = -EINVAL; -		pfuze_chip->regulators[i] = regulator_register(desc, &config); +		pfuze_chip->regulators[i] = +			devm_regulator_register(&client->dev, desc, &config);  		if (IS_ERR(pfuze_chip->regulators[i])) {  			dev_err(&client->dev, "register regulator%s failed\n", -				pfuze100_regulators[i].desc.name); -			ret = PTR_ERR(pfuze_chip->regulators[i]); -			while (--i >= 0) -				regulator_unregister(pfuze_chip->regulators[i]); -			return ret; +				pfuze_regulators[i].desc.name); +			return PTR_ERR(pfuze_chip->regulators[i]);  		}  	}  	return 0;  } -static int pfuze100_regulator_remove(struct i2c_client *client) -{ -	int i; -	struct pfuze_chip *pfuze_chip = i2c_get_clientdata(client); - -	for (i = 0; i < PFUZE100_MAX_REGULATOR; i++) -		regulator_unregister(pfuze_chip->regulators[i]); - -	return 0; -} -  static struct i2c_driver pfuze_driver = {  	.id_table = pfuze_device_id,  	.driver = { @@ -435,11 +531,10 @@ static struct i2c_driver pfuze_driver = {  		.of_match_table = pfuze_dt_ids,  	},  	.probe = pfuze100_regulator_probe, -	.remove = pfuze100_regulator_remove,  };  module_i2c_driver(pfuze_driver);  MODULE_AUTHOR("Robin Gong <b38343@freescale.com>"); -MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100 PMIC"); +MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/PFUZE200 PMIC");  MODULE_LICENSE("GPL v2");  MODULE_ALIAS("i2c:pfuze100-regulator"); diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c index 5885b450459..4c414ae109a 100644 --- a/drivers/regulator/rc5t583-regulator.c +++ b/drivers/regulator/rc5t583-regulator.c @@ -119,7 +119,6 @@ static int rc5t583_regulator_probe(struct platform_device *pdev)  {  	struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent);  	struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev); -	struct regulator_init_data *reg_data;  	struct regulator_config config = { };  	struct rc5t583_regulator *reg = NULL;  	struct rc5t583_regulator *regs; @@ -135,19 +134,11 @@ static int rc5t583_regulator_probe(struct platform_device *pdev)  	regs = devm_kzalloc(&pdev->dev, RC5T583_REGULATOR_MAX *  			sizeof(struct rc5t583_regulator), GFP_KERNEL); -	if (!regs) { -		dev_err(&pdev->dev, "Memory allocation failed exiting..\n"); +	if (!regs)  		return -ENOMEM; -	}  	for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) { -		reg_data = pdata->reg_init_data[id]; - -		/* No need to register if there is no regulator data */ -		if (!reg_data) -			continue; -  		reg = ®s[id];  		ri = &rc5t583_reg_info[id];  		reg->reg_info = ri; @@ -169,37 +160,20 @@ static int rc5t583_regulator_probe(struct platform_device *pdev)  skip_ext_pwr_config:  		config.dev = &pdev->dev; -		config.init_data = reg_data; +		config.init_data = pdata->reg_init_data[id];  		config.driver_data = reg;  		config.regmap = rc5t583->regmap; -		rdev = regulator_register(&ri->desc, &config); +		rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config);  		if (IS_ERR(rdev)) {  			dev_err(&pdev->dev, "Failed to register regulator %s\n",  						ri->desc.name); -			ret = PTR_ERR(rdev); -			goto clean_exit; +			return PTR_ERR(rdev);  		}  		reg->rdev = rdev;  	}  	platform_set_drvdata(pdev, regs);  	return 0; - -clean_exit: -	while (--id >= 0) -		regulator_unregister(regs[id].rdev); - -	return ret; -} - -static int rc5t583_regulator_remove(struct platform_device *pdev) -{ -	struct rc5t583_regulator *regs = platform_get_drvdata(pdev); -	int id; - -	for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) -		regulator_unregister(regs[id].rdev); -	return 0;  }  static struct platform_driver rc5t583_regulator_driver = { @@ -208,7 +182,6 @@ static struct platform_driver rc5t583_regulator_driver = {  		.owner	= THIS_MODULE,  	},  	.probe		= rc5t583_regulator_probe, -	.remove		= rc5t583_regulator_remove,  };  static int __init rc5t583_regulator_init(void) diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c new file mode 100644 index 00000000000..ee83b487642 --- /dev/null +++ b/drivers/regulator/s2mpa01.c @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd + *		http://www.samsung.com + * + *  This program is free software; you can redistribute  it and/or modify it + *  under  the terms of  the GNU General  Public License as published by the + *  Free Software Foundation;  either version 2 of the  License, or (at your + *  option) any later version. + * + */ + +#include <linux/bug.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/mfd/samsung/core.h> +#include <linux/mfd/samsung/s2mpa01.h> + +#define S2MPA01_REGULATOR_CNT ARRAY_SIZE(regulators) + +struct s2mpa01_info { +	int ramp_delay24; +	int ramp_delay3; +	int ramp_delay5; +	int ramp_delay16; +	int ramp_delay7; +	int ramp_delay8910; +}; + +static int get_ramp_delay(int ramp_delay) +{ +	unsigned char cnt = 0; + +	ramp_delay /= 6250; + +	while (true) { +		ramp_delay = ramp_delay >> 1; +		if (ramp_delay == 0) +			break; +		cnt++; +	} + +	if (cnt > 3) +		cnt = 3; + +	return cnt; +} + +static int s2mpa01_regulator_set_voltage_time_sel(struct regulator_dev *rdev, +				   unsigned int old_selector, +				   unsigned int new_selector) +{ +	struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev); +	unsigned int ramp_delay = 0; +	int old_volt, new_volt; + +	switch (rdev_get_id(rdev)) { +	case S2MPA01_BUCK2: +	case S2MPA01_BUCK4: +		ramp_delay = s2mpa01->ramp_delay24; +		break; +	case S2MPA01_BUCK3: +		ramp_delay = s2mpa01->ramp_delay3; +		break; +	case S2MPA01_BUCK5: +		ramp_delay = s2mpa01->ramp_delay5; +		break; +	case S2MPA01_BUCK1: +	case S2MPA01_BUCK6: +		ramp_delay = s2mpa01->ramp_delay16; +		break; +	case S2MPA01_BUCK7: +		ramp_delay = s2mpa01->ramp_delay7; +		break; +	case S2MPA01_BUCK8: +	case S2MPA01_BUCK9: +	case S2MPA01_BUCK10: +		ramp_delay = s2mpa01->ramp_delay8910; +		break; +	} + +	if (ramp_delay == 0) +		ramp_delay = rdev->desc->ramp_delay; + +	old_volt = rdev->desc->min_uV + (rdev->desc->uV_step * old_selector); +	new_volt = rdev->desc->min_uV + (rdev->desc->uV_step * new_selector); + +	return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay); +} + +static int s2mpa01_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) +{ +	struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev); +	unsigned int ramp_val, ramp_shift, ramp_reg = S2MPA01_REG_RAMP2; +	unsigned int ramp_enable = 1, enable_shift = 0; +	int ret; + +	switch (rdev_get_id(rdev)) { +	case S2MPA01_BUCK1: +		enable_shift = S2MPA01_BUCK1_RAMP_EN_SHIFT; +		if (!ramp_delay) { +			ramp_enable = 0; +			break; +		} + +		if (ramp_delay > s2mpa01->ramp_delay16) +			s2mpa01->ramp_delay16 = ramp_delay; +		else +			ramp_delay = s2mpa01->ramp_delay16; + +		ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT; +		break; +	case S2MPA01_BUCK2: +		enable_shift = S2MPA01_BUCK2_RAMP_EN_SHIFT; +		if (!ramp_delay) { +			ramp_enable = 0; +			break; +		} + +		if (ramp_delay > s2mpa01->ramp_delay24) +			s2mpa01->ramp_delay24 = ramp_delay; +		else +			ramp_delay = s2mpa01->ramp_delay24; + +		ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT; +		ramp_reg = S2MPA01_REG_RAMP1; +		break; +	case S2MPA01_BUCK3: +		enable_shift = S2MPA01_BUCK3_RAMP_EN_SHIFT; +		if (!ramp_delay) { +			ramp_enable = 0; +			break; +		} + +		s2mpa01->ramp_delay3 = ramp_delay; +		ramp_shift = S2MPA01_BUCK3_RAMP_SHIFT; +		ramp_reg = S2MPA01_REG_RAMP1; +		break; +	case S2MPA01_BUCK4: +		enable_shift = S2MPA01_BUCK4_RAMP_EN_SHIFT; +		if (!ramp_delay) { +			ramp_enable = 0; +			break; +		} + +		if (ramp_delay > s2mpa01->ramp_delay24) +			s2mpa01->ramp_delay24 = ramp_delay; +		else +			ramp_delay = s2mpa01->ramp_delay24; + +		ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT; +		ramp_reg = S2MPA01_REG_RAMP1; +		break; +	case S2MPA01_BUCK5: +		s2mpa01->ramp_delay5 = ramp_delay; +		ramp_shift = S2MPA01_BUCK5_RAMP_SHIFT; +		break; +	case S2MPA01_BUCK6: +		if (ramp_delay > s2mpa01->ramp_delay16) +			s2mpa01->ramp_delay16 = ramp_delay; +		else +			ramp_delay = s2mpa01->ramp_delay16; + +		ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT; +		break; +	case S2MPA01_BUCK7: +		s2mpa01->ramp_delay7 = ramp_delay; +		ramp_shift = S2MPA01_BUCK7_RAMP_SHIFT; +		break; +	case S2MPA01_BUCK8: +	case S2MPA01_BUCK9: +	case S2MPA01_BUCK10: +		if (ramp_delay > s2mpa01->ramp_delay8910) +			s2mpa01->ramp_delay8910 = ramp_delay; +		else +			ramp_delay = s2mpa01->ramp_delay8910; + +		ramp_shift = S2MPA01_BUCK8910_RAMP_SHIFT; +		break; +	default: +		return 0; +	} + +	if (!ramp_enable) +		goto ramp_disable; + +	/* Ramp delay can be enabled/disabled only for buck[1234] */ +	if (rdev_get_id(rdev) >= S2MPA01_BUCK1 && +			rdev_get_id(rdev) <= S2MPA01_BUCK4) { +		ret = regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1, +					 1 << enable_shift, 1 << enable_shift); +		if (ret) { +			dev_err(&rdev->dev, "failed to enable ramp rate\n"); +			return ret; +		} +	} + +	ramp_val = get_ramp_delay(ramp_delay); + +	return regmap_update_bits(rdev->regmap, ramp_reg, 0x3 << ramp_shift, +				  ramp_val << ramp_shift); + +ramp_disable: +	return regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1, +				  1 << enable_shift, 0); +} + +static struct regulator_ops s2mpa01_ldo_ops = { +	.list_voltage		= regulator_list_voltage_linear, +	.map_voltage		= regulator_map_voltage_linear, +	.is_enabled		= regulator_is_enabled_regmap, +	.enable			= regulator_enable_regmap, +	.disable		= regulator_disable_regmap, +	.get_voltage_sel	= regulator_get_voltage_sel_regmap, +	.set_voltage_sel	= regulator_set_voltage_sel_regmap, +	.set_voltage_time_sel	= regulator_set_voltage_time_sel, +}; + +static struct regulator_ops s2mpa01_buck_ops = { +	.list_voltage		= regulator_list_voltage_linear, +	.map_voltage		= regulator_map_voltage_linear, +	.is_enabled		= regulator_is_enabled_regmap, +	.enable			= regulator_enable_regmap, +	.disable		= regulator_disable_regmap, +	.get_voltage_sel	= regulator_get_voltage_sel_regmap, +	.set_voltage_sel	= regulator_set_voltage_sel_regmap, +	.set_voltage_time_sel	= s2mpa01_regulator_set_voltage_time_sel, +	.set_ramp_delay		= s2mpa01_set_ramp_delay, +}; + +#define regulator_desc_ldo1(num)	{		\ +	.name		= "LDO"#num,			\ +	.id		= S2MPA01_LDO##num,		\ +	.ops		= &s2mpa01_ldo_ops,		\ +	.type		= REGULATOR_VOLTAGE,		\ +	.owner		= THIS_MODULE,			\ +	.min_uV		= S2MPA01_LDO_MIN,		\ +	.uV_step	= S2MPA01_LDO_STEP1,		\ +	.n_voltages	= S2MPA01_LDO_N_VOLTAGES,	\ +	.vsel_reg	= S2MPA01_REG_L1CTRL + num - 1,	\ +	.vsel_mask	= S2MPA01_LDO_VSEL_MASK,	\ +	.enable_reg	= S2MPA01_REG_L1CTRL + num - 1,	\ +	.enable_mask	= S2MPA01_ENABLE_MASK		\ +} +#define regulator_desc_ldo2(num)	{		\ +	.name		= "LDO"#num,			\ +	.id		= S2MPA01_LDO##num,		\ +	.ops		= &s2mpa01_ldo_ops,		\ +	.type		= REGULATOR_VOLTAGE,		\ +	.owner		= THIS_MODULE,			\ +	.min_uV		= S2MPA01_LDO_MIN,		\ +	.uV_step	= S2MPA01_LDO_STEP2,		\ +	.n_voltages	= S2MPA01_LDO_N_VOLTAGES,	\ +	.vsel_reg	= S2MPA01_REG_L1CTRL + num - 1,	\ +	.vsel_mask	= S2MPA01_LDO_VSEL_MASK,	\ +	.enable_reg	= S2MPA01_REG_L1CTRL + num - 1,	\ +	.enable_mask	= S2MPA01_ENABLE_MASK		\ +} + +#define regulator_desc_buck1_4(num)	{			\ +	.name		= "BUCK"#num,				\ +	.id		= S2MPA01_BUCK##num,			\ +	.ops		= &s2mpa01_buck_ops,			\ +	.type		= REGULATOR_VOLTAGE,			\ +	.owner		= THIS_MODULE,				\ +	.min_uV		= S2MPA01_BUCK_MIN1,			\ +	.uV_step	= S2MPA01_BUCK_STEP1,			\ +	.n_voltages	= S2MPA01_BUCK_N_VOLTAGES,		\ +	.ramp_delay	= S2MPA01_RAMP_DELAY,			\ +	.vsel_reg	= S2MPA01_REG_B1CTRL2 + (num - 1) * 2,	\ +	.vsel_mask	= S2MPA01_BUCK_VSEL_MASK,		\ +	.enable_reg	= S2MPA01_REG_B1CTRL1 + (num - 1) * 2,	\ +	.enable_mask	= S2MPA01_ENABLE_MASK			\ +} + +#define regulator_desc_buck5	{				\ +	.name		= "BUCK5",				\ +	.id		= S2MPA01_BUCK5,			\ +	.ops		= &s2mpa01_buck_ops,			\ +	.type		= REGULATOR_VOLTAGE,			\ +	.owner		= THIS_MODULE,				\ +	.min_uV		= S2MPA01_BUCK_MIN2,			\ +	.uV_step	= S2MPA01_BUCK_STEP1,			\ +	.n_voltages	= S2MPA01_BUCK_N_VOLTAGES,		\ +	.ramp_delay	= S2MPA01_RAMP_DELAY,			\ +	.vsel_reg	= S2MPA01_REG_B5CTRL2,			\ +	.vsel_mask	= S2MPA01_BUCK_VSEL_MASK,		\ +	.enable_reg	= S2MPA01_REG_B5CTRL1,			\ +	.enable_mask	= S2MPA01_ENABLE_MASK			\ +} + +#define regulator_desc_buck6_7(num)	{			\ +	.name		= "BUCK"#num,				\ +	.id		= S2MPA01_BUCK##num,			\ +	.ops		= &s2mpa01_buck_ops,			\ +	.type		= REGULATOR_VOLTAGE,			\ +	.owner		= THIS_MODULE,				\ +	.min_uV		= S2MPA01_BUCK_MIN1,			\ +	.uV_step	= S2MPA01_BUCK_STEP1,			\ +	.n_voltages	= S2MPA01_BUCK_N_VOLTAGES,		\ +	.ramp_delay	= S2MPA01_RAMP_DELAY,			\ +	.vsel_reg	= S2MPA01_REG_B6CTRL2 + (num - 6) * 2,	\ +	.vsel_mask	= S2MPA01_BUCK_VSEL_MASK,		\ +	.enable_reg	= S2MPA01_REG_B6CTRL1 + (num - 6) * 2,	\ +	.enable_mask	= S2MPA01_ENABLE_MASK			\ +} + +#define regulator_desc_buck8	{				\ +	.name		= "BUCK8",				\ +	.id		= S2MPA01_BUCK8,			\ +	.ops		= &s2mpa01_buck_ops,			\ +	.type		= REGULATOR_VOLTAGE,			\ +	.owner		= THIS_MODULE,				\ +	.min_uV		= S2MPA01_BUCK_MIN2,			\ +	.uV_step	= S2MPA01_BUCK_STEP2,			\ +	.n_voltages	= S2MPA01_BUCK_N_VOLTAGES,		\ +	.ramp_delay	= S2MPA01_RAMP_DELAY,			\ +	.vsel_reg	= S2MPA01_REG_B8CTRL2,			\ +	.vsel_mask	= S2MPA01_BUCK_VSEL_MASK,		\ +	.enable_reg	= S2MPA01_REG_B8CTRL1,			\ +	.enable_mask	= S2MPA01_ENABLE_MASK			\ +} + +#define regulator_desc_buck9	{				\ +	.name		= "BUCK9",				\ +	.id		= S2MPA01_BUCK9,			\ +	.ops		= &s2mpa01_buck_ops,			\ +	.type		= REGULATOR_VOLTAGE,			\ +	.owner		= THIS_MODULE,				\ +	.min_uV		= S2MPA01_BUCK_MIN4,			\ +	.uV_step	= S2MPA01_BUCK_STEP2,			\ +	.n_voltages	= S2MPA01_BUCK_N_VOLTAGES,		\ +	.ramp_delay	= S2MPA01_RAMP_DELAY,			\ +	.vsel_reg	= S2MPA01_REG_B9CTRL2,			\ +	.vsel_mask	= S2MPA01_BUCK_VSEL_MASK,		\ +	.enable_reg	= S2MPA01_REG_B9CTRL1,			\ +	.enable_mask	= S2MPA01_ENABLE_MASK			\ +} + +#define regulator_desc_buck10	{				\ +	.name		= "BUCK10",				\ +	.id		= S2MPA01_BUCK10,			\ +	.ops		= &s2mpa01_buck_ops,			\ +	.type		= REGULATOR_VOLTAGE,			\ +	.owner		= THIS_MODULE,				\ +	.min_uV		= S2MPA01_BUCK_MIN3,			\ +	.uV_step	= S2MPA01_BUCK_STEP2,			\ +	.n_voltages	= S2MPA01_BUCK_N_VOLTAGES,		\ +	.ramp_delay	= S2MPA01_RAMP_DELAY,			\ +	.vsel_reg	= S2MPA01_REG_B10CTRL2,			\ +	.vsel_mask	= S2MPA01_BUCK_VSEL_MASK,		\ +	.enable_reg	= S2MPA01_REG_B10CTRL1,			\ +	.enable_mask	= S2MPA01_ENABLE_MASK			\ +} + +static struct regulator_desc regulators[] = { +	regulator_desc_ldo2(1), +	regulator_desc_ldo1(2), +	regulator_desc_ldo1(3), +	regulator_desc_ldo1(4), +	regulator_desc_ldo1(5), +	regulator_desc_ldo2(6), +	regulator_desc_ldo1(7), +	regulator_desc_ldo1(8), +	regulator_desc_ldo1(9), +	regulator_desc_ldo1(10), +	regulator_desc_ldo2(11), +	regulator_desc_ldo1(12), +	regulator_desc_ldo1(13), +	regulator_desc_ldo1(14), +	regulator_desc_ldo1(15), +	regulator_desc_ldo1(16), +	regulator_desc_ldo1(17), +	regulator_desc_ldo1(18), +	regulator_desc_ldo1(19), +	regulator_desc_ldo1(20), +	regulator_desc_ldo1(21), +	regulator_desc_ldo2(22), +	regulator_desc_ldo2(23), +	regulator_desc_ldo1(24), +	regulator_desc_ldo1(25), +	regulator_desc_ldo1(26), +	regulator_desc_buck1_4(1), +	regulator_desc_buck1_4(2), +	regulator_desc_buck1_4(3), +	regulator_desc_buck1_4(4), +	regulator_desc_buck5, +	regulator_desc_buck6_7(6), +	regulator_desc_buck6_7(7), +	regulator_desc_buck8, +	regulator_desc_buck9, +	regulator_desc_buck10, +}; + +static int s2mpa01_pmic_probe(struct platform_device *pdev) +{ +	struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); +	struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); +	struct of_regulator_match rdata[S2MPA01_REGULATOR_MAX]; +	struct device_node *reg_np = NULL; +	struct regulator_config config = { }; +	struct s2mpa01_info *s2mpa01; +	int i; + +	s2mpa01 = devm_kzalloc(&pdev->dev, sizeof(*s2mpa01), GFP_KERNEL); +	if (!s2mpa01) +		return -ENOMEM; + +	for (i = 0; i < S2MPA01_REGULATOR_CNT; i++) +		rdata[i].name = regulators[i].name; + +	if (iodev->dev->of_node) { +		reg_np = of_get_child_by_name(iodev->dev->of_node, +							"regulators"); +			if (!reg_np) { +				dev_err(&pdev->dev, +					"could not find regulators sub-node\n"); +				return -EINVAL; +			} + +		of_regulator_match(&pdev->dev, reg_np, rdata, +						S2MPA01_REGULATOR_MAX); +		of_node_put(reg_np); +	} + +	platform_set_drvdata(pdev, s2mpa01); + +	config.dev = &pdev->dev; +	config.regmap = iodev->regmap_pmic; +	config.driver_data = s2mpa01; + +	for (i = 0; i < S2MPA01_REGULATOR_MAX; i++) { +		struct regulator_dev *rdev; +		if (pdata) +			config.init_data = pdata->regulators[i].initdata; +		else +			config.init_data = rdata[i].init_data; + +		if (reg_np) +			config.of_node = rdata[i].of_node; + +		rdev = devm_regulator_register(&pdev->dev, +						®ulators[i], &config); +		if (IS_ERR(rdev)) { +			dev_err(&pdev->dev, "regulator init failed for %d\n", +				i); +			return PTR_ERR(rdev); +		} +	} + +	return 0; +} + +static const struct platform_device_id s2mpa01_pmic_id[] = { +	{ "s2mpa01-pmic", 0}, +	{ }, +}; +MODULE_DEVICE_TABLE(platform, s2mpa01_pmic_id); + +static struct platform_driver s2mpa01_pmic_driver = { +	.driver = { +		.name = "s2mpa01-pmic", +		.owner = THIS_MODULE, +	}, +	.probe = s2mpa01_pmic_probe, +	.id_table = s2mpa01_pmic_id, +}; + +module_platform_driver(s2mpa01_pmic_driver); + +/* Module information */ +MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); +MODULE_AUTHOR("Sachin Kamat <sachin.kamat@samsung.com>"); +MODULE_DESCRIPTION("SAMSUNG S2MPA01 Regulator Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 5eba2ff8c0e..02e2fb2fca6 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -1,13 +1,18 @@  /*   * s2mps11.c   * - * Copyright (c) 2012 Samsung Electronics Co., Ltd + * Copyright (c) 2012-2014 Samsung Electronics Co., Ltd   *              http://www.samsung.com   * - *  This program is free software; you can redistribute  it and/or modify it - *  under  the terms of  the GNU General  Public License as published by the - *  Free Software Foundation;  either version 2 of the  License, or (at your - *  option) any later version. + * This program is free software; you can redistribute  it and/or modify it + * under  the terms of  the GNU General  Public License as published by the + * Free Software Foundation;  either version 2 of the  License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details.   *   */ @@ -22,20 +27,26 @@  #include <linux/regulator/driver.h>  #include <linux/regulator/machine.h>  #include <linux/regulator/of_regulator.h> +#include <linux/of_gpio.h>  #include <linux/mfd/samsung/core.h>  #include <linux/mfd/samsung/s2mps11.h> - -#define S2MPS11_REGULATOR_CNT ARRAY_SIZE(regulators) +#include <linux/mfd/samsung/s2mps14.h>  struct s2mps11_info { -	struct regulator_dev *rdev[S2MPS11_REGULATOR_MAX]; - +	unsigned int rdev_num;  	int ramp_delay2;  	int ramp_delay34;  	int ramp_delay5;  	int ramp_delay16;  	int ramp_delay7810;  	int ramp_delay9; +	/* +	 * One bit for each S2MPS14 regulator whether the suspend mode +	 * was enabled. +	 */ +	unsigned int s2mps14_suspend_state:30; +	/* Array of size rdev_num with GPIO-s for external sleep control */ +	int *ext_control_gpio;  };  static int get_ramp_delay(int ramp_delay) @@ -65,13 +76,11 @@ static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev,  	unsigned int ramp_delay = 0;  	int old_volt, new_volt; -	switch (rdev->desc->id) { +	switch (rdev_get_id(rdev)) {  	case S2MPS11_BUCK2:  		ramp_delay = s2mps11->ramp_delay2;  		break;  	case S2MPS11_BUCK3: -		ramp_delay = s2mps11->ramp_delay34; -		break;  	case S2MPS11_BUCK4:  		ramp_delay = s2mps11->ramp_delay34;  		break; @@ -107,7 +116,7 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)  	unsigned int ramp_enable = 1, enable_shift = 0;  	int ret; -	switch (rdev->desc->id) { +	switch (rdev_get_id(rdev)) {  	case S2MPS11_BUCK1:  		if (ramp_delay > s2mps11->ramp_delay16)  			s2mps11->ramp_delay16 = ramp_delay; @@ -196,9 +205,12 @@ static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)  	if (!ramp_enable)  		goto ramp_disable; -	if (enable_shift) { +	/* Ramp delay can be enabled/disabled only for buck[2346] */ +	if ((rdev_get_id(rdev) >= S2MPS11_BUCK2 && +			rdev_get_id(rdev) <= S2MPS11_BUCK4) || +			rdev_get_id(rdev) == S2MPS11_BUCK6)  {  		ret = regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP, -					1 << enable_shift, 1 << enable_shift); +					 1 << enable_shift, 1 << enable_shift);  		if (ret) {  			dev_err(&rdev->dev, "failed to enable ramp rate\n");  			return ret; @@ -238,7 +250,7 @@ static struct regulator_ops s2mps11_buck_ops = {  	.set_ramp_delay		= s2mps11_set_ramp_delay,  }; -#define regulator_desc_ldo1(num)	{		\ +#define regulator_desc_s2mps11_ldo1(num)	{		\  	.name		= "LDO"#num,			\  	.id		= S2MPS11_LDO##num,		\  	.ops		= &s2mps11_ldo_ops,		\ @@ -252,7 +264,7 @@ static struct regulator_ops s2mps11_buck_ops = {  	.enable_reg	= S2MPS11_REG_L1CTRL + num - 1,	\  	.enable_mask	= S2MPS11_ENABLE_MASK		\  } -#define regulator_desc_ldo2(num)	{		\ +#define regulator_desc_s2mps11_ldo2(num) {		\  	.name		= "LDO"#num,			\  	.id		= S2MPS11_LDO##num,		\  	.ops		= &s2mps11_ldo_ops,		\ @@ -267,7 +279,7 @@ static struct regulator_ops s2mps11_buck_ops = {  	.enable_mask	= S2MPS11_ENABLE_MASK		\  } -#define regulator_desc_buck1_4(num)	{			\ +#define regulator_desc_s2mps11_buck1_4(num) {			\  	.name		= "BUCK"#num,				\  	.id		= S2MPS11_BUCK##num,			\  	.ops		= &s2mps11_buck_ops,			\ @@ -283,7 +295,7 @@ static struct regulator_ops s2mps11_buck_ops = {  	.enable_mask	= S2MPS11_ENABLE_MASK			\  } -#define regulator_desc_buck5	{				\ +#define regulator_desc_s2mps11_buck5 {				\  	.name		= "BUCK5",				\  	.id		= S2MPS11_BUCK5,			\  	.ops		= &s2mps11_buck_ops,			\ @@ -299,7 +311,7 @@ static struct regulator_ops s2mps11_buck_ops = {  	.enable_mask	= S2MPS11_ENABLE_MASK			\  } -#define regulator_desc_buck6_8(num)	{			\ +#define regulator_desc_s2mps11_buck6_8(num) {			\  	.name		= "BUCK"#num,				\  	.id		= S2MPS11_BUCK##num,			\  	.ops		= &s2mps11_buck_ops,			\ @@ -315,7 +327,7 @@ static struct regulator_ops s2mps11_buck_ops = {  	.enable_mask	= S2MPS11_ENABLE_MASK			\  } -#define regulator_desc_buck9	{				\ +#define regulator_desc_s2mps11_buck9 {				\  	.name		= "BUCK9",				\  	.id		= S2MPS11_BUCK9,			\  	.ops		= &s2mps11_buck_ops,			\ @@ -331,7 +343,7 @@ static struct regulator_ops s2mps11_buck_ops = {  	.enable_mask	= S2MPS11_ENABLE_MASK			\  } -#define regulator_desc_buck10	{				\ +#define regulator_desc_s2mps11_buck10 {				\  	.name		= "BUCK10",				\  	.id		= S2MPS11_BUCK10,			\  	.ops		= &s2mps11_buck_ops,			\ @@ -347,74 +359,318 @@ static struct regulator_ops s2mps11_buck_ops = {  	.enable_mask	= S2MPS11_ENABLE_MASK			\  } -static struct regulator_desc regulators[] = { -	regulator_desc_ldo2(1), -	regulator_desc_ldo1(2), -	regulator_desc_ldo1(3), -	regulator_desc_ldo1(4), -	regulator_desc_ldo1(5), -	regulator_desc_ldo2(6), -	regulator_desc_ldo1(7), -	regulator_desc_ldo1(8), -	regulator_desc_ldo1(9), -	regulator_desc_ldo1(10), -	regulator_desc_ldo2(11), -	regulator_desc_ldo1(12), -	regulator_desc_ldo1(13), -	regulator_desc_ldo1(14), -	regulator_desc_ldo1(15), -	regulator_desc_ldo1(16), -	regulator_desc_ldo1(17), -	regulator_desc_ldo1(18), -	regulator_desc_ldo1(19), -	regulator_desc_ldo1(20), -	regulator_desc_ldo1(21), -	regulator_desc_ldo2(22), -	regulator_desc_ldo2(23), -	regulator_desc_ldo1(24), -	regulator_desc_ldo1(25), -	regulator_desc_ldo1(26), -	regulator_desc_ldo2(27), -	regulator_desc_ldo1(28), -	regulator_desc_ldo1(29), -	regulator_desc_ldo1(30), -	regulator_desc_ldo1(31), -	regulator_desc_ldo1(32), -	regulator_desc_ldo1(33), -	regulator_desc_ldo1(34), -	regulator_desc_ldo1(35), -	regulator_desc_ldo1(36), -	regulator_desc_ldo1(37), -	regulator_desc_ldo1(38), -	regulator_desc_buck1_4(1), -	regulator_desc_buck1_4(2), -	regulator_desc_buck1_4(3), -	regulator_desc_buck1_4(4), -	regulator_desc_buck5, -	regulator_desc_buck6_8(6), -	regulator_desc_buck6_8(7), -	regulator_desc_buck6_8(8), -	regulator_desc_buck9, -	regulator_desc_buck10, +static const struct regulator_desc s2mps11_regulators[] = { +	regulator_desc_s2mps11_ldo2(1), +	regulator_desc_s2mps11_ldo1(2), +	regulator_desc_s2mps11_ldo1(3), +	regulator_desc_s2mps11_ldo1(4), +	regulator_desc_s2mps11_ldo1(5), +	regulator_desc_s2mps11_ldo2(6), +	regulator_desc_s2mps11_ldo1(7), +	regulator_desc_s2mps11_ldo1(8), +	regulator_desc_s2mps11_ldo1(9), +	regulator_desc_s2mps11_ldo1(10), +	regulator_desc_s2mps11_ldo2(11), +	regulator_desc_s2mps11_ldo1(12), +	regulator_desc_s2mps11_ldo1(13), +	regulator_desc_s2mps11_ldo1(14), +	regulator_desc_s2mps11_ldo1(15), +	regulator_desc_s2mps11_ldo1(16), +	regulator_desc_s2mps11_ldo1(17), +	regulator_desc_s2mps11_ldo1(18), +	regulator_desc_s2mps11_ldo1(19), +	regulator_desc_s2mps11_ldo1(20), +	regulator_desc_s2mps11_ldo1(21), +	regulator_desc_s2mps11_ldo2(22), +	regulator_desc_s2mps11_ldo2(23), +	regulator_desc_s2mps11_ldo1(24), +	regulator_desc_s2mps11_ldo1(25), +	regulator_desc_s2mps11_ldo1(26), +	regulator_desc_s2mps11_ldo2(27), +	regulator_desc_s2mps11_ldo1(28), +	regulator_desc_s2mps11_ldo1(29), +	regulator_desc_s2mps11_ldo1(30), +	regulator_desc_s2mps11_ldo1(31), +	regulator_desc_s2mps11_ldo1(32), +	regulator_desc_s2mps11_ldo1(33), +	regulator_desc_s2mps11_ldo1(34), +	regulator_desc_s2mps11_ldo1(35), +	regulator_desc_s2mps11_ldo1(36), +	regulator_desc_s2mps11_ldo1(37), +	regulator_desc_s2mps11_ldo1(38), +	regulator_desc_s2mps11_buck1_4(1), +	regulator_desc_s2mps11_buck1_4(2), +	regulator_desc_s2mps11_buck1_4(3), +	regulator_desc_s2mps11_buck1_4(4), +	regulator_desc_s2mps11_buck5, +	regulator_desc_s2mps11_buck6_8(6), +	regulator_desc_s2mps11_buck6_8(7), +	regulator_desc_s2mps11_buck6_8(8), +	regulator_desc_s2mps11_buck9, +	regulator_desc_s2mps11_buck10, +}; + +static int s2mps14_regulator_enable(struct regulator_dev *rdev) +{ +	struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); +	unsigned int val; + +	if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev))) +		val = S2MPS14_ENABLE_SUSPEND; +	else if (gpio_is_valid(s2mps11->ext_control_gpio[rdev_get_id(rdev)])) +		val = S2MPS14_ENABLE_EXT_CONTROL; +	else +		val = rdev->desc->enable_mask; + +	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, +			rdev->desc->enable_mask, val); +} + +static int s2mps14_regulator_set_suspend_disable(struct regulator_dev *rdev) +{ +	int ret; +	unsigned int val; +	struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev); + +	/* LDO3 should be always on and does not support suspend mode */ +	if (rdev_get_id(rdev) == S2MPS14_LDO3) +		return 0; + +	ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val); +	if (ret < 0) +		return ret; + +	s2mps11->s2mps14_suspend_state |= (1 << rdev_get_id(rdev)); +	/* +	 * Don't enable suspend mode if regulator is already disabled because +	 * this would effectively for a short time turn on the regulator after +	 * resuming. +	 * However we still want to toggle the suspend_state bit for regulator +	 * in case if it got enabled before suspending the system. +	 */ +	if (!(val & rdev->desc->enable_mask)) +		return 0; + +	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, +			rdev->desc->enable_mask, S2MPS14_ENABLE_SUSPEND); +} + +static struct regulator_ops s2mps14_reg_ops = { +	.list_voltage		= regulator_list_voltage_linear, +	.map_voltage		= regulator_map_voltage_linear, +	.is_enabled		= regulator_is_enabled_regmap, +	.enable			= s2mps14_regulator_enable, +	.disable		= regulator_disable_regmap, +	.get_voltage_sel	= regulator_get_voltage_sel_regmap, +	.set_voltage_sel	= regulator_set_voltage_sel_regmap, +	.set_voltage_time_sel	= regulator_set_voltage_time_sel, +	.set_suspend_disable	= s2mps14_regulator_set_suspend_disable, +}; + +#define regulator_desc_s2mps14_ldo1(num) {		\ +	.name		= "LDO"#num,			\ +	.id		= S2MPS14_LDO##num,		\ +	.ops		= &s2mps14_reg_ops,		\ +	.type		= REGULATOR_VOLTAGE,		\ +	.owner		= THIS_MODULE,			\ +	.min_uV		= S2MPS14_LDO_MIN_800MV,	\ +	.uV_step	= S2MPS14_LDO_STEP_25MV,	\ +	.n_voltages	= S2MPS14_LDO_N_VOLTAGES,	\ +	.vsel_reg	= S2MPS14_REG_L1CTRL + num - 1,	\ +	.vsel_mask	= S2MPS14_LDO_VSEL_MASK,	\ +	.enable_reg	= S2MPS14_REG_L1CTRL + num - 1,	\ +	.enable_mask	= S2MPS14_ENABLE_MASK		\ +} +#define regulator_desc_s2mps14_ldo2(num) {		\ +	.name		= "LDO"#num,			\ +	.id		= S2MPS14_LDO##num,		\ +	.ops		= &s2mps14_reg_ops,		\ +	.type		= REGULATOR_VOLTAGE,		\ +	.owner		= THIS_MODULE,			\ +	.min_uV		= S2MPS14_LDO_MIN_1800MV,	\ +	.uV_step	= S2MPS14_LDO_STEP_25MV,	\ +	.n_voltages	= S2MPS14_LDO_N_VOLTAGES,	\ +	.vsel_reg	= S2MPS14_REG_L1CTRL + num - 1,	\ +	.vsel_mask	= S2MPS14_LDO_VSEL_MASK,	\ +	.enable_reg	= S2MPS14_REG_L1CTRL + num - 1,	\ +	.enable_mask	= S2MPS14_ENABLE_MASK		\ +} +#define regulator_desc_s2mps14_ldo3(num) {		\ +	.name		= "LDO"#num,			\ +	.id		= S2MPS14_LDO##num,		\ +	.ops		= &s2mps14_reg_ops,		\ +	.type		= REGULATOR_VOLTAGE,		\ +	.owner		= THIS_MODULE,			\ +	.min_uV		= S2MPS14_LDO_MIN_800MV,	\ +	.uV_step	= S2MPS14_LDO_STEP_12_5MV,	\ +	.n_voltages	= S2MPS14_LDO_N_VOLTAGES,	\ +	.vsel_reg	= S2MPS14_REG_L1CTRL + num - 1,	\ +	.vsel_mask	= S2MPS14_LDO_VSEL_MASK,	\ +	.enable_reg	= S2MPS14_REG_L1CTRL + num - 1,	\ +	.enable_mask	= S2MPS14_ENABLE_MASK		\ +} +#define regulator_desc_s2mps14_buck1235(num) {			\ +	.name		= "BUCK"#num,				\ +	.id		= S2MPS14_BUCK##num,			\ +	.ops		= &s2mps14_reg_ops,			\ +	.type		= REGULATOR_VOLTAGE,			\ +	.owner		= THIS_MODULE,				\ +	.min_uV		= S2MPS14_BUCK1235_MIN_600MV,		\ +	.uV_step	= S2MPS14_BUCK1235_STEP_6_25MV,		\ +	.n_voltages	= S2MPS14_BUCK_N_VOLTAGES,		\ +	.linear_min_sel = S2MPS14_BUCK1235_START_SEL,		\ +	.ramp_delay	= S2MPS14_BUCK_RAMP_DELAY,		\ +	.vsel_reg	= S2MPS14_REG_B1CTRL2 + (num - 1) * 2,	\ +	.vsel_mask	= S2MPS14_BUCK_VSEL_MASK,		\ +	.enable_reg	= S2MPS14_REG_B1CTRL1 + (num - 1) * 2,	\ +	.enable_mask	= S2MPS14_ENABLE_MASK			\ +} +#define regulator_desc_s2mps14_buck4(num) {			\ +	.name		= "BUCK"#num,				\ +	.id		= S2MPS14_BUCK##num,			\ +	.ops		= &s2mps14_reg_ops,			\ +	.type		= REGULATOR_VOLTAGE,			\ +	.owner		= THIS_MODULE,				\ +	.min_uV		= S2MPS14_BUCK4_MIN_1400MV,		\ +	.uV_step	= S2MPS14_BUCK4_STEP_12_5MV,		\ +	.n_voltages	= S2MPS14_BUCK_N_VOLTAGES,		\ +	.linear_min_sel = S2MPS14_BUCK4_START_SEL,		\ +	.ramp_delay	= S2MPS14_BUCK_RAMP_DELAY,		\ +	.vsel_reg	= S2MPS14_REG_B1CTRL2 + (num - 1) * 2,	\ +	.vsel_mask	= S2MPS14_BUCK_VSEL_MASK,		\ +	.enable_reg	= S2MPS14_REG_B1CTRL1 + (num - 1) * 2,	\ +	.enable_mask	= S2MPS14_ENABLE_MASK			\ +} + +static const struct regulator_desc s2mps14_regulators[] = { +	regulator_desc_s2mps14_ldo3(1), +	regulator_desc_s2mps14_ldo3(2), +	regulator_desc_s2mps14_ldo1(3), +	regulator_desc_s2mps14_ldo1(4), +	regulator_desc_s2mps14_ldo3(5), +	regulator_desc_s2mps14_ldo3(6), +	regulator_desc_s2mps14_ldo1(7), +	regulator_desc_s2mps14_ldo2(8), +	regulator_desc_s2mps14_ldo3(9), +	regulator_desc_s2mps14_ldo3(10), +	regulator_desc_s2mps14_ldo1(11), +	regulator_desc_s2mps14_ldo2(12), +	regulator_desc_s2mps14_ldo2(13), +	regulator_desc_s2mps14_ldo2(14), +	regulator_desc_s2mps14_ldo2(15), +	regulator_desc_s2mps14_ldo2(16), +	regulator_desc_s2mps14_ldo2(17), +	regulator_desc_s2mps14_ldo2(18), +	regulator_desc_s2mps14_ldo1(19), +	regulator_desc_s2mps14_ldo1(20), +	regulator_desc_s2mps14_ldo1(21), +	regulator_desc_s2mps14_ldo3(22), +	regulator_desc_s2mps14_ldo1(23), +	regulator_desc_s2mps14_ldo2(24), +	regulator_desc_s2mps14_ldo2(25), +	regulator_desc_s2mps14_buck1235(1), +	regulator_desc_s2mps14_buck1235(2), +	regulator_desc_s2mps14_buck1235(3), +	regulator_desc_s2mps14_buck4(4), +	regulator_desc_s2mps14_buck1235(5),  }; +static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11, +		struct regulator_dev *rdev) +{ +	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, +			rdev->desc->enable_mask, S2MPS14_ENABLE_EXT_CONTROL); +} + +static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev, +		struct of_regulator_match *rdata, struct s2mps11_info *s2mps11) +{ +	int *gpio = s2mps11->ext_control_gpio; +	unsigned int i; +	unsigned int valid_regulators[3] = { S2MPS14_LDO10, S2MPS14_LDO11, +		S2MPS14_LDO12 }; + +	for (i = 0; i < ARRAY_SIZE(valid_regulators); i++) { +		unsigned int reg = valid_regulators[i]; + +		if (!rdata[reg].init_data || !rdata[reg].of_node) +			continue; + +		gpio[reg] = of_get_named_gpio(rdata[reg].of_node, +				"samsung,ext-control-gpios", 0); +		if (gpio_is_valid(gpio[reg])) +			dev_dbg(&pdev->dev, "Using GPIO %d for ext-control over %d/%s\n", +					gpio[reg], reg, rdata[reg].name); +	} +} + +static int s2mps11_pmic_dt_parse(struct platform_device *pdev, +		struct of_regulator_match *rdata, struct s2mps11_info *s2mps11, +		enum sec_device_type dev_type) +{ +	struct device_node *reg_np; + +	reg_np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); +	if (!reg_np) { +		dev_err(&pdev->dev, "could not find regulators sub-node\n"); +		return -EINVAL; +	} + +	of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num); +	if (dev_type == S2MPS14X) +		s2mps14_pmic_dt_parse_ext_control_gpio(pdev, rdata, s2mps11); + +	of_node_put(reg_np); + +	return 0; +} +  static int s2mps11_pmic_probe(struct platform_device *pdev)  {  	struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); -	struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); -	struct of_regulator_match rdata[S2MPS11_REGULATOR_MAX]; -	struct device_node *reg_np = NULL; +	struct sec_platform_data *pdata = NULL; +	struct of_regulator_match *rdata = NULL;  	struct regulator_config config = { };  	struct s2mps11_info *s2mps11; -	int i, ret; +	int i, ret = 0; +	const struct regulator_desc *regulators; +	enum sec_device_type dev_type;  	s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info),  				GFP_KERNEL);  	if (!s2mps11)  		return -ENOMEM; +	dev_type = platform_get_device_id(pdev)->driver_data; +	switch (dev_type) { +	case S2MPS11X: +		s2mps11->rdev_num = ARRAY_SIZE(s2mps11_regulators); +		regulators = s2mps11_regulators; +		break; +	case S2MPS14X: +		s2mps11->rdev_num = ARRAY_SIZE(s2mps14_regulators); +		regulators = s2mps14_regulators; +		break; +	default: +		dev_err(&pdev->dev, "Invalid device type: %u\n", dev_type); +		return -EINVAL; +	}; + +	s2mps11->ext_control_gpio = devm_kzalloc(&pdev->dev, +			sizeof(*s2mps11->ext_control_gpio) * s2mps11->rdev_num, +			GFP_KERNEL); +	if (!s2mps11->ext_control_gpio) +		return -ENOMEM; +	/* +	 * 0 is a valid GPIO so initialize all GPIO-s to negative value +	 * to indicate that external control won't be used for this regulator. +	 */ +	for (i = 0; i < s2mps11->rdev_num; i++) +		s2mps11->ext_control_gpio[i] = -EINVAL; +  	if (!iodev->dev->of_node) { -		if (pdata) { +		if (iodev->pdata) { +			pdata = iodev->pdata;  			goto common_reg;  		} else {  			dev_err(pdev->dev.parent, @@ -423,62 +679,66 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)  		}  	} -	for (i = 0; i < S2MPS11_REGULATOR_CNT; i++) -		rdata[i].name = regulators[i].name; +	rdata = kzalloc(sizeof(*rdata) * s2mps11->rdev_num, GFP_KERNEL); +	if (!rdata) +		return -ENOMEM; -	reg_np = of_find_node_by_name(iodev->dev->of_node, "regulators"); -	if (!reg_np) { -		dev_err(&pdev->dev, "could not find regulators sub-node\n"); -		return -EINVAL; -	} +	for (i = 0; i < s2mps11->rdev_num; i++) +		rdata[i].name = regulators[i].name; -	of_regulator_match(&pdev->dev, reg_np, rdata, S2MPS11_REGULATOR_MAX); +	ret = s2mps11_pmic_dt_parse(pdev, rdata, s2mps11, dev_type); +	if (ret) +		goto out;  common_reg:  	platform_set_drvdata(pdev, s2mps11);  	config.dev = &pdev->dev; -	config.regmap = iodev->regmap; +	config.regmap = iodev->regmap_pmic;  	config.driver_data = s2mps11; -	for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) { -		if (!reg_np) { +	config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH; +	for (i = 0; i < s2mps11->rdev_num; i++) { +		struct regulator_dev *regulator; + +		if (pdata) {  			config.init_data = pdata->regulators[i].initdata; +			config.of_node = pdata->regulators[i].reg_node;  		} else {  			config.init_data = rdata[i].init_data;  			config.of_node = rdata[i].of_node;  		} +		config.ena_gpio = s2mps11->ext_control_gpio[i]; -		s2mps11->rdev[i] = regulator_register(®ulators[i], &config); -		if (IS_ERR(s2mps11->rdev[i])) { -			ret = PTR_ERR(s2mps11->rdev[i]); +		regulator = devm_regulator_register(&pdev->dev, +						®ulators[i], &config); +		if (IS_ERR(regulator)) { +			ret = PTR_ERR(regulator);  			dev_err(&pdev->dev, "regulator init failed for %d\n",  				i); -			s2mps11->rdev[i] = NULL; -			goto err; +			goto out; +		} + +		if (gpio_is_valid(s2mps11->ext_control_gpio[i])) { +			ret = s2mps14_pmic_enable_ext_control(s2mps11, +					regulator); +			if (ret < 0) { +				dev_err(&pdev->dev, +						"failed to enable GPIO control over %s: %d\n", +						regulator->desc->name, ret); +				goto out; +			}  		}  	} -	return 0; -err: -	for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) -		regulator_unregister(s2mps11->rdev[i]); +out: +	kfree(rdata);  	return ret;  } -static int s2mps11_pmic_remove(struct platform_device *pdev) -{ -	struct s2mps11_info *s2mps11 = platform_get_drvdata(pdev); -	int i; - -	for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) -		regulator_unregister(s2mps11->rdev[i]); - -	return 0; -} -  static const struct platform_device_id s2mps11_pmic_id[] = { -	{ "s2mps11-pmic", 0}, +	{ "s2mps11-pmic", S2MPS11X}, +	{ "s2mps14-pmic", S2MPS14X},  	{ },  };  MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id); @@ -489,7 +749,6 @@ static struct platform_driver s2mps11_pmic_driver = {  		.owner = THIS_MODULE,  	},  	.probe = s2mps11_pmic_probe, -	.remove = s2mps11_pmic_remove,  	.id_table = s2mps11_pmic_id,  }; @@ -507,5 +766,5 @@ module_exit(s2mps11_pmic_exit);  /* Module information */  MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); -MODULE_DESCRIPTION("SAMSUNG S2MPS11 Regulator Driver"); +MODULE_DESCRIPTION("SAMSUNG S2MPS11/S2MPS14 Regulator Driver");  MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index c24448bc43c..c79af943a5c 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -11,11 +11,8 @@   *   */ -#include <linux/bug.h>  #include <linux/err.h> -#include <linux/gpio.h>  #include <linux/of_gpio.h> -#include <linux/slab.h>  #include <linux/module.h>  #include <linux/platform_device.h>  #include <linux/regulator/driver.h> @@ -23,6 +20,7 @@  #include <linux/mfd/samsung/core.h>  #include <linux/mfd/samsung/s5m8767.h>  #include <linux/regulator/of_regulator.h> +#include <linux/regmap.h>  #define S5M8767_OPMODE_NORMAL_MODE 0x1 @@ -30,7 +28,6 @@ struct s5m8767_info {  	struct device *dev;  	struct sec_pmic_dev *iodev;  	int num_regulators; -	struct regulator_dev **rdev;  	struct sec_opmode_data *opmode;  	int ramp_delay; @@ -120,8 +117,8 @@ static const struct sec_voltage_desc *reg_voltage_map[] = {  	[S5M8767_BUCK4] = &buck_voltage_val2,  	[S5M8767_BUCK5] = &buck_voltage_val1,  	[S5M8767_BUCK6] = &buck_voltage_val1, -	[S5M8767_BUCK7] = NULL, -	[S5M8767_BUCK8] = NULL, +	[S5M8767_BUCK7] = &buck_voltage_val3, +	[S5M8767_BUCK8] = &buck_voltage_val3,  	[S5M8767_BUCK9] = &buck_voltage_val3,  }; @@ -169,12 +166,11 @@ static unsigned int s5m8767_opmode_reg[][4] = {  	{0x0, 0x3, 0x1, 0x1}, /* BUCK9 */  }; -static int s5m8767_get_register(struct regulator_dev *rdev, int *reg, -				int *enable_ctrl) +static int s5m8767_get_register(struct s5m8767_info *s5m8767, int reg_id, +				int *reg, int *enable_ctrl)  { -	int i, reg_id = rdev_get_id(rdev); +	int i;  	unsigned int mode; -	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);  	switch (reg_id) {  	case S5M8767_LDO1 ... S5M8767_LDO2: @@ -213,52 +209,6 @@ static int s5m8767_get_register(struct regulator_dev *rdev, int *reg,  	return 0;  } -static int s5m8767_reg_is_enabled(struct regulator_dev *rdev) -{ -	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); -	int ret, reg; -	int mask = 0xc0, enable_ctrl; -	unsigned int val; - -	ret = s5m8767_get_register(rdev, ®, &enable_ctrl); -	if (ret == -EINVAL) -		return 1; -	else if (ret) -		return ret; - -	ret = sec_reg_read(s5m8767->iodev, reg, &val); -	if (ret) -		return ret; - -	return (val & mask) == enable_ctrl; -} - -static int s5m8767_reg_enable(struct regulator_dev *rdev) -{ -	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); -	int ret, reg; -	int mask = 0xc0, enable_ctrl; - -	ret = s5m8767_get_register(rdev, ®, &enable_ctrl); -	if (ret) -		return ret; - -	return sec_reg_update(s5m8767->iodev, reg, enable_ctrl, mask); -} - -static int s5m8767_reg_disable(struct regulator_dev *rdev) -{ -	struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); -	int ret, reg; -	int  mask = 0xc0, enable_ctrl; - -	ret = s5m8767_get_register(rdev, ®, &enable_ctrl); -	if (ret) -		return ret; - -	return sec_reg_update(s5m8767->iodev, reg, ~mask, mask); -} -  static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767)  {  	int reg; @@ -408,18 +358,21 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,  static struct regulator_ops s5m8767_ops = {  	.list_voltage		= regulator_list_voltage_linear, -	.is_enabled		= s5m8767_reg_is_enabled, -	.enable			= s5m8767_reg_enable, -	.disable		= s5m8767_reg_disable, +	.is_enabled		= regulator_is_enabled_regmap, +	.enable			= regulator_enable_regmap, +	.disable		= regulator_disable_regmap,  	.get_voltage_sel	= regulator_get_voltage_sel_regmap,  	.set_voltage_sel	= s5m8767_set_voltage_sel,  	.set_voltage_time_sel	= s5m8767_set_voltage_time_sel,  };  static struct regulator_ops s5m8767_buck78_ops = { -	.is_enabled		= s5m8767_reg_is_enabled, -	.enable			= s5m8767_reg_enable, -	.disable		= s5m8767_reg_disable, +	.list_voltage		= regulator_list_voltage_linear, +	.is_enabled		= regulator_is_enabled_regmap, +	.enable			= regulator_enable_regmap, +	.disable		= regulator_disable_regmap, +	.get_voltage_sel	= regulator_get_voltage_sel_regmap, +	.set_voltage_sel	= regulator_set_voltage_sel_regmap,  };  #define s5m8767_regulator_desc(_name) {		\ @@ -478,6 +431,66 @@ static struct regulator_desc regulators[] = {  	s5m8767_regulator_desc(BUCK9),  }; +/* + * Enable GPIO control over BUCK9 in regulator_config for that regulator. + */ +static void s5m8767_regulator_config_ext_control(struct s5m8767_info *s5m8767, +		struct sec_regulator_data *rdata, +		struct regulator_config *config) +{ +	int i, mode = 0; + +	if (rdata->id != S5M8767_BUCK9) +		return; + +	/* Check if opmode for regulator matches S5M8767_ENCTRL_USE_GPIO */ +	for (i = 0; i < s5m8767->num_regulators; i++) { +		const struct sec_opmode_data *opmode = &s5m8767->opmode[i]; +		if (opmode->id == rdata->id) { +			mode = s5m8767_opmode_reg[rdata->id][opmode->mode]; +			break; +		} +	} +	if (mode != S5M8767_ENCTRL_USE_GPIO) { +		dev_warn(s5m8767->dev, +				"ext-control for %s: mismatched op_mode (%x), ignoring\n", +				rdata->reg_node->name, mode); +		return; +	} + +	if (!gpio_is_valid(rdata->ext_control_gpio)) { +		dev_warn(s5m8767->dev, +				"ext-control for %s: GPIO not valid, ignoring\n", +				rdata->reg_node->name); +		return; +	} + +	config->ena_gpio = rdata->ext_control_gpio; +	config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH; +} + +/* + * Turn on GPIO control over BUCK9. + */ +static int s5m8767_enable_ext_control(struct s5m8767_info *s5m8767, +		struct regulator_dev *rdev) +{ +	int id = rdev_get_id(rdev); +	int ret, reg, enable_ctrl; + +	if (id != S5M8767_BUCK9) +		return -EINVAL; + +	ret = s5m8767_get_register(s5m8767, id, ®, &enable_ctrl); +	if (ret) +		return ret; + +	return regmap_update_bits(s5m8767->iodev->regmap_pmic, +			reg, S5M8767_ENCTRL_MASK, +			S5M8767_ENCTRL_USE_GPIO << S5M8767_ENCTRL_SHIFT); +} + +  #ifdef CONFIG_OF  static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev,  			struct sec_platform_data *pdata, @@ -522,7 +535,7 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,  	struct device_node *pmic_np, *regulators_np, *reg_np;  	struct sec_regulator_data *rdata;  	struct sec_opmode_data *rmode; -	unsigned int i, dvs_voltage_nr = 1, ret; +	unsigned int i, dvs_voltage_nr = 8, ret;  	pmic_np = iodev->dev->of_node;  	if (!pmic_np) { @@ -530,7 +543,7 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,  		return -ENODEV;  	} -	regulators_np = of_find_node_by_name(pmic_np, "regulators"); +	regulators_np = of_get_child_by_name(pmic_np, "regulators");  	if (!regulators_np) {  		dev_err(iodev->dev, "could not find regulators sub-node\n");  		return -EINVAL; @@ -541,19 +554,13 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,  	rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *  				pdata->num_regulators, GFP_KERNEL); -	if (!rdata) { -		dev_err(iodev->dev, -			"could not allocate memory for regulator data\n"); +	if (!rdata)  		return -ENOMEM; -	}  	rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) *  				pdata->num_regulators, GFP_KERNEL); -	if (!rmode) { -		dev_err(iodev->dev, -			"could not allocate memory for regulator mode\n"); +	if (!rmode)  		return -ENOMEM; -	}  	pdata->regulators = rdata;  	pdata->opmode = rmode; @@ -569,6 +576,9 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,  			continue;  		} +		rdata->ext_control_gpio = of_get_named_gpio(reg_np, +			"s5m8767,pmic-ext-control-gpios", 0); +  		rdata->id = i;  		rdata->initdata = of_get_regulator_init_data(  						&pdev->dev, reg_np); @@ -586,15 +596,41 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,  		rmode++;  	} -	if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) +	of_node_put(regulators_np); + +	if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) {  		pdata->buck2_gpiodvs = true; -	if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL)) +		if (of_property_read_u32_array(pmic_np, +				"s5m8767,pmic-buck2-dvs-voltage", +				pdata->buck2_voltage, dvs_voltage_nr)) { +			dev_err(iodev->dev, "buck2 voltages not specified\n"); +			return -EINVAL; +		} +	} + +	if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL)) {  		pdata->buck3_gpiodvs = true; -	if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL)) +		if (of_property_read_u32_array(pmic_np, +				"s5m8767,pmic-buck3-dvs-voltage", +				pdata->buck3_voltage, dvs_voltage_nr)) { +			dev_err(iodev->dev, "buck3 voltages not specified\n"); +			return -EINVAL; +		} +	} + +	if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL)) {  		pdata->buck4_gpiodvs = true; +		if (of_property_read_u32_array(pmic_np, +				"s5m8767,pmic-buck4-dvs-voltage", +				pdata->buck4_voltage, dvs_voltage_nr)) { +			dev_err(iodev->dev, "buck4 voltages not specified\n"); +			return -EINVAL; +		} +	} +  	if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||  						pdata->buck4_gpiodvs) {  		ret = s5m8767_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np); @@ -612,32 +648,26 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,  				"invalid value for default dvs index, use 0\n");  			}  		} -		dvs_voltage_nr = 8;  	}  	ret = s5m8767_pmic_dt_parse_ds_gpio(iodev, pdata, pmic_np);  	if (ret)  		return -EINVAL; -	if (of_property_read_u32_array(pmic_np, -				"s5m8767,pmic-buck2-dvs-voltage", -				pdata->buck2_voltage, dvs_voltage_nr)) { -		dev_err(iodev->dev, "buck2 voltages not specified\n"); -		return -EINVAL; -	} +	if (of_get_property(pmic_np, "s5m8767,pmic-buck2-ramp-enable", NULL)) +		pdata->buck2_ramp_enable = true; -	if (of_property_read_u32_array(pmic_np, -				"s5m8767,pmic-buck3-dvs-voltage", -				pdata->buck3_voltage, dvs_voltage_nr)) { -		dev_err(iodev->dev, "buck3 voltages not specified\n"); -		return -EINVAL; -	} +	if (of_get_property(pmic_np, "s5m8767,pmic-buck3-ramp-enable", NULL)) +		pdata->buck3_ramp_enable = true; -	if (of_property_read_u32_array(pmic_np, -				"s5m8767,pmic-buck4-dvs-voltage", -				pdata->buck4_voltage, dvs_voltage_nr)) { -		dev_err(iodev->dev, "buck4 voltages not specified\n"); -		return -EINVAL; +	if (of_get_property(pmic_np, "s5m8767,pmic-buck4-ramp-enable", NULL)) +		pdata->buck4_ramp_enable = true; + +	if (pdata->buck2_ramp_enable || pdata->buck3_ramp_enable +			|| pdata->buck4_ramp_enable) { +		if (of_property_read_u32(pmic_np, "s5m8767,pmic-buck-ramp-delay", +				&pdata->buck_ramp_delay)) +			pdata->buck_ramp_delay = 0;  	}  	return 0; @@ -655,7 +685,6 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)  	struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);  	struct sec_platform_data *pdata = iodev->pdata;  	struct regulator_config config = { }; -	struct regulator_dev **rdev;  	struct s5m8767_info *s5m8767;  	int i, ret, size, buck_init; @@ -697,11 +726,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)  		return -ENOMEM;  	size = sizeof(struct regulator_dev *) * (S5M8767_REG_MAX - 2); -	s5m8767->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); -	if (!s5m8767->rdev) -		return -ENOMEM; -	rdev = s5m8767->rdev;  	s5m8767->dev = &pdev->dev;  	s5m8767->iodev = iodev;  	s5m8767->num_regulators = pdata->num_regulators; @@ -727,17 +752,20 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)  	buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,  						   pdata->buck2_init); -	sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init); +	regmap_write(s5m8767->iodev->regmap_pmic, S5M8767_REG_BUCK2DVS2, +			buck_init);  	buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,  						   pdata->buck3_init); -	sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init); +	regmap_write(s5m8767->iodev->regmap_pmic, S5M8767_REG_BUCK3DVS2, +			buck_init);  	buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,  						   pdata->buck4_init); -	sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init); +	regmap_write(s5m8767->iodev->regmap_pmic, S5M8767_REG_BUCK4DVS2, +			buck_init);  	for (i = 0; i < 8; i++) {  		if (s5m8767->buck2_gpiodvs) { @@ -819,76 +847,83 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)  	if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||  	   pdata->buck4_gpiodvs) { -		sec_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, -				(pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), -				1 << 1); -		sec_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, -				(pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), -				1 << 1); -		sec_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, -				(pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), -				1 << 1); +		regmap_update_bits(s5m8767->iodev->regmap_pmic, +				S5M8767_REG_BUCK2CTRL, 1 << 1, +				(pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1)); +		regmap_update_bits(s5m8767->iodev->regmap_pmic, +				S5M8767_REG_BUCK3CTRL, 1 << 1, +				(pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1)); +		regmap_update_bits(s5m8767->iodev->regmap_pmic, +				S5M8767_REG_BUCK4CTRL, 1 << 1, +				(pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1));  	}  	/* Initialize GPIO DVS registers */  	for (i = 0; i < 8; i++) {  		if (s5m8767->buck2_gpiodvs) { -			sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS1 + i, -					   s5m8767->buck2_vol[i]); +			regmap_write(s5m8767->iodev->regmap_pmic, +					S5M8767_REG_BUCK2DVS1 + i, +					s5m8767->buck2_vol[i]);  		}  		if (s5m8767->buck3_gpiodvs) { -			sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS1 + i, -					   s5m8767->buck3_vol[i]); +			regmap_write(s5m8767->iodev->regmap_pmic, +					S5M8767_REG_BUCK3DVS1 + i, +					s5m8767->buck3_vol[i]);  		}  		if (s5m8767->buck4_gpiodvs) { -			sec_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS1 + i, -					   s5m8767->buck4_vol[i]); +			regmap_write(s5m8767->iodev->regmap_pmic, +					S5M8767_REG_BUCK4DVS1 + i, +					s5m8767->buck4_vol[i]);  		}  	}  	if (s5m8767->buck2_ramp) -		sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x08, 0x08); +		regmap_update_bits(s5m8767->iodev->regmap_pmic, +				S5M8767_REG_DVSRAMP, 0x08, 0x08);  	if (s5m8767->buck3_ramp) -		sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x04, 0x04); +		regmap_update_bits(s5m8767->iodev->regmap_pmic, +				S5M8767_REG_DVSRAMP, 0x04, 0x04);  	if (s5m8767->buck4_ramp) -		sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x02, 0x02); +		regmap_update_bits(s5m8767->iodev->regmap_pmic, +				S5M8767_REG_DVSRAMP, 0x02, 0x02);  	if (s5m8767->buck2_ramp || s5m8767->buck3_ramp  		|| s5m8767->buck4_ramp) { +		unsigned int val;  		switch (s5m8767->ramp_delay) {  		case 5: -			sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, -					0x40, 0xf0); +			val = S5M8767_DVS_BUCK_RAMP_5;  			break;  		case 10: -			sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, -					0x90, 0xf0); +			val = S5M8767_DVS_BUCK_RAMP_10;  			break;  		case 25: -			sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, -					0xd0, 0xf0); +			val = S5M8767_DVS_BUCK_RAMP_25;  			break;  		case 50: -			sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, -					0xe0, 0xf0); +			val = S5M8767_DVS_BUCK_RAMP_50;  			break;  		case 100: -			sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, -					0xf0, 0xf0); +			val = S5M8767_DVS_BUCK_RAMP_100;  			break;  		default: -			sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, -					0x90, 0xf0); +			val = S5M8767_DVS_BUCK_RAMP_10;  		} +		regmap_update_bits(s5m8767->iodev->regmap_pmic, +					S5M8767_REG_DVSRAMP, +					S5M8767_DVS_BUCK_RAMP_MASK, +					val << S5M8767_DVS_BUCK_RAMP_SHIFT);  	}  	for (i = 0; i < pdata->num_regulators; i++) {  		const struct sec_voltage_desc *desc;  		int id = pdata->regulators[i].id; +		int enable_reg, enable_val; +		struct regulator_dev *rdev;  		desc = reg_voltage_map[id];  		if (desc) { @@ -902,40 +937,44 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)  				regulators[id].vsel_mask = 0x3f;  			else  				regulators[id].vsel_mask = 0xff; + +			s5m8767_get_register(s5m8767, id, &enable_reg, +					     &enable_val); +			regulators[id].enable_reg = enable_reg; +			regulators[id].enable_mask = S5M8767_ENCTRL_MASK; +			regulators[id].enable_val = enable_val;  		}  		config.dev = s5m8767->dev;  		config.init_data = pdata->regulators[i].initdata;  		config.driver_data = s5m8767; -		config.regmap = iodev->regmap; +		config.regmap = iodev->regmap_pmic;  		config.of_node = pdata->regulators[i].reg_node; - -		rdev[i] = regulator_register(®ulators[id], &config); -		if (IS_ERR(rdev[i])) { -			ret = PTR_ERR(rdev[i]); +		config.ena_gpio = -EINVAL; +		config.ena_gpio_flags = 0; +		if (gpio_is_valid(pdata->regulators[i].ext_control_gpio)) +			s5m8767_regulator_config_ext_control(s5m8767, +					&pdata->regulators[i], &config); + +		rdev = devm_regulator_register(&pdev->dev, ®ulators[id], +						  &config); +		if (IS_ERR(rdev)) { +			ret = PTR_ERR(rdev);  			dev_err(s5m8767->dev, "regulator init failed for %d\n",  					id); -			rdev[i] = NULL; -			goto err; +			return ret;  		} -	} - -	return 0; -err: -	for (i = 0; i < s5m8767->num_regulators; i++) -		regulator_unregister(rdev[i]); - -	return ret; -} -static int s5m8767_pmic_remove(struct platform_device *pdev) -{ -	struct s5m8767_info *s5m8767 = platform_get_drvdata(pdev); -	struct regulator_dev **rdev = s5m8767->rdev; -	int i; - -	for (i = 0; i < s5m8767->num_regulators; i++) -		regulator_unregister(rdev[i]); +		if (gpio_is_valid(pdata->regulators[i].ext_control_gpio)) { +			ret = s5m8767_enable_ext_control(s5m8767, rdev); +			if (ret < 0) { +				dev_err(s5m8767->dev, +						"failed to enable gpio control over %s: %d\n", +						rdev->desc->name, ret); +				return ret; +			} +		} +	}  	return 0;  } @@ -952,7 +991,6 @@ static struct platform_driver s5m8767_pmic_driver = {  		.owner = THIS_MODULE,  	},  	.probe = s5m8767_pmic_probe, -	.remove = s5m8767_pmic_remove,  	.id_table = s5m8767_pmic_id,  }; diff --git a/drivers/regulator/st-pwm.c b/drivers/regulator/st-pwm.c new file mode 100644 index 00000000000..5ea78df449f --- /dev/null +++ b/drivers/regulator/st-pwm.c @@ -0,0 +1,190 @@ +/* + * Regulator driver for ST's PWM Regulators + * + * Copyright (C) 2014 - STMicroelectronics Inc. + * + * Author: Lee Jones <lee.jones@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pwm.h> + +#define ST_PWM_REG_PERIOD 8448 + +struct st_pwm_regulator_pdata { +	const struct regulator_desc *desc; +	struct st_pwm_voltages *duty_cycle_table; +}; + +struct st_pwm_regulator_data { +	const struct st_pwm_regulator_pdata *pdata; +	struct pwm_device *pwm; +	bool enabled; +	int state; +}; + +struct st_pwm_voltages { +	unsigned int uV; +	unsigned int dutycycle; +}; + +static int st_pwm_regulator_get_voltage_sel(struct regulator_dev *dev) +{ +	struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev); + +	return drvdata->state; +} + +static int st_pwm_regulator_set_voltage_sel(struct regulator_dev *dev, +					    unsigned selector) +{ +	struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev); +	int dutycycle; +	int ret; + +	dutycycle = (ST_PWM_REG_PERIOD / 100) * +		drvdata->pdata->duty_cycle_table[selector].dutycycle; + +	ret = pwm_config(drvdata->pwm, dutycycle, ST_PWM_REG_PERIOD); +	if (ret) { +		dev_err(&dev->dev, "Failed to configure PWM\n"); +		return ret; +	} + +	drvdata->state = selector; + +	if (!drvdata->enabled) { +		ret = pwm_enable(drvdata->pwm); +		if (ret) { +			dev_err(&dev->dev, "Failed to enable PWM\n"); +			return ret; +		} +		drvdata->enabled = true; +	} + +	return 0; +} + +static int st_pwm_regulator_list_voltage(struct regulator_dev *dev, +					 unsigned selector) +{ +	struct st_pwm_regulator_data *drvdata = rdev_get_drvdata(dev); + +	if (selector >= dev->desc->n_voltages) +		return -EINVAL; + +	return drvdata->pdata->duty_cycle_table[selector].uV; +} + +static struct regulator_ops st_pwm_regulator_voltage_ops = { +	.set_voltage_sel = st_pwm_regulator_set_voltage_sel, +	.get_voltage_sel = st_pwm_regulator_get_voltage_sel, +	.list_voltage    = st_pwm_regulator_list_voltage, +	.map_voltage     = regulator_map_voltage_iterate, +}; + +static struct st_pwm_voltages b2105_duty_cycle_table[] = { +	{ .uV = 1114000, .dutycycle = 0,  }, +	{ .uV = 1095000, .dutycycle = 10, }, +	{ .uV = 1076000, .dutycycle = 20, }, +	{ .uV = 1056000, .dutycycle = 30, }, +	{ .uV = 1036000, .dutycycle = 40, }, +	{ .uV = 1016000, .dutycycle = 50, }, +	/* WARNING: Values above 50% duty-cycle cause boot failures. */ +}; + +static const struct regulator_desc b2105_desc = { +	.name		= "b2105-pwm-regulator", +	.ops		= &st_pwm_regulator_voltage_ops, +	.type		= REGULATOR_VOLTAGE, +	.owner		= THIS_MODULE, +	.n_voltages	= ARRAY_SIZE(b2105_duty_cycle_table), +	.supply_name    = "pwm", +}; + +static const struct st_pwm_regulator_pdata b2105_info = { +	.desc		  = &b2105_desc, +	.duty_cycle_table = b2105_duty_cycle_table, +}; + +static const struct of_device_id st_pwm_of_match[] = { +	{ .compatible = "st,b2105-pwm-regulator", .data = &b2105_info, }, +	{ }, +}; +MODULE_DEVICE_TABLE(of, st_pwm_of_match); + +static int st_pwm_regulator_probe(struct platform_device *pdev) +{ +	struct st_pwm_regulator_data *drvdata; +	struct regulator_dev *regulator; +	struct regulator_config config = { }; +	struct device_node *np = pdev->dev.of_node; +	const struct of_device_id *of_match; + +	if (!np) { +		dev_err(&pdev->dev, "Device Tree node missing\n"); +		return -EINVAL; +	} + +	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); +	if (!drvdata) +		return -ENOMEM; + +	of_match = of_match_device(st_pwm_of_match, &pdev->dev); +	if (!of_match) { +		dev_err(&pdev->dev, "failed to match of device\n"); +		return -ENODEV; +	} +	drvdata->pdata = of_match->data; + +	config.init_data = of_get_regulator_init_data(&pdev->dev, np); +	if (!config.init_data) +		return -ENOMEM; + +	config.of_node = np; +	config.dev = &pdev->dev; +	config.driver_data = drvdata; + +	drvdata->pwm = devm_pwm_get(&pdev->dev, NULL); +	if (IS_ERR(drvdata->pwm)) { +		dev_err(&pdev->dev, "Failed to get PWM\n"); +		return PTR_ERR(drvdata->pwm); +	} + +	regulator = devm_regulator_register(&pdev->dev, +					    drvdata->pdata->desc, &config); +	if (IS_ERR(regulator)) { +		dev_err(&pdev->dev, "Failed to register regulator %s\n", +			drvdata->pdata->desc->name); +		return PTR_ERR(regulator); +	} + +	return 0; +} + +static struct platform_driver st_pwm_regulator_driver = { +	.driver = { +		.name		= "st-pwm-regulator", +		.owner		= THIS_MODULE, +		.of_match_table = of_match_ptr(st_pwm_of_match), +	}, +	.probe = st_pwm_regulator_probe, +}; + +module_platform_driver(st_pwm_regulator_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>"); +MODULE_DESCRIPTION("ST PWM Regulator Driver"); +MODULE_ALIAS("platform:st_pwm-regulator"); diff --git a/drivers/regulator/stw481x-vmmc.c b/drivers/regulator/stw481x-vmmc.c new file mode 100644 index 00000000000..a7e152696a0 --- /dev/null +++ b/drivers/regulator/stw481x-vmmc.c @@ -0,0 +1,103 @@ +/* + * Regulator driver for STw4810/STw4811 VMMC regulator. + * + * Copyright (C) 2013 ST-Ericsson SA + * Written on behalf of Linaro for ST-Ericsson + * + * Author: Linus Walleij <linus.walleij@linaro.org> + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/err.h> +#include <linux/init.h> +#include <linux/mfd/stw481x.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> + +static const unsigned int stw481x_vmmc_voltages[] = { +	1800000, +	1800000, +	2850000, +	3000000, +	1850000, +	2600000, +	2700000, +	3300000, +}; + +static struct regulator_ops stw481x_vmmc_ops = { +	.list_voltage = regulator_list_voltage_table, +	.enable      = regulator_enable_regmap, +	.disable     = regulator_disable_regmap, +	.is_enabled  = regulator_is_enabled_regmap, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, +	.set_voltage_sel = regulator_set_voltage_sel_regmap, +}; + +static struct regulator_desc vmmc_regulator = { +	.name = "VMMC", +	.id   = 0, +	.ops  = &stw481x_vmmc_ops, +	.type = REGULATOR_VOLTAGE, +	.owner = THIS_MODULE, +	.n_voltages = ARRAY_SIZE(stw481x_vmmc_voltages), +	.volt_table = stw481x_vmmc_voltages, +	.enable_time = 200, /* FIXME: look this up */ +	.enable_reg = STW_CONF1, +	.enable_mask = STW_CONF1_PDN_VMMC, +	.vsel_reg = STW_CONF1, +	.vsel_mask = STW_CONF1_VMMC_MASK, +}; + +static int stw481x_vmmc_regulator_probe(struct platform_device *pdev) +{ +	struct stw481x *stw481x = dev_get_platdata(&pdev->dev); +	struct regulator_config config = { }; +	int ret; + +	/* First disable the external VMMC if it's active */ +	ret = regmap_update_bits(stw481x->map, STW_CONF2, +				 STW_CONF2_VMMC_EXT, 0); +	if (ret) { +		dev_err(&pdev->dev, "could not disable external VMMC\n"); +		return ret; +	} + +	/* Register VMMC regulator */ +	config.dev = &pdev->dev; +	config.driver_data = stw481x; +	config.regmap = stw481x->map; +	config.of_node = pdev->dev.of_node; +	config.init_data = of_get_regulator_init_data(&pdev->dev, +						      pdev->dev.of_node); + +	stw481x->vmmc_regulator = devm_regulator_register(&pdev->dev, +						&vmmc_regulator, &config); +	if (IS_ERR(stw481x->vmmc_regulator)) { +		dev_err(&pdev->dev, +			"error initializing STw481x VMMC regulator\n"); +		return PTR_ERR(stw481x->vmmc_regulator); +	} + +	dev_info(&pdev->dev, "initialized STw481x VMMC regulator\n"); +	return 0; +} + +static const struct of_device_id stw481x_vmmc_match[] = { +	{ .compatible = "st,stw481x-vmmc", }, +	{}, +}; + +static struct platform_driver stw481x_vmmc_regulator_driver = { +	.driver = { +		.name  = "stw481x-vmmc-regulator", +		.owner = THIS_MODULE, +		.of_match_table = stw481x_vmmc_match, +	}, +	.probe = stw481x_vmmc_regulator_probe, +}; + +module_platform_driver(stw481x_vmmc_regulator_driver); diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c index d8e3e1262bc..a2dabb575b9 100644 --- a/drivers/regulator/ti-abb-regulator.c +++ b/drivers/regulator/ti-abb-regulator.c @@ -54,8 +54,8 @@ struct ti_abb_info {  /**   * struct ti_abb_reg - Register description for ABB block - * @setup_reg:			setup register offset from base - * @control_reg:		control register offset from base + * @setup_off:			setup register offset from base + * @control_off:		control register offset from base   * @sr2_wtcnt_value_mask:	setup register- sr2_wtcnt_value mask   * @fbb_sel_mask:		setup register- FBB sel mask   * @rbb_sel_mask:		setup register- RBB sel mask @@ -64,8 +64,8 @@ struct ti_abb_info {   * @opp_sel_mask:		control register - mask for mode to operate   */  struct ti_abb_reg { -	u32 setup_reg; -	u32 control_reg; +	u32 setup_off; +	u32 control_off;  	/* Setup register fields */  	u32 sr2_wtcnt_value_mask; @@ -83,6 +83,8 @@ struct ti_abb_reg {   * @rdesc:			regulator descriptor   * @clk:			clock(usually sysclk) supplying ABB block   * @base:			base address of ABB block + * @setup_reg:			setup register of ABB block + * @control_reg:		control register of ABB block   * @int_base:			interrupt register base address   * @efuse_base:			(optional) efuse base address for ABB modes   * @ldo_base:			(optional) LDOVBB vset override base address @@ -99,6 +101,8 @@ struct ti_abb {  	struct regulator_desc rdesc;  	struct clk *clk;  	void __iomem *base; +	void __iomem *setup_reg; +	void __iomem *control_reg;  	void __iomem *int_base;  	void __iomem *efuse_base;  	void __iomem *ldo_base; @@ -118,20 +122,18 @@ struct ti_abb {   * ti_abb_rmw() - handy wrapper to set specific register bits   * @mask:	mask for register field   * @value:	value shifted to mask location and written - * @offset:	offset of register - * @base:	base address + * @reg:	register address   *   * Return: final register value (may be unused)   */ -static inline u32 ti_abb_rmw(u32 mask, u32 value, u32 offset, -			     void __iomem *base) +static inline u32 ti_abb_rmw(u32 mask, u32 value, void __iomem *reg)  {  	u32 val; -	val = readl(base + offset); +	val = readl(reg);  	val &= ~mask;  	val |= (value << __ffs(mask)) & mask; -	writel(val, base + offset); +	writel(val, reg);  	return val;  } @@ -263,28 +265,30 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb,  	if (ret)  		goto out; -	ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, regs->setup_reg, -		   abb->base); +	ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, abb->setup_reg);  	switch (info->opp_sel) {  	case TI_ABB_SLOW_OPP: -		ti_abb_rmw(regs->rbb_sel_mask, 1, regs->setup_reg, abb->base); +		ti_abb_rmw(regs->rbb_sel_mask, 1, abb->setup_reg);  		break;  	case TI_ABB_FAST_OPP: -		ti_abb_rmw(regs->fbb_sel_mask, 1, regs->setup_reg, abb->base); +		ti_abb_rmw(regs->fbb_sel_mask, 1, abb->setup_reg);  		break;  	}  	/* program next state of ABB ldo */ -	ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, regs->control_reg, -		   abb->base); +	ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, abb->control_reg); -	/* program LDO VBB vset override if needed */ -	if (abb->ldo_base) +	/* +	 * program LDO VBB vset override if needed for !bypass mode +	 * XXX: Do not switch sequence - for !bypass, LDO override reset *must* +	 * be performed *before* switch to bias mode else VBB glitches. +	 */ +	if (abb->ldo_base && info->opp_sel != TI_ABB_NOMINAL_OPP)  		ti_abb_program_ldovbb(dev, abb, info);  	/* Initiate ABB ldo change */ -	ti_abb_rmw(regs->opp_change_mask, 1, regs->control_reg, abb->base); +	ti_abb_rmw(regs->opp_change_mask, 1, abb->control_reg);  	/* Wait for ABB LDO to complete transition to new Bias setting */  	ret = ti_abb_wait_txdone(dev, abb); @@ -295,6 +299,14 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb,  	if (ret)  		goto out; +	/* +	 * Reset LDO VBB vset override bypass mode +	 * XXX: Do not switch sequence - for bypass, LDO override reset *must* +	 * be performed *after* switch to bypass else VBB glitches. +	 */ +	if (abb->ldo_base && info->opp_sel == TI_ABB_NOMINAL_OPP) +		ti_abb_program_ldovbb(dev, abb, info); +  out:  	return ret;  } @@ -478,8 +490,7 @@ static int ti_abb_init_timings(struct device *dev, struct ti_abb *abb)  	dev_dbg(dev, "%s: Clk_rate=%ld, sr2_cnt=0x%08x\n", __func__,  		clk_get_rate(abb->clk), sr2_wt_cnt_val); -	ti_abb_rmw(regs->sr2_wtcnt_value_mask, sr2_wt_cnt_val, regs->setup_reg, -		   abb->base); +	ti_abb_rmw(regs->sr2_wtcnt_value_mask, sr2_wt_cnt_val, abb->setup_reg);  	return 0;  } @@ -496,32 +507,24 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb,  			     struct regulator_init_data *rinit_data)  {  	struct ti_abb_info *info; -	const struct property *prop; -	const __be32 *abb_info;  	const u32 num_values = 6;  	char *pname = "ti,abb_info"; -	u32 num_entries, i; +	u32 i;  	unsigned int *volt_table; -	int min_uV = INT_MAX, max_uV = 0; +	int num_entries, min_uV = INT_MAX, max_uV = 0;  	struct regulation_constraints *c = &rinit_data->constraints; -	prop = of_find_property(dev->of_node, pname, NULL); -	if (!prop) { -		dev_err(dev, "No '%s' property?\n", pname); -		return -ENODEV; -	} - -	if (!prop->value) { -		dev_err(dev, "Empty '%s' property?\n", pname); -		return -ENODATA; -	} -  	/*  	 * Each abb_info is a set of n-tuple, where n is num_values, consisting  	 * of voltage and a set of detection logic for ABB information for that  	 * voltage to apply.  	 */ -	num_entries = prop->length / sizeof(u32); +	num_entries = of_property_count_u32_elems(dev->of_node, pname); +	if (num_entries < 0) { +		dev_err(dev, "No '%s' property?\n", pname); +		return num_entries; +	} +  	if (!num_entries || (num_entries % num_values)) {  		dev_err(dev, "All '%s' list entries need %d vals\n", pname,  			num_values); @@ -530,38 +533,38 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb,  	num_entries /= num_values;  	info = devm_kzalloc(dev, sizeof(*info) * num_entries, GFP_KERNEL); -	if (!info) { -		dev_err(dev, "Can't allocate info table for '%s' property\n", -			pname); +	if (!info)  		return -ENOMEM; -	} +  	abb->info = info;  	volt_table = devm_kzalloc(dev, sizeof(unsigned int) * num_entries,  				  GFP_KERNEL); -	if (!volt_table) { -		dev_err(dev, "Can't allocate voltage table for '%s' property\n", -			pname); +	if (!volt_table)  		return -ENOMEM; -	}  	abb->rdesc.n_voltages = num_entries;  	abb->rdesc.volt_table = volt_table;  	/* We do not know where the OPP voltage is at the moment */  	abb->current_info_idx = -EINVAL; -	abb_info = prop->value;  	for (i = 0; i < num_entries; i++, info++, volt_table++) {  		u32 efuse_offset, rbb_mask, fbb_mask, vset_mask;  		u32 efuse_val;  		/* NOTE: num_values should equal to entries picked up here */ -		*volt_table = be32_to_cpup(abb_info++); -		info->opp_sel = be32_to_cpup(abb_info++); -		efuse_offset = be32_to_cpup(abb_info++); -		rbb_mask = be32_to_cpup(abb_info++); -		fbb_mask = be32_to_cpup(abb_info++); -		vset_mask = be32_to_cpup(abb_info++); +		of_property_read_u32_index(dev->of_node, pname, i * num_values, +					   volt_table); +		of_property_read_u32_index(dev->of_node, pname, +					   i * num_values + 1, &info->opp_sel); +		of_property_read_u32_index(dev->of_node, pname, +					   i * num_values + 2, &efuse_offset); +		of_property_read_u32_index(dev->of_node, pname, +					   i * num_values + 3, &rbb_mask); +		of_property_read_u32_index(dev->of_node, pname, +					   i * num_values + 4, &fbb_mask); +		of_property_read_u32_index(dev->of_node, pname, +					   i * num_values + 5, &vset_mask);  		dev_dbg(dev,  			"[%d]v=%d ABB=%d ef=0x%x rbb=0x%x fbb=0x%x vset=0x%x\n", @@ -603,7 +606,7 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb,  					pname, *volt_table, vset_mask);  			continue;  		} -		info->vset = efuse_val & vset_mask >> __ffs(vset_mask); +		info->vset = (efuse_val & vset_mask) >> __ffs(vset_mask);  		dev_dbg(dev, "[%d]v=%d vset=%x\n", i, *volt_table, info->vset);  check_abb:  		switch (info->opp_sel) { @@ -636,8 +639,8 @@ static struct regulator_ops ti_abb_reg_ops = {  /* Default ABB block offsets, IF this changes in future, create new one */  static const struct ti_abb_reg abb_regs_v1 = {  	/* WARNING: registers are wrongly documented in TRM */ -	.setup_reg		= 0x04, -	.control_reg		= 0x00, +	.setup_off		= 0x04, +	.control_off		= 0x00,  	.sr2_wtcnt_value_mask	= (0xff << 8),  	.fbb_sel_mask		= (0x01 << 2), @@ -649,9 +652,19 @@ static const struct ti_abb_reg abb_regs_v1 = {  };  static const struct ti_abb_reg abb_regs_v2 = { -	.setup_reg		= 0x00, -	.control_reg		= 0x04, +	.setup_off		= 0x00, +	.control_off		= 0x04, + +	.sr2_wtcnt_value_mask	= (0xff << 8), +	.fbb_sel_mask		= (0x01 << 2), +	.rbb_sel_mask		= (0x01 << 1), +	.sr2_en_mask		= (0x01 << 0), + +	.opp_change_mask	= (0x01 << 2), +	.opp_sel_mask		= (0x03 << 0), +}; +static const struct ti_abb_reg abb_regs_generic = {  	.sr2_wtcnt_value_mask	= (0xff << 8),  	.fbb_sel_mask		= (0x01 << 2),  	.rbb_sel_mask		= (0x01 << 1), @@ -664,6 +677,7 @@ static const struct ti_abb_reg abb_regs_v2 = {  static const struct of_device_id ti_abb_of_match[] = {  	{.compatible = "ti,abb-v1", .data = &abb_regs_v1},  	{.compatible = "ti,abb-v2", .data = &abb_regs_v2}, +	{.compatible = "ti,abb-v3", .data = &abb_regs_generic},  	{ },  }; @@ -696,39 +710,49 @@ static int ti_abb_probe(struct platform_device *pdev)  	match = of_match_device(ti_abb_of_match, dev);  	if (!match) {  		/* We do not expect this to happen */ -		ret = -ENODEV;  		dev_err(dev, "%s: Unable to match device\n", __func__); -		goto err; +		return -ENODEV;  	}  	if (!match->data) { -		ret = -EINVAL;  		dev_err(dev, "%s: Bad data in match\n", __func__); -		goto err; +		return -EINVAL;  	}  	abb = devm_kzalloc(dev, sizeof(struct ti_abb), GFP_KERNEL); -	if (!abb) { -		dev_err(dev, "%s: Unable to allocate ABB struct\n", __func__); -		ret = -ENOMEM; -		goto err; -	} +	if (!abb) +		return -ENOMEM;  	abb->regs = match->data;  	/* Map ABB resources */ -	pname = "base-address"; -	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); -	abb->base = devm_ioremap_resource(dev, res); -	if (IS_ERR(abb->base)) { -		ret = PTR_ERR(abb->base); -		goto err; +	if (abb->regs->setup_off || abb->regs->control_off) { +		pname = "base-address"; +		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); +		abb->base = devm_ioremap_resource(dev, res); +		if (IS_ERR(abb->base)) +			return PTR_ERR(abb->base); + +		abb->setup_reg = abb->base + abb->regs->setup_off; +		abb->control_reg = abb->base + abb->regs->control_off; + +	} else { +		pname = "control-address"; +		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); +		abb->control_reg = devm_ioremap_resource(dev, res); +		if (IS_ERR(abb->control_reg)) +			return PTR_ERR(abb->control_reg); + +		pname = "setup-address"; +		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); +		abb->setup_reg = devm_ioremap_resource(dev, res); +		if (IS_ERR(abb->setup_reg)) +			return PTR_ERR(abb->setup_reg);  	}  	pname = "int-address";  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);  	if (!res) {  		dev_err(dev, "Missing '%s' IO resource\n", pname); -		ret = -ENODEV; -		goto err; +		return -ENODEV;  	}  	/*  	 * We may have shared interrupt register offsets which are @@ -738,8 +762,7 @@ static int ti_abb_probe(struct platform_device *pdev)  					     resource_size(res));  	if (!abb->int_base) {  		dev_err(dev, "Unable to map '%s'\n", pname); -		ret = -ENOMEM; -		goto err; +		return -ENOMEM;  	}  	/* Map Optional resources */ @@ -759,17 +782,19 @@ static int ti_abb_probe(struct platform_device *pdev)  					       resource_size(res));  	if (!abb->efuse_base) {  		dev_err(dev, "Unable to map '%s'\n", pname); -		ret = -ENOMEM; -		goto err; +		return -ENOMEM;  	}  	pname = "ldo-address";  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); -	abb->ldo_base = devm_ioremap_resource(dev, res); -	if (IS_ERR(abb->ldo_base)) { -		ret = PTR_ERR(abb->ldo_base); -		goto err; +	if (!res) { +		dev_dbg(dev, "Missing '%s' IO resource\n", pname); +		ret = -ENODEV; +		goto skip_opt;  	} +	abb->ldo_base = devm_ioremap_resource(dev, res); +	if (IS_ERR(abb->ldo_base)) +		return PTR_ERR(abb->ldo_base);  	/* IF ldo_base is set, the following are mandatory */  	pname = "ti,ldovbb-override-mask"; @@ -778,12 +803,11 @@ static int ti_abb_probe(struct platform_device *pdev)  				 &abb->ldovbb_override_mask);  	if (ret) {  		dev_err(dev, "Missing '%s' (%d)\n", pname, ret); -		goto err; +		return ret;  	}  	if (!abb->ldovbb_override_mask) {  		dev_err(dev, "Invalid property:'%s' set as 0!\n", pname); -		ret = -EINVAL; -		goto err; +		return -EINVAL;  	}  	pname = "ti,ldovbb-vset-mask"; @@ -792,12 +816,11 @@ static int ti_abb_probe(struct platform_device *pdev)  				 &abb->ldovbb_vset_mask);  	if (ret) {  		dev_err(dev, "Missing '%s' (%d)\n", pname, ret); -		goto err; +		return ret;  	}  	if (!abb->ldovbb_vset_mask) {  		dev_err(dev, "Invalid property:'%s' set as 0!\n", pname); -		ret = -EINVAL; -		goto err; +		return -EINVAL;  	}  skip_opt: @@ -807,31 +830,29 @@ skip_opt:  				 &abb->txdone_mask);  	if (ret) {  		dev_err(dev, "Missing '%s' (%d)\n", pname, ret); -		goto err; +		return ret;  	}  	if (!abb->txdone_mask) {  		dev_err(dev, "Invalid property:'%s' set as 0!\n", pname); -		ret = -EINVAL; -		goto err; +		return -EINVAL;  	}  	initdata = of_get_regulator_init_data(dev, pdev->dev.of_node);  	if (!initdata) { -		ret = -ENOMEM;  		dev_err(dev, "%s: Unable to alloc regulator init data\n",  			__func__); -		goto err; +		return -ENOMEM;  	}  	/* init ABB opp_sel table */  	ret = ti_abb_init_table(dev, abb, initdata);  	if (ret) -		goto err; +		return ret;  	/* init ABB timing */  	ret = ti_abb_init_timings(dev, abb);  	if (ret) -		goto err; +		return ret;  	desc = &abb->rdesc;  	desc->name = dev_name(dev); @@ -849,36 +870,18 @@ skip_opt:  	config.driver_data = abb;  	config.of_node = pdev->dev.of_node; -	rdev = regulator_register(desc, &config); +	rdev = devm_regulator_register(dev, desc, &config);  	if (IS_ERR(rdev)) {  		ret = PTR_ERR(rdev);  		dev_err(dev, "%s: failed to register regulator(%d)\n",  			__func__, ret); -		goto err; +		return ret;  	}  	platform_set_drvdata(pdev, rdev);  	/* Enable the ldo if not already done by bootloader */ -	ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->regs->setup_reg, abb->base); - -	return 0; - -err: -	dev_err(dev, "%s: Failed to initialize(%d)\n", __func__, ret); -	return ret; -} - -/** - * ti_abb_remove() - cleanups - * @pdev: ABB platform device - * - * Return: 0 - */ -static int ti_abb_remove(struct platform_device *pdev) -{ -	struct regulator_dev *rdev = platform_get_drvdata(pdev); +	ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->setup_reg); -	regulator_unregister(rdev);  	return 0;  } @@ -886,7 +889,6 @@ MODULE_ALIAS("platform:ti_abb");  static struct platform_driver ti_abb_driver = {  	.probe = ti_abb_probe, -	.remove = ti_abb_remove,  	.driver = {  		   .name = "ti_abb",  		   .owner = THIS_MODULE, diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c index 9392a7ca3d2..f31f22e3e1b 100644 --- a/drivers/regulator/tps51632-regulator.c +++ b/drivers/regulator/tps51632-regulator.c @@ -70,16 +70,16 @@  #define TPS51632_POWER_STATE_SINGLE_PHASE_CCM	0x1  #define TPS51632_POWER_STATE_SINGLE_PHASE_DCM	0x2 -#define TPS51632_MIN_VOLATGE			500000 -#define TPS51632_MAX_VOLATGE			1520000 -#define TPS51632_VOLATGE_STEP_10mV		10000 -#define TPS51632_VOLATGE_STEP_20mV		20000 +#define TPS51632_MIN_VOLTAGE			500000 +#define TPS51632_MAX_VOLTAGE			1520000 +#define TPS51632_VOLTAGE_STEP_10mV		10000 +#define TPS51632_VOLTAGE_STEP_20mV		20000  #define TPS51632_MAX_VSEL			0x7F  #define TPS51632_MIN_VSEL			0x19  #define TPS51632_DEFAULT_RAMP_DELAY		6000  #define TPS51632_VOLT_VSEL(uV)					\ -		(DIV_ROUND_UP(uV - TPS51632_MIN_VOLATGE,	\ -			TPS51632_VOLATGE_STEP_10mV) +		\ +		(DIV_ROUND_UP(uV - TPS51632_MIN_VOLTAGE,	\ +			TPS51632_VOLTAGE_STEP_10mV) +		\  			TPS51632_MIN_VSEL)  /* TPS51632 chip information */ @@ -227,10 +227,8 @@ static struct tps51632_regulator_platform_data *  	struct device_node *np = dev->of_node;  	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); -	if (!pdata) { -		dev_err(dev, "Memory alloc failed for platform data\n"); +	if (!pdata)  		return NULL; -	}  	pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);  	if (!pdata->reg_init_data) { @@ -243,9 +241,9 @@ static struct tps51632_regulator_platform_data *  	pdata->dvfs_step_20mV = of_property_read_bool(np, "ti,dvfs-step-20mV");  	pdata->base_voltage_uV = pdata->reg_init_data->constraints.min_uV ? : -					TPS51632_MIN_VOLATGE; +					TPS51632_MIN_VOLTAGE;  	pdata->max_voltage_uV = pdata->reg_init_data->constraints.max_uV ? : -					TPS51632_MAX_VOLATGE; +					TPS51632_MAX_VOLTAGE;  	return pdata;  }  #else @@ -284,32 +282,30 @@ static int tps51632_probe(struct i2c_client *client,  	}  	if (pdata->enable_pwm_dvfs) { -		if ((pdata->base_voltage_uV < TPS51632_MIN_VOLATGE) || -		    (pdata->base_voltage_uV > TPS51632_MAX_VOLATGE)) { +		if ((pdata->base_voltage_uV < TPS51632_MIN_VOLTAGE) || +		    (pdata->base_voltage_uV > TPS51632_MAX_VOLTAGE)) {  			dev_err(&client->dev, "Invalid base_voltage_uV setting\n");  			return -EINVAL;  		}  		if ((pdata->max_voltage_uV) && -		    ((pdata->max_voltage_uV < TPS51632_MIN_VOLATGE) || -		     (pdata->max_voltage_uV > TPS51632_MAX_VOLATGE))) { +		    ((pdata->max_voltage_uV < TPS51632_MIN_VOLTAGE) || +		     (pdata->max_voltage_uV > TPS51632_MAX_VOLTAGE))) {  			dev_err(&client->dev, "Invalid max_voltage_uV setting\n");  			return -EINVAL;  		}  	}  	tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); -	if (!tps) { -		dev_err(&client->dev, "Memory allocation failed\n"); +	if (!tps)  		return -ENOMEM; -	}  	tps->dev = &client->dev; -	tps->desc.name = id->name; +	tps->desc.name = client->name;  	tps->desc.id = 0;  	tps->desc.ramp_delay = TPS51632_DEFAULT_RAMP_DELAY; -	tps->desc.min_uV = TPS51632_MIN_VOLATGE; -	tps->desc.uV_step = TPS51632_VOLATGE_STEP_10mV; +	tps->desc.min_uV = TPS51632_MIN_VOLTAGE; +	tps->desc.uV_step = TPS51632_VOLTAGE_STEP_10mV;  	tps->desc.linear_min_sel = TPS51632_MIN_VSEL;  	tps->desc.n_voltages = TPS51632_MAX_VSEL + 1;  	tps->desc.ops = &tps51632_dcdc_ops; @@ -343,7 +339,7 @@ static int tps51632_probe(struct i2c_client *client,  	config.regmap = tps->regmap;  	config.of_node = client->dev.of_node; -	rdev = regulator_register(&tps->desc, &config); +	rdev = devm_regulator_register(&client->dev, &tps->desc, &config);  	if (IS_ERR(rdev)) {  		dev_err(tps->dev, "regulator register failed\n");  		return PTR_ERR(rdev); @@ -353,14 +349,6 @@ static int tps51632_probe(struct i2c_client *client,  	return 0;  } -static int tps51632_remove(struct i2c_client *client) -{ -	struct tps51632_chip *tps = i2c_get_clientdata(client); - -	regulator_unregister(tps->rdev); -	return 0; -} -  static const struct i2c_device_id tps51632_id[] = {  	{.name = "tps51632",},  	{}, @@ -375,7 +363,6 @@ static struct i2c_driver tps51632_i2c_driver = {  		.of_match_table = of_match_ptr(tps51632_of_match),  	},  	.probe = tps51632_probe, -	.remove = tps51632_remove,  	.id_table = tps51632_id,  }; diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c index ec9453ffb77..c1e33a3d397 100644 --- a/drivers/regulator/tps6105x-regulator.c +++ b/drivers/regulator/tps6105x-regulator.c @@ -137,7 +137,7 @@ static int tps6105x_regulator_probe(struct platform_device *pdev)  	/* This instance is not set for regulator mode so bail out */  	if (pdata->mode != TPS6105X_MODE_VOLTAGE) {  		dev_info(&pdev->dev, -			 "chip not in voltage mode mode, exit probe \n"); +			"chip not in voltage mode mode, exit probe\n");  		return 0;  	} @@ -146,8 +146,9 @@ static int tps6105x_regulator_probe(struct platform_device *pdev)  	config.driver_data = tps6105x;  	/* Register regulator with framework */ -	tps6105x->regulator = regulator_register(&tps6105x_regulator_desc, -						 &config); +	tps6105x->regulator = devm_regulator_register(&pdev->dev, +						      &tps6105x_regulator_desc, +						      &config);  	if (IS_ERR(tps6105x->regulator)) {  		ret = PTR_ERR(tps6105x->regulator);  		dev_err(&tps6105x->client->dev, @@ -159,20 +160,12 @@ static int tps6105x_regulator_probe(struct platform_device *pdev)  	return 0;  } -static int tps6105x_regulator_remove(struct platform_device *pdev) -{ -	struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev); -	regulator_unregister(tps6105x->regulator); -	return 0; -} -  static struct platform_driver tps6105x_regulator_driver = {  	.driver = {  		.name  = "tps6105x-regulator",  		.owner = THIS_MODULE,  	},  	.probe = tps6105x_regulator_probe, -	.remove = tps6105x_regulator_remove,  };  static __init int tps6105x_regulator_init(void) diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index 0b7ebb1ebf8..a1672044e51 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -299,10 +299,8 @@ static struct tps62360_regulator_platform_data *  	struct device_node *np = dev->of_node;  	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); -	if (!pdata) { -		dev_err(dev, "Memory alloc failed for platform data\n"); +	if (!pdata)  		return NULL; -	}  	pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);  	if (!pdata->reg_init_data) { @@ -360,7 +358,7 @@ static int tps62360_probe(struct i2c_client *client,  			dev_err(&client->dev, "Error: No device match found\n");  			return -ENODEV;  		} -		chip_id = (int)match->data; +		chip_id = (int)(long)match->data;  		if (!pdata)  			pdata = of_get_tps62360_platform_data(&client->dev);  	} else if (id) { @@ -377,11 +375,8 @@ static int tps62360_probe(struct i2c_client *client,  	}  	tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); -	if (!tps) { -		dev_err(&client->dev, "%s(): Memory allocation failed\n", -						__func__); +	if (!tps)  		return -ENOMEM; -	}  	tps->en_discharge = pdata->en_discharge;  	tps->en_internal_pulldn = pdata->en_internal_pulldn; @@ -476,7 +471,7 @@ static int tps62360_probe(struct i2c_client *client,  	config.of_node = client->dev.of_node;  	/* Register the regulators */ -	rdev = regulator_register(&tps->desc, &config); +	rdev = devm_regulator_register(&client->dev, &tps->desc, &config);  	if (IS_ERR(rdev)) {  		dev_err(tps->dev,  			"%s(): regulator register failed with err %s\n", @@ -488,20 +483,6 @@ static int tps62360_probe(struct i2c_client *client,  	return 0;  } -/** - * tps62360_remove - tps62360 driver i2c remove handler - * @client: i2c driver client device structure - * - * Unregister TPS driver as an i2c client device driver - */ -static int tps62360_remove(struct i2c_client *client) -{ -	struct tps62360_chip *tps = i2c_get_clientdata(client); - -	regulator_unregister(tps->rdev); -	return 0; -} -  static void tps62360_shutdown(struct i2c_client *client)  {  	struct tps62360_chip *tps = i2c_get_clientdata(client); @@ -535,7 +516,6 @@ static struct i2c_driver tps62360_i2c_driver = {  		.of_match_table = of_match_ptr(tps62360_of_match),  	},  	.probe = tps62360_probe, -	.remove = tps62360_remove,  	.shutdown = tps62360_shutdown,  	.id_table = tps62360_id,  }; diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index a15263d4bdf..3ef67a86115 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -277,12 +277,12 @@ static int tps_65023_probe(struct i2c_client *client,  		config.regmap = tps->regmap;  		/* Register the regulators */ -		rdev = regulator_register(&tps->desc[i], &config); +		rdev = devm_regulator_register(&client->dev, &tps->desc[i], +					       &config);  		if (IS_ERR(rdev)) {  			dev_err(&client->dev, "failed to register %s\n",  				id->name); -			error = PTR_ERR(rdev); -			goto fail; +			return PTR_ERR(rdev);  		}  		/* Save regulator for cleanup */ @@ -293,24 +293,10 @@ static int tps_65023_probe(struct i2c_client *client,  	/* Enable setting output voltage by I2C */  	regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2, -			TPS65023_REG_CTRL2_CORE_ADJ, TPS65023_REG_CTRL2_CORE_ADJ); +					TPS65023_REG_CTRL2_CORE_ADJ, +					TPS65023_REG_CTRL2_CORE_ADJ);  	return 0; - - fail: -	while (--i >= 0) -		regulator_unregister(tps->rdev[i]); -	return error; -} - -static int tps_65023_remove(struct i2c_client *client) -{ -	struct tps_pmic *tps = i2c_get_clientdata(client); -	int i; - -	for (i = 0; i < TPS65023_NUM_REGULATOR; i++) -		regulator_unregister(tps->rdev[i]); -	return 0;  }  static const struct tps_info tps65020_regs[] = { @@ -430,7 +416,6 @@ static struct i2c_driver tps_65023_i2c_driver = {  		.owner = THIS_MODULE,  	},  	.probe = tps_65023_probe, -	.remove = tps_65023_remove,  	.id_table = tps_65023_id,  }; diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index 4117ff52dba..98e66ce2672 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -359,7 +359,6 @@ static struct regulator_ops tps6507x_pmic_ops = {  	.map_voltage = regulator_map_voltage_ascend,  }; -#ifdef CONFIG_OF  static struct of_regulator_match tps6507x_matches[] = {  	{ .name = "VDCDC1"},  	{ .name = "VDCDC2"}, @@ -381,12 +380,10 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(  	tps_board = devm_kzalloc(&pdev->dev, sizeof(*tps_board),  					GFP_KERNEL); -	if (!tps_board) { -		dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n"); +	if (!tps_board)  		return NULL; -	} -	regulators = of_find_node_by_name(np, "regulators"); +	regulators = of_get_child_by_name(np, "regulators");  	if (!regulators) {  		dev_err(&pdev->dev, "regulator node not found\n");  		return NULL; @@ -396,6 +393,7 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(  	matches = tps6507x_matches;  	ret = of_regulator_match(&pdev->dev, regulators, matches, count); +	of_node_put(regulators);  	if (ret < 0) {  		dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",  			ret); @@ -406,10 +404,8 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(  	reg_data = devm_kzalloc(&pdev->dev, (sizeof(struct regulator_init_data)  					* TPS6507X_NUM_REGULATOR), GFP_KERNEL); -	if (!reg_data) { -		dev_err(&pdev->dev, "Failure to alloc init data for regulators.\n"); +	if (!reg_data)  		return NULL; -	}  	tps_board->tps6507x_pmic_init_data = reg_data; @@ -424,15 +420,7 @@ static struct tps6507x_board *tps6507x_parse_dt_reg_data(  	return tps_board;  } -#else -static inline struct tps6507x_board *tps6507x_parse_dt_reg_data( -			struct platform_device *pdev, -			struct of_regulator_match **tps6507x_reg_matches) -{ -	*tps6507x_reg_matches = NULL; -	return NULL; -} -#endif +  static int tps6507x_pmic_probe(struct platform_device *pdev)  {  	struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); @@ -453,9 +441,10 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)  	 */  	tps_board = dev_get_platdata(tps6507x_dev->dev); -	if (!tps_board && tps6507x_dev->dev->of_node) +	if (IS_ENABLED(CONFIG_OF) && !tps_board && +		tps6507x_dev->dev->of_node)  		tps_board = tps6507x_parse_dt_reg_data(pdev, -						&tps6507x_reg_matches); +				&tps6507x_reg_matches);  	if (!tps_board)  		return -EINVAL; @@ -481,7 +470,7 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)  		tps->info[i] = info;  		if (init_data->driver_data) {  			struct tps6507x_reg_platform_data *data = -							init_data->driver_data; +					init_data->driver_data;  			tps->info[i]->defdcdc_default = data->defdcdc_default;  		} @@ -508,13 +497,13 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)  			config.of_node = tps6507x_reg_matches[i].of_node;  		} -		rdev = regulator_register(&tps->desc[i], &config); +		rdev = devm_regulator_register(&pdev->dev, &tps->desc[i], +					       &config);  		if (IS_ERR(rdev)) {  			dev_err(tps6507x_dev->dev,  				"failed to register %s regulator\n",  				pdev->name); -			error = PTR_ERR(rdev); -			goto fail; +			return PTR_ERR(rdev);  		}  		/* Save regulator for cleanup */ @@ -525,22 +514,6 @@ static int tps6507x_pmic_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, tps6507x_dev);  	return 0; - -fail: -	while (--i >= 0) -		regulator_unregister(tps->rdev[i]); -	return error; -} - -static int tps6507x_pmic_remove(struct platform_device *pdev) -{ -	struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev); -	struct tps6507x_pmic *tps = tps6507x_dev->pmic; -	int i; - -	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++) -		regulator_unregister(tps->rdev[i]); -	return 0;  }  static struct platform_driver tps6507x_pmic_driver = { @@ -549,7 +522,6 @@ static struct platform_driver tps6507x_pmic_driver = {  		.owner = THIS_MODULE,  	},  	.probe = tps6507x_pmic_probe, -	.remove = tps6507x_pmic_remove,  };  static int __init tps6507x_pmic_init(void) diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index c8e70451df3..2064b3fd45f 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c @@ -17,6 +17,7 @@   */  #include <linux/module.h> +#include <linux/delay.h>  #include <linux/init.h>  #include <linux/gpio.h>  #include <linux/of_gpio.h> @@ -28,49 +29,216 @@  #include <linux/regulator/of_regulator.h>  #include <linux/mfd/tps65090.h> +#define MAX_CTRL_READ_TRIES	5 +#define MAX_FET_ENABLE_TRIES	1000 + +#define CTRL_EN_BIT		0 /* Regulator enable bit, active high */ +#define CTRL_WT_BIT		2 /* Regulator wait time 0 bit */ +#define CTRL_PG_BIT		4 /* Regulator power good bit, 1=good */ +#define CTRL_TO_BIT		7 /* Regulator timeout bit, 1=wait */ + +#define MAX_OVERCURRENT_WAIT	3 /* Overcurrent wait must be <= this */ + +/** + * struct tps65090_regulator - Per-regulator data for a tps65090 regulator + * + * @dev: Pointer to our device. + * @desc: The struct regulator_desc for the regulator. + * @rdev: The struct regulator_dev for the regulator. + * @overcurrent_wait_valid: True if overcurrent_wait is valid. + * @overcurrent_wait: For FETs, the value to put in the WTFET bitfield. + */ +  struct tps65090_regulator {  	struct device		*dev;  	struct regulator_desc	*desc;  	struct regulator_dev	*rdev; +	bool			overcurrent_wait_valid; +	int			overcurrent_wait;  };  static struct regulator_ops tps65090_ext_control_ops = {  }; -static struct regulator_ops tps65090_reg_contol_ops = { +/** + * tps65090_reg_set_overcurrent_wait - Setup overcurrent wait + * + * This will set the overcurrent wait time based on what's in the regulator + * info. + * + * @ri:		Overall regulator data + * @rdev:	Regulator device + * + * Return: 0 if no error, non-zero if there was an error writing the register. + */ +static int tps65090_reg_set_overcurrent_wait(struct tps65090_regulator *ri, +					     struct regulator_dev *rdev) +{ +	int ret; + +	ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, +				 MAX_OVERCURRENT_WAIT << CTRL_WT_BIT, +				 ri->overcurrent_wait << CTRL_WT_BIT); +	if (ret) { +		dev_err(&rdev->dev, "Error updating overcurrent wait %#x\n", +			rdev->desc->enable_reg); +	} + +	return ret; +} + +/** + * tps65090_try_enable_fet - Try to enable a FET + * + * @rdev:	Regulator device + * + * Return: 0 if ok, -ENOTRECOVERABLE if the FET power good bit did not get + * set, or some other -ve value if another error occurred (e.g. i2c error) + */ +static int tps65090_try_enable_fet(struct regulator_dev *rdev) +{ +	unsigned int control; +	int ret, i; + +	ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, +				 rdev->desc->enable_mask, +				 rdev->desc->enable_mask); +	if (ret < 0) { +		dev_err(&rdev->dev, "Error in updating reg %#x\n", +			rdev->desc->enable_reg); +		return ret; +	} + +	for (i = 0; i < MAX_CTRL_READ_TRIES; i++) { +		ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, +				  &control); +		if (ret < 0) +			return ret; + +		if (!(control & BIT(CTRL_TO_BIT))) +			break; + +		usleep_range(1000, 1500); +	} +	if (!(control & BIT(CTRL_PG_BIT))) +		return -ENOTRECOVERABLE; + +	return 0; +} + +/** + * tps65090_fet_enable - Enable a FET, trying a few times if it fails + * + * Some versions of the tps65090 have issues when turning on the FETs. + * This function goes through several steps to ensure the best chance of the + * FET going on.  Specifically: + * - We'll make sure that we bump the "overcurrent wait" to the maximum, which + *   increases the chances that we'll turn on properly. + * - We'll retry turning the FET on multiple times (turning off in between). + * + * @rdev:	Regulator device + * + * Return: 0 if ok, non-zero if it fails. + */ +static int tps65090_fet_enable(struct regulator_dev *rdev) +{ +	int ret, tries; + +	/* +	 * Try enabling multiple times until we succeed since sometimes the +	 * first try times out. +	 */ +	tries = 0; +	while (true) { +		ret = tps65090_try_enable_fet(rdev); +		if (!ret) +			break; +		if (ret != -ENOTRECOVERABLE || tries == MAX_FET_ENABLE_TRIES) +			goto err; + +		/* Try turning the FET off (and then on again) */ +		ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, +					 rdev->desc->enable_mask, 0); +		if (ret) +			goto err; + +		tries++; +	} + +	if (tries) +		dev_warn(&rdev->dev, "reg %#x enable ok after %d tries\n", +			 rdev->desc->enable_reg, tries); + +	return 0; +err: +	dev_warn(&rdev->dev, "reg %#x enable failed\n", rdev->desc->enable_reg); +	WARN_ON(1); + +	return ret; +} + +static struct regulator_ops tps65090_reg_control_ops = {  	.enable		= regulator_enable_regmap,  	.disable	= regulator_disable_regmap,  	.is_enabled	= regulator_is_enabled_regmap,  }; +static struct regulator_ops tps65090_fet_control_ops = { +	.enable		= tps65090_fet_enable, +	.disable	= regulator_disable_regmap, +	.is_enabled	= regulator_is_enabled_regmap, +}; +  static struct regulator_ops tps65090_ldo_ops = {  }; -#define tps65090_REG_DESC(_id, _sname, _en_reg, _ops)	\ +#define tps65090_REG_DESC(_id, _sname, _en_reg, _en_bits, _ops)	\  {							\  	.name = "TPS65090_RAILS"#_id,			\  	.supply_name = _sname,				\  	.id = TPS65090_REGULATOR_##_id,			\  	.ops = &_ops,					\  	.enable_reg = _en_reg,				\ -	.enable_mask = BIT(0),				\ +	.enable_val = _en_bits,				\ +	.enable_mask = _en_bits,			\  	.type = REGULATOR_VOLTAGE,			\  	.owner = THIS_MODULE,				\  }  static struct regulator_desc tps65090_regulator_desc[] = { -	tps65090_REG_DESC(DCDC1, "vsys1",   0x0C, tps65090_reg_contol_ops), -	tps65090_REG_DESC(DCDC2, "vsys2",   0x0D, tps65090_reg_contol_ops), -	tps65090_REG_DESC(DCDC3, "vsys3",   0x0E, tps65090_reg_contol_ops), -	tps65090_REG_DESC(FET1,  "infet1",  0x0F, tps65090_reg_contol_ops), -	tps65090_REG_DESC(FET2,  "infet2",  0x10, tps65090_reg_contol_ops), -	tps65090_REG_DESC(FET3,  "infet3",  0x11, tps65090_reg_contol_ops), -	tps65090_REG_DESC(FET4,  "infet4",  0x12, tps65090_reg_contol_ops), -	tps65090_REG_DESC(FET5,  "infet5",  0x13, tps65090_reg_contol_ops), -	tps65090_REG_DESC(FET6,  "infet6",  0x14, tps65090_reg_contol_ops), -	tps65090_REG_DESC(FET7,  "infet7",  0x15, tps65090_reg_contol_ops), -	tps65090_REG_DESC(LDO1,  "vsys-l1", 0,    tps65090_ldo_ops), -	tps65090_REG_DESC(LDO2,  "vsys-l2", 0,    tps65090_ldo_ops), +	tps65090_REG_DESC(DCDC1, "vsys1",   0x0C, BIT(CTRL_EN_BIT), +			  tps65090_reg_control_ops), +	tps65090_REG_DESC(DCDC2, "vsys2",   0x0D, BIT(CTRL_EN_BIT), +			  tps65090_reg_control_ops), +	tps65090_REG_DESC(DCDC3, "vsys3",   0x0E, BIT(CTRL_EN_BIT), +			  tps65090_reg_control_ops), + +	tps65090_REG_DESC(FET1,  "infet1",  0x0F, +			  BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), +			  tps65090_fet_control_ops), +	tps65090_REG_DESC(FET2,  "infet2",  0x10, +			  BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), +			  tps65090_fet_control_ops), +	tps65090_REG_DESC(FET3,  "infet3",  0x11, +			  BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), +			  tps65090_fet_control_ops), +	tps65090_REG_DESC(FET4,  "infet4",  0x12, +			  BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), +			  tps65090_fet_control_ops), +	tps65090_REG_DESC(FET5,  "infet5",  0x13, +			  BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), +			  tps65090_fet_control_ops), +	tps65090_REG_DESC(FET6,  "infet6",  0x14, +			  BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), +			  tps65090_fet_control_ops), +	tps65090_REG_DESC(FET7,  "infet7",  0x15, +			  BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), +			  tps65090_fet_control_ops), + +	tps65090_REG_DESC(LDO1,  "vsys-l1", 0, 0, +			  tps65090_ldo_ops), +	tps65090_REG_DESC(LDO2,  "vsys-l2", 0, 0, +			  tps65090_ldo_ops),  };  static inline bool is_dcdc(int id) @@ -168,19 +336,15 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(  	tps65090_pdata = devm_kzalloc(&pdev->dev, sizeof(*tps65090_pdata),  				GFP_KERNEL); -	if (!tps65090_pdata) { -		dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n"); +	if (!tps65090_pdata)  		return ERR_PTR(-ENOMEM); -	}  	reg_pdata = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX *  				sizeof(*reg_pdata), GFP_KERNEL); -	if (!reg_pdata) { -		dev_err(&pdev->dev, "Memory alloc for reg_pdata failed\n"); +	if (!reg_pdata)  		return ERR_PTR(-ENOMEM); -	} -	regulators = of_find_node_by_name(np, "regulators"); +	regulators = of_get_child_by_name(np, "regulators");  	if (!regulators) {  		dev_err(&pdev->dev, "regulator node not found\n");  		return ERR_PTR(-ENODEV); @@ -188,6 +352,7 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(  	ret = of_regulator_match(&pdev->dev, regulators, tps65090_matches,  			ARRAY_SIZE(tps65090_matches)); +	of_node_put(regulators);  	if (ret < 0) {  		dev_err(&pdev->dev,  			"Error parsing regulator init data: %d\n", ret); @@ -212,6 +377,11 @@ static struct tps65090_platform_data *tps65090_parse_dt_reg_data(  			rpdata->gpio = of_get_named_gpio(np,  					"dcdc-ext-control-gpios", 0); +		if (of_property_read_u32(tps65090_matches[idx].of_node, +					 "ti,overcurrent-wait", +					 &rpdata->overcurrent_wait) == 0) +			rpdata->overcurrent_wait_valid = true; +  		tps65090_pdata->reg_pdata[idx] = rpdata;  	}  	return tps65090_pdata; @@ -252,10 +422,8 @@ static int tps65090_regulator_probe(struct platform_device *pdev)  	pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic),  			GFP_KERNEL); -	if (!pmic) { -		dev_err(&pdev->dev, "mem alloc for pmic failed\n"); +	if (!pmic)  		return -ENOMEM; -	}  	for (num = 0; num < TPS65090_REGULATOR_MAX; num++) {  		tps_pdata = tps65090_pdata->reg_pdata[num]; @@ -263,6 +431,11 @@ static int tps65090_regulator_probe(struct platform_device *pdev)  		ri = &pmic[num];  		ri->dev = &pdev->dev;  		ri->desc = &tps65090_regulator_desc[num]; +		if (tps_pdata) { +			ri->overcurrent_wait_valid = +				tps_pdata->overcurrent_wait_valid; +			ri->overcurrent_wait = tps_pdata->overcurrent_wait; +		}  		/*  		 * TPS5090 DCDC support the control from external digital input. @@ -279,7 +452,7 @@ static int tps65090_regulator_probe(struct platform_device *pdev)  				if (ret < 0) {  					dev_err(&pdev->dev,  						"failed disable ext control\n"); -					goto scrub; +					return ret;  				}  			}  		} @@ -296,49 +469,31 @@ static int tps65090_regulator_probe(struct platform_device *pdev)  		else  			config.of_node = NULL; -		rdev = regulator_register(ri->desc, &config); +		rdev = devm_regulator_register(&pdev->dev, ri->desc, &config);  		if (IS_ERR(rdev)) {  			dev_err(&pdev->dev, "failed to register regulator %s\n",  				ri->desc->name); -			ret = PTR_ERR(rdev); -			goto scrub; +			return PTR_ERR(rdev);  		}  		ri->rdev = rdev; +		if (ri->overcurrent_wait_valid) { +			ret = tps65090_reg_set_overcurrent_wait(ri, rdev); +			if (ret < 0) +				return ret; +		} +  		/* Enable external control if it is require */  		if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data &&  				tps_pdata->enable_ext_control) {  			ret = tps65090_config_ext_control(ri, true); -			if (ret < 0) { -				/* Increment num to get unregister rdev */ -				num++; -				goto scrub; -			} +			if (ret < 0) +				return ret;  		}  	}  	platform_set_drvdata(pdev, pmic);  	return 0; - -scrub: -	while (--num >= 0) { -		ri = &pmic[num]; -		regulator_unregister(ri->rdev); -	} -	return ret; -} - -static int tps65090_regulator_remove(struct platform_device *pdev) -{ -	struct tps65090_regulator *pmic = platform_get_drvdata(pdev); -	struct tps65090_regulator *ri; -	int num; - -	for (num = 0; num < TPS65090_REGULATOR_MAX; ++num) { -		ri = &pmic[num]; -		regulator_unregister(ri->rdev); -	} -	return 0;  }  static struct platform_driver tps65090_regulator_driver = { @@ -347,7 +502,6 @@ static struct platform_driver tps65090_regulator_driver = {  		.owner	= THIS_MODULE,  	},  	.probe		= tps65090_regulator_probe, -	.remove		= tps65090_regulator_remove,  };  static int __init tps65090_regulator_init(void) diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index 90861d68a0b..f7ed20a5a8b 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -52,25 +52,17 @@ static const unsigned int LDO1_VSEL_table[] = {  };  static const struct regulator_linear_range tps65217_uv1_ranges[] = { -	{ .min_uV = 900000, .max_uV = 1500000, .min_sel =  0, .max_sel = 24, -	  .uV_step = 25000 }, -	{ .min_uV = 1550000, .max_uV = 1800000, .min_sel = 25, .max_sel = 30, -	  .uV_step = 50000 }, -	{ .min_uV = 1850000, .max_uV = 2900000, .min_sel = 31, .max_sel = 52, -	  .uV_step = 50000 }, -	{ .min_uV = 3000000, .max_uV = 3200000, .min_sel = 53, .max_sel = 55, -	  .uV_step = 100000 }, -	{ .min_uV = 3300000, .max_uV = 3300000, .min_sel = 56, .max_sel = 62, -	  .uV_step = 0 }, +	REGULATOR_LINEAR_RANGE(900000, 0, 24, 25000), +	REGULATOR_LINEAR_RANGE(1550000, 25, 30, 50000), +	REGULATOR_LINEAR_RANGE(1850000, 31, 52, 50000), +	REGULATOR_LINEAR_RANGE(3000000, 53, 55, 100000), +	REGULATOR_LINEAR_RANGE(3300000, 56, 62, 0),  };  static const struct regulator_linear_range tps65217_uv2_ranges[] = { -	{ .min_uV = 1500000, .max_uV = 1900000, .min_sel =  0, .max_sel = 8, -	  .uV_step = 50000 }, -	{ .min_uV = 2000000, .max_uV = 2400000, .min_sel = 9, .max_sel = 13, -	  .uV_step = 100000 }, -	{ .min_uV = 2450000, .max_uV = 3300000, .min_sel = 14, .max_sel = 31, -	  .uV_step = 50000 }, +	REGULATOR_LINEAR_RANGE(1500000, 0, 8, 50000), +	REGULATOR_LINEAR_RANGE(2000000, 9, 13, 100000), +	REGULATOR_LINEAR_RANGE(2450000, 14, 31, 50000),  };  static int tps65217_pmic_enable(struct regulator_dev *dev) @@ -142,6 +134,7 @@ static struct regulator_ops tps65217_pmic_ldo1_ops = {  	.get_voltage_sel	= regulator_get_voltage_sel_regmap,  	.set_voltage_sel	= tps65217_pmic_set_voltage_sel,  	.list_voltage		= regulator_list_voltage_table, +	.map_voltage		= regulator_map_voltage_ascend,  };  static const struct regulator_desc regulators[] = { @@ -195,7 +188,7 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)  	struct device_node *regs;  	int i, count; -	regs = of_find_node_by_name(node, "regulators"); +	regs = of_get_child_by_name(node, "regulators");  	if (!regs)  		return NULL; @@ -210,7 +203,7 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)  		return NULL;  	for (i = 0; i < count; i++) { -		if (!reg_matches[i].init_data || !reg_matches[i].of_node) +		if (!reg_matches[i].of_node)  			continue;  		pdata->tps65217_init_data[i] = reg_matches[i].init_data; @@ -230,10 +223,9 @@ static int tps65217_regulator_probe(struct platform_device *pdev)  {  	struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);  	struct tps65217_board *pdata = dev_get_platdata(tps->dev); -	struct regulator_init_data *reg_data;  	struct regulator_dev *rdev;  	struct regulator_config config = { }; -	int i, ret; +	int i;  	if (tps->dev->of_node)  		pdata = tps65217_parse_dt(pdev); @@ -251,53 +243,23 @@ static int tps65217_regulator_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, tps);  	for (i = 0; i < TPS65217_NUM_REGULATOR; i++) { - -		reg_data = pdata->tps65217_init_data[i]; - -		/* -		 * Regulator API handles empty constraints but not NULL -		 * constraints -		 */ -		if (!reg_data) -			continue; -  		/* Register the regulators */  		config.dev = tps->dev; -		config.init_data = reg_data; +		config.init_data = pdata->tps65217_init_data[i];  		config.driver_data = tps;  		config.regmap = tps->regmap;  		if (tps->dev->of_node)  			config.of_node = pdata->of_node[i]; -		rdev = regulator_register(®ulators[i], &config); +		rdev = devm_regulator_register(&pdev->dev, ®ulators[i], +					       &config);  		if (IS_ERR(rdev)) {  			dev_err(tps->dev, "failed to register %s regulator\n",  				pdev->name); -			ret = PTR_ERR(rdev); -			goto err_unregister_regulator; +			return PTR_ERR(rdev);  		} - -		/* Save regulator for cleanup */ -		tps->rdev[i] = rdev;  	}  	return 0; - -err_unregister_regulator: -	while (--i >= 0) -		regulator_unregister(tps->rdev[i]); - -	return ret; -} - -static int tps65217_regulator_remove(struct platform_device *pdev) -{ -	struct tps65217 *tps = platform_get_drvdata(pdev); -	unsigned int i; - -	for (i = 0; i < TPS65217_NUM_REGULATOR; i++) -		regulator_unregister(tps->rdev[i]); - -	return 0;  }  static struct platform_driver tps65217_regulator_driver = { @@ -305,7 +267,6 @@ static struct platform_driver tps65217_regulator_driver = {  		.name = "tps65217-pmic",  	},  	.probe = tps65217_regulator_probe, -	.remove = tps65217_regulator_remove,  };  static int __init tps65217_regulator_init(void) diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c new file mode 100644 index 00000000000..9effe48c605 --- /dev/null +++ b/drivers/regulator/tps65218-regulator.c @@ -0,0 +1,269 @@ +/* + * tps65218-regulator.c + * + * Regulator driver for TPS65218 PMIC + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether expressed or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License version 2 for more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/of_device.h> +#include <linux/regulator/of_regulator.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/tps65218.h> + +enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, DCDC5, DCDC6, LDO1 }; + +#define TPS65218_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _er, _em, _t, \ +			    _lr, _nlr, _delay)			\ +	{							\ +		.name			= _name,		\ +		.id			= _id,			\ +		.ops			= &_ops,		\ +		.n_voltages		= _n,			\ +		.type			= REGULATOR_VOLTAGE,	\ +		.owner			= THIS_MODULE,		\ +		.vsel_reg		= _vr,			\ +		.vsel_mask		= _vm,			\ +		.enable_reg		= _er,			\ +		.enable_mask		= _em,			\ +		.volt_table		= _t,			\ +		.linear_ranges		= _lr,			\ +		.n_linear_ranges	= _nlr,			\ +		.ramp_delay		= _delay,		\ +	}							\ + +#define TPS65218_INFO(_id, _nm, _min, _max)	\ +	{						\ +		.id		= _id,			\ +		.name		= _nm,			\ +		.min_uV		= _min,			\ +		.max_uV		= _max,			\ +	} + +static const struct regulator_linear_range dcdc1_dcdc2_ranges[] = { +	REGULATOR_LINEAR_RANGE(850000, 0x0, 0x32, 10000), +	REGULATOR_LINEAR_RANGE(1375000, 0x33, 0x3f, 25000), +}; + +static const struct regulator_linear_range ldo1_dcdc3_ranges[] = { +	REGULATOR_LINEAR_RANGE(900000, 0x0, 0x1a, 25000), +	REGULATOR_LINEAR_RANGE(1600000, 0x1b, 0x3f, 50000), +}; + +static const struct regulator_linear_range dcdc4_ranges[] = { +	REGULATOR_LINEAR_RANGE(1175000, 0x0, 0xf, 25000), +	REGULATOR_LINEAR_RANGE(1550000, 0x10, 0x34, 50000), +}; + +static struct tps_info tps65218_pmic_regs[] = { +	TPS65218_INFO(0, "DCDC1", 850000, 167500), +	TPS65218_INFO(1, "DCDC2", 850000, 1675000), +	TPS65218_INFO(2, "DCDC3", 900000, 3400000), +	TPS65218_INFO(3, "DCDC4", 1175000, 3400000), +	TPS65218_INFO(4, "DCDC5", 1000000, 1000000), +	TPS65218_INFO(5, "DCDC6", 1800000, 1800000), +	TPS65218_INFO(6, "LDO1", 900000, 3400000), +}; + +#define TPS65218_OF_MATCH(comp, label) \ +	{ \ +		.compatible = comp, \ +		.data = &label, \ +	} + +static const struct of_device_id tps65218_of_match[] = { +	TPS65218_OF_MATCH("ti,tps65218-dcdc1", tps65218_pmic_regs[DCDC1]), +	TPS65218_OF_MATCH("ti,tps65218-dcdc2", tps65218_pmic_regs[DCDC2]), +	TPS65218_OF_MATCH("ti,tps65218-dcdc3", tps65218_pmic_regs[DCDC3]), +	TPS65218_OF_MATCH("ti,tps65218-dcdc4", tps65218_pmic_regs[DCDC4]), +	TPS65218_OF_MATCH("ti,tps65218-dcdc5", tps65218_pmic_regs[DCDC5]), +	TPS65218_OF_MATCH("ti,tps65218-dcdc6", tps65218_pmic_regs[DCDC6]), +	TPS65218_OF_MATCH("ti,tps65218-ldo1", tps65218_pmic_regs[LDO1]), +	{ } +}; +MODULE_DEVICE_TABLE(of, tps65218_of_match); + +static int tps65218_pmic_set_voltage_sel(struct regulator_dev *dev, +					 unsigned selector) +{ +	int ret; +	struct tps65218 *tps = rdev_get_drvdata(dev); +	unsigned int rid = rdev_get_id(dev); + +	/* Set the voltage based on vsel value and write protect level is 2 */ +	ret = tps65218_set_bits(tps, dev->desc->vsel_reg, dev->desc->vsel_mask, +				selector, TPS65218_PROTECT_L1); + +	/* Set GO bit for DCDC1/2 to initiate voltage transistion */ +	switch (rid) { +	case TPS65218_DCDC_1: +	case TPS65218_DCDC_2: +		ret = tps65218_set_bits(tps, TPS65218_REG_CONTRL_SLEW_RATE, +					TPS65218_SLEW_RATE_GO, +					TPS65218_SLEW_RATE_GO, +					TPS65218_PROTECT_L1); +		break; +	} + +	return ret; +} + +static int tps65218_pmic_enable(struct regulator_dev *dev) +{ +	struct tps65218 *tps = rdev_get_drvdata(dev); +	unsigned int rid = rdev_get_id(dev); + +	if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1) +		return -EINVAL; + +	/* Enable the regulator and password protection is level 1 */ +	return tps65218_set_bits(tps, dev->desc->enable_reg, +				 dev->desc->enable_mask, dev->desc->enable_mask, +				 TPS65218_PROTECT_L1); +} + +static int tps65218_pmic_disable(struct regulator_dev *dev) +{ +	struct tps65218 *tps = rdev_get_drvdata(dev); +	unsigned int rid = rdev_get_id(dev); + +	if (rid < TPS65218_DCDC_1 || rid > TPS65218_LDO_1) +		return -EINVAL; + +	/* Disable the regulator and password protection is level 1 */ +	return tps65218_clear_bits(tps, dev->desc->enable_reg, +				   dev->desc->enable_mask, TPS65218_PROTECT_L1); +} + +/* Operations permitted on DCDC1, DCDC2 */ +static struct regulator_ops tps65218_dcdc12_ops = { +	.is_enabled		= regulator_is_enabled_regmap, +	.enable			= tps65218_pmic_enable, +	.disable		= tps65218_pmic_disable, +	.get_voltage_sel	= regulator_get_voltage_sel_regmap, +	.set_voltage_sel	= tps65218_pmic_set_voltage_sel, +	.list_voltage		= regulator_list_voltage_linear_range, +	.map_voltage		= regulator_map_voltage_linear_range, +	.set_voltage_time_sel	= regulator_set_voltage_time_sel, +}; + +/* Operations permitted on DCDC3, DCDC4 and LDO1 */ +static struct regulator_ops tps65218_ldo1_dcdc34_ops = { +	.is_enabled		= regulator_is_enabled_regmap, +	.enable			= tps65218_pmic_enable, +	.disable		= tps65218_pmic_disable, +	.get_voltage_sel	= regulator_get_voltage_sel_regmap, +	.set_voltage_sel	= tps65218_pmic_set_voltage_sel, +	.list_voltage		= regulator_list_voltage_linear_range, +	.map_voltage		= regulator_map_voltage_linear_range, +}; + +/* Operations permitted on DCDC5, DCDC6 */ +static struct regulator_ops tps65218_dcdc56_pmic_ops = { +	.is_enabled		= regulator_is_enabled_regmap, +	.enable			= tps65218_pmic_enable, +	.disable		= tps65218_pmic_disable, +}; + +static const struct regulator_desc regulators[] = { +	TPS65218_REGULATOR("DCDC1", TPS65218_DCDC_1, tps65218_dcdc12_ops, 64, +			   TPS65218_REG_CONTROL_DCDC1, +			   TPS65218_CONTROL_DCDC1_MASK, +			   TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC1_EN, NULL, +			   dcdc1_dcdc2_ranges, 2, 4000), +	TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, tps65218_dcdc12_ops, 64, +			   TPS65218_REG_CONTROL_DCDC2, +			   TPS65218_CONTROL_DCDC2_MASK, +			   TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC2_EN, NULL, +			   dcdc1_dcdc2_ranges, 2, 4000), +	TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, tps65218_ldo1_dcdc34_ops, +			   64, TPS65218_REG_CONTROL_DCDC3, +			   TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1, +			   TPS65218_ENABLE1_DC3_EN, NULL, +			   ldo1_dcdc3_ranges, 2, 0), +	TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, tps65218_ldo1_dcdc34_ops, +			   53, TPS65218_REG_CONTROL_DCDC4, +			   TPS65218_CONTROL_DCDC4_MASK, +			   TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC4_EN, NULL, +			   dcdc4_ranges, 2, 0), +	TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, tps65218_dcdc56_pmic_ops, +			   1, -1, -1, TPS65218_REG_ENABLE1, +			   TPS65218_ENABLE1_DC5_EN, NULL, NULL, 0, 0), +	TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, tps65218_dcdc56_pmic_ops, +			   1, -1, -1, TPS65218_REG_ENABLE1, +			   TPS65218_ENABLE1_DC6_EN, NULL, NULL, 0, 0), +	TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, tps65218_ldo1_dcdc34_ops, 64, +			   TPS65218_REG_CONTROL_LDO1, +			   TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2, +			   TPS65218_ENABLE2_LDO1_EN, NULL, ldo1_dcdc3_ranges, +			   2, 0), +}; + +static int tps65218_regulator_probe(struct platform_device *pdev) +{ +	struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent); +	struct regulator_init_data *init_data; +	const struct tps_info	*template; +	struct regulator_dev *rdev; +	const struct of_device_id	*match; +	struct regulator_config config = { }; +	int id; + +	match = of_match_device(tps65218_of_match, &pdev->dev); +	if (!match) +		return -ENODEV; + +	template = match->data; +	id = template->id; +	init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node); + +	platform_set_drvdata(pdev, tps); + +	tps->info[id] = &tps65218_pmic_regs[id]; +	config.dev = &pdev->dev; +	config.init_data = init_data; +	config.driver_data = tps; +	config.regmap = tps->regmap; +	config.of_node = pdev->dev.of_node; + +	rdev = devm_regulator_register(&pdev->dev, ®ulators[id], &config); +	if (IS_ERR(rdev)) { +		dev_err(tps->dev, "failed to register %s regulator\n", +			pdev->name); +		return PTR_ERR(rdev); +	} + +	return 0; +} + +static struct platform_driver tps65218_regulator_driver = { +	.driver = { +		.name = "tps65218-pmic", +		.owner = THIS_MODULE, +		.of_match_table = tps65218_of_match, +	}, +	.probe = tps65218_regulator_probe, +}; + +module_platform_driver(tps65218_regulator_driver); + +MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>"); +MODULE_DESCRIPTION("TPS65218 voltage regulator driver"); +MODULE_ALIAS("platform:tps65218-pmic"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c index 62e8d28beab..5b494db9f95 100644 --- a/drivers/regulator/tps6524x-regulator.c +++ b/drivers/regulator/tps6524x-regulator.c @@ -577,21 +577,6 @@ static struct regulator_ops regulator_ops = {  	.get_current_limit	= get_current_limit,  }; -static int pmic_remove(struct spi_device *spi) -{ -	struct tps6524x *hw = spi_get_drvdata(spi); -	int i; - -	if (!hw) -		return 0; -	for (i = 0; i < N_REGULATORS; i++) { -		regulator_unregister(hw->rdev[i]); -		hw->rdev[i] = NULL; -	} -	spi_set_drvdata(spi, NULL); -	return 0; -} -  static int pmic_probe(struct spi_device *spi)  {  	struct tps6524x *hw; @@ -599,7 +584,7 @@ static int pmic_probe(struct spi_device *spi)  	const struct supply_info *info = supply_info;  	struct regulator_init_data *init_data;  	struct regulator_config config = { }; -	int ret = 0, i; +	int i;  	init_data = dev_get_platdata(dev);  	if (!init_data) { @@ -608,10 +593,9 @@ static int pmic_probe(struct spi_device *spi)  	}  	hw = devm_kzalloc(&spi->dev, sizeof(struct tps6524x), GFP_KERNEL); -	if (!hw) { -		dev_err(dev, "cannot allocate regulator private data\n"); +	if (!hw)  		return -ENOMEM; -	} +  	spi_set_drvdata(spi, hw);  	memset(hw, 0, sizeof(struct tps6524x)); @@ -632,24 +616,17 @@ static int pmic_probe(struct spi_device *spi)  		config.init_data = init_data;  		config.driver_data = hw; -		hw->rdev[i] = regulator_register(&hw->desc[i], &config); -		if (IS_ERR(hw->rdev[i])) { -			ret = PTR_ERR(hw->rdev[i]); -			hw->rdev[i] = NULL; -			goto fail; -		} +		hw->rdev[i] = devm_regulator_register(dev, &hw->desc[i], +						      &config); +		if (IS_ERR(hw->rdev[i])) +			return PTR_ERR(hw->rdev[i]);  	}  	return 0; - -fail: -	pmic_remove(spi); -	return ret;  }  static struct spi_driver pmic_driver = {  	.probe		= pmic_probe, -	.remove		= pmic_remove,  	.driver		= {  		.name	= "tps6524x",  		.owner	= THIS_MODULE, diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 2c9155b66f0..0a3bb3aecd9 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -63,12 +63,7 @@ struct tps6586x_regulator {  	int enable_reg[2];  }; -static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev) -{ -	return rdev_get_dev(rdev)->parent; -} - -static struct regulator_ops tps6586x_regulator_ops = { +static struct regulator_ops tps6586x_rw_regulator_ops = {  	.list_voltage = regulator_list_voltage_table,  	.map_voltage = regulator_map_voltage_ascend,  	.get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -79,6 +74,16 @@ static struct regulator_ops tps6586x_regulator_ops = {  	.disable = regulator_disable_regmap,  }; +static struct regulator_ops tps6586x_ro_regulator_ops = { +	.list_voltage = regulator_list_voltage_table, +	.map_voltage = regulator_map_voltage_ascend, +	.get_voltage_sel = regulator_get_voltage_sel_regmap, + +	.is_enabled = regulator_is_enabled_regmap, +	.enable = regulator_enable_regmap, +	.disable = regulator_disable_regmap, +}; +  static struct regulator_ops tps6586x_sys_regulator_ops = {  }; @@ -93,6 +98,8 @@ static const unsigned int tps6586x_ldo4_voltages[] = {  	2300000, 2325000, 2350000, 2375000, 2400000, 2425000, 2450000, 2475000,  }; +#define tps658623_sm2_voltages tps6586x_ldo4_voltages +  static const unsigned int tps6586x_ldo_voltages[] = {  	1250000, 1500000, 1800000, 2500000, 2700000, 2850000, 3100000, 3300000,  }; @@ -104,6 +111,20 @@ static const unsigned int tps6586x_sm2_voltages[] = {  	4200000, 4250000, 4300000, 4350000, 4400000, 4450000, 4500000, 4550000,  }; +static int tps658640_sm2_voltages[] = { +	2150000, 2200000, 2250000, 2300000, 2350000, 2400000, 2450000, 2500000, +	2550000, 2600000, 2650000, 2700000, 2750000, 2800000, 2850000, 2900000, +	2950000, 3000000, 3050000, 3100000, 3150000, 3200000, 3250000, 3300000, +	3350000, 3400000, 3450000, 3500000, 3550000, 3600000, 3650000, 3700000, +}; + +static const unsigned int tps658643_sm2_voltages[] = { +	1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, 1200000, +	1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000, 1400000, +	1425000, 1450000, 1475000, 1500000, 1525000, 1550000, 1575000, 1600000, +	1625000, 1650000, 1675000, 1700000, 1725000, 1750000, 1775000, 1800000, +}; +  static const unsigned int tps6586x_dvm_voltages[] = {  	 725000,  750000,  775000,  800000,  825000,  850000,  875000,  900000,  	 925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000, @@ -111,16 +132,20 @@ static const unsigned int tps6586x_dvm_voltages[] = {  	1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,  }; -#define TPS6586X_REGULATOR(_id, _pin_name, vdata, vreg, shift, nbits,	\ +static int tps658640_rtc_voltages[] = { +	2500000, 2850000, 3100000, 3300000, +}; + +#define TPS6586X_REGULATOR(_id, _ops, _pin_name, vdata, vreg, shift, nbits, \  			   ereg0, ebit0, ereg1, ebit1, goreg, gobit)	\  	.desc	= {							\  		.supply_name = _pin_name,				\  		.name	= "REG-" #_id,					\ -		.ops	= &tps6586x_regulator_ops,			\ +		.ops	= &tps6586x_## _ops ## _regulator_ops,		\  		.type	= REGULATOR_VOLTAGE,				\  		.id	= TPS6586X_ID_##_id,				\ -		.n_voltages = ARRAY_SIZE(tps6586x_##vdata##_voltages),	\ -		.volt_table = tps6586x_##vdata##_voltages,		\ +		.n_voltages = ARRAY_SIZE(vdata##_voltages),		\ +		.volt_table = vdata##_voltages,				\  		.owner	= THIS_MODULE,					\  		.enable_reg = TPS6586X_SUPPLY##ereg0,			\  		.enable_mask = 1 << (ebit0),				\ @@ -137,14 +162,21 @@ static const unsigned int tps6586x_dvm_voltages[] = {  #define TPS6586X_LDO(_id, _pname, vdata, vreg, shift, nbits,		\  		     ereg0, ebit0, ereg1, ebit1)			\  {									\ -	TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits,	\ +	TPS6586X_REGULATOR(_id, rw, _pname, vdata, vreg, shift, nbits,	\ +			   ereg0, ebit0, ereg1, ebit1, 0, 0)		\ +} + +#define TPS6586X_FIXED_LDO(_id, _pname, vdata, vreg, shift, nbits,	\ +			  ereg0, ebit0, ereg1, ebit1)			\ +{									\ +	TPS6586X_REGULATOR(_id, ro, _pname, vdata, vreg, shift, nbits,	\  			   ereg0, ebit0, ereg1, ebit1, 0, 0)		\  }  #define TPS6586X_DVM(_id, _pname, vdata, vreg, shift, nbits,		\  		     ereg0, ebit0, ereg1, ebit1, goreg, gobit)		\  {									\ -	TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits,	\ +	TPS6586X_REGULATOR(_id, rw, _pname, vdata, vreg, shift, nbits,	\  			   ereg0, ebit0, ereg1, ebit1, goreg, gobit)	\  } @@ -162,27 +194,67 @@ static const unsigned int tps6586x_dvm_voltages[] = {  static struct tps6586x_regulator tps6586x_regulator[] = {  	TPS6586X_SYS_REGULATOR(), -	TPS6586X_LDO(LDO_0, "vinldo01", ldo0, SUPPLYV1, 5, 3, ENC, 0, END, 0), -	TPS6586X_LDO(LDO_3, "vinldo23", ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2), -	TPS6586X_LDO(LDO_5, "REG-SYS", ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6), -	TPS6586X_LDO(LDO_6, "vinldo678", ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4), -	TPS6586X_LDO(LDO_7, "vinldo678", ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5), -	TPS6586X_LDO(LDO_8, "vinldo678", ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6), -	TPS6586X_LDO(LDO_9, "vinldo9", ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7), -	TPS6586X_LDO(LDO_RTC, "REG-SYS", ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7), -	TPS6586X_LDO(LDO_1, "vinldo01", dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1), -	TPS6586X_LDO(SM_2, "vin-sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7), - -	TPS6586X_DVM(LDO_2, "vinldo23", dvm, LDO2BV1, 0, 5, ENA, 3, +	TPS6586X_LDO(LDO_0, "vinldo01", tps6586x_ldo0, SUPPLYV1, 5, 3, ENC, 0, +					END, 0), +	TPS6586X_LDO(LDO_3, "vinldo23", tps6586x_ldo, SUPPLYV4, 0, 3, ENC, 2, +					END, 2), +	TPS6586X_LDO(LDO_5, "REG-SYS", tps6586x_ldo, SUPPLYV6, 0, 3, ENE, 6, +					ENE, 6), +	TPS6586X_LDO(LDO_6, "vinldo678", tps6586x_ldo, SUPPLYV3, 0, 3, ENC, 4, +					END, 4), +	TPS6586X_LDO(LDO_7, "vinldo678", tps6586x_ldo, SUPPLYV3, 3, 3, ENC, 5, +					END, 5), +	TPS6586X_LDO(LDO_8, "vinldo678", tps6586x_ldo, SUPPLYV2, 5, 3, ENC, 6, +					END, 6), +	TPS6586X_LDO(LDO_9, "vinldo9", tps6586x_ldo, SUPPLYV6, 3, 3, ENE, 7, +					ENE, 7), +	TPS6586X_LDO(LDO_RTC, "REG-SYS", tps6586x_ldo, SUPPLYV4, 3, 3, V4, 7, +					V4, 7), +	TPS6586X_LDO(LDO_1, "vinldo01", tps6586x_dvm, SUPPLYV1, 0, 5, ENC, 1, +					END, 1), +	TPS6586X_LDO(SM_2, "vin-sm2", tps6586x_sm2, SUPPLYV2, 0, 5, ENC, 7, +					END, 7), + +	TPS6586X_DVM(LDO_2, "vinldo23", tps6586x_dvm, LDO2BV1, 0, 5, ENA, 3,  					ENB, 3, TPS6586X_VCC2, BIT(6)), -	TPS6586X_DVM(LDO_4, "vinldo4", ldo4, LDO4V1, 0, 5, ENC, 3, +	TPS6586X_DVM(LDO_4, "vinldo4", tps6586x_ldo4, LDO4V1, 0, 5, ENC, 3,  					END, 3, TPS6586X_VCC1, BIT(6)), -	TPS6586X_DVM(SM_0, "vin-sm0", dvm, SM0V1, 0, 5, ENA, 1, +	TPS6586X_DVM(SM_0, "vin-sm0", tps6586x_dvm, SM0V1, 0, 5, ENA, 1,  					ENB, 1, TPS6586X_VCC1, BIT(2)), -	TPS6586X_DVM(SM_1, "vin-sm1", dvm, SM1V1, 0, 5, ENA, 0, +	TPS6586X_DVM(SM_1, "vin-sm1", tps6586x_dvm, SM1V1, 0, 5, ENA, 0,  					ENB, 0, TPS6586X_VCC1, BIT(0)),  }; +static struct tps6586x_regulator tps658623_regulator[] = { +	TPS6586X_LDO(SM_2, "vin-sm2", tps658623_sm2, SUPPLYV2, 0, 5, ENC, 7, +					END, 7), +}; + +static struct tps6586x_regulator tps658640_regulator[] = { +	TPS6586X_LDO(LDO_3, "vinldo23", tps6586x_ldo0, SUPPLYV4, 0, 3, +					ENC, 2, END, 2), +	TPS6586X_LDO(LDO_5, "REG-SYS", tps6586x_ldo0, SUPPLYV6, 0, 3, +					ENE, 6, ENE, 6), +	TPS6586X_LDO(LDO_6, "vinldo678", tps6586x_ldo0, SUPPLYV3, 0, 3, +					ENC, 4, END, 4), +	TPS6586X_LDO(LDO_7, "vinldo678", tps6586x_ldo0, SUPPLYV3, 3, 3, +					ENC, 5, END, 5), +	TPS6586X_LDO(LDO_8, "vinldo678", tps6586x_ldo0, SUPPLYV2, 5, 3, +					ENC, 6, END, 6), +	TPS6586X_LDO(LDO_9, "vinldo9", tps6586x_ldo0, SUPPLYV6, 3, 3, +					ENE, 7, ENE, 7), +	TPS6586X_LDO(SM_2, "vin-sm2", tps658640_sm2, SUPPLYV2, 0, 5, +					ENC, 7, END, 7), + +	TPS6586X_FIXED_LDO(LDO_RTC, "REG-SYS", tps658640_rtc, SUPPLYV4, 3, 2, +					V4, 7, V4, 7), +}; + +static struct tps6586x_regulator tps658643_regulator[] = { +	TPS6586X_LDO(SM_2, "vin-sm2", tps658643_sm2, SUPPLYV2, 0, 5, ENC, 7, +					END, 7), +}; +  /*   * TPS6586X has 2 enable bits that are OR'ed to determine the actual   * regulator state. Clearing one of this bits allows switching @@ -254,11 +326,38 @@ static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev,  			setting->slew_rate & TPS6586X_SLEW_RATE_MASK);  } -static inline struct tps6586x_regulator *find_regulator_info(int id) +static struct tps6586x_regulator *find_regulator_info(int id, int version)  {  	struct tps6586x_regulator *ri; +	struct tps6586x_regulator *table = NULL; +	int num;  	int i; +	switch (version) { +	case TPS658623: +		table = tps658623_regulator; +		num = ARRAY_SIZE(tps658623_regulator); +		break; +	case TPS658640: +	case TPS658640v2: +		table = tps658640_regulator; +		num = ARRAY_SIZE(tps658640_regulator); +		break; +	case TPS658643: +		table = tps658643_regulator; +		num = ARRAY_SIZE(tps658643_regulator); +		break; +	} + +	/* Search version specific table first */ +	if (table) { +		for (i = 0; i < num; i++) { +			ri = &table[i]; +			if (ri->desc.id == id) +				return ri; +		} +	} +  	for (i = 0; i < ARRAY_SIZE(tps6586x_regulator); i++) {  		ri = &tps6586x_regulator[i];  		if (ri->desc.id == id) @@ -298,7 +397,7 @@ static struct tps6586x_platform_data *tps6586x_parse_regulator_dt(  	struct tps6586x_platform_data *pdata;  	int err; -	regs = of_find_node_by_name(np, "regulators"); +	regs = of_get_child_by_name(np, "regulators");  	if (!regs) {  		dev_err(&pdev->dev, "regulator node not found\n");  		return NULL; @@ -312,10 +411,8 @@ static struct tps6586x_platform_data *tps6586x_parse_regulator_dt(  	}  	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); -	if (!pdata) { -		dev_err(&pdev->dev, "Memory alloction failed\n"); +	if (!pdata)  		return NULL; -	}  	for (i = 0; i < num; i++) {  		int id; @@ -347,10 +444,11 @@ static int tps6586x_regulator_probe(struct platform_device *pdev)  {  	struct tps6586x_regulator *ri = NULL;  	struct regulator_config config = { }; -	struct regulator_dev **rdev; +	struct regulator_dev *rdev;  	struct regulator_init_data *reg_data;  	struct tps6586x_platform_data *pdata;  	struct of_regulator_match *tps6586x_reg_matches = NULL; +	int version;  	int id;  	int err; @@ -366,28 +464,23 @@ static int tps6586x_regulator_probe(struct platform_device *pdev)  		return -ENODEV;  	} -	rdev = devm_kzalloc(&pdev->dev, TPS6586X_ID_MAX_REGULATOR * -				sizeof(*rdev), GFP_KERNEL); -	if (!rdev) { -		dev_err(&pdev->dev, "Mmemory alloc failed\n"); -		return -ENOMEM; -	} +	version = tps6586x_get_version(pdev->dev.parent);  	for (id = 0; id < TPS6586X_ID_MAX_REGULATOR; ++id) {  		reg_data = pdata->reg_init_data[id]; -		ri = find_regulator_info(id); +		ri = find_regulator_info(id, version); +  		if (!ri) {  			dev_err(&pdev->dev, "invalid regulator ID specified\n"); -			err = -EINVAL; -			goto fail; +			return -EINVAL;  		}  		err = tps6586x_regulator_preinit(pdev->dev.parent, ri);  		if (err) {  			dev_err(&pdev->dev,  				"regulator %d preinit failed, e %d\n", id, err); -			goto fail; +			return err;  		}  		config.dev = pdev->dev.parent; @@ -397,12 +490,11 @@ static int tps6586x_regulator_probe(struct platform_device *pdev)  		if (tps6586x_reg_matches)  			config.of_node = tps6586x_reg_matches[id].of_node; -		rdev[id] = regulator_register(&ri->desc, &config); -		if (IS_ERR(rdev[id])) { +		rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config); +		if (IS_ERR(rdev)) {  			dev_err(&pdev->dev, "failed to register regulator %s\n",  					ri->desc.name); -			err = PTR_ERR(rdev[id]); -			goto fail; +			return PTR_ERR(rdev);  		}  		if (reg_data) { @@ -411,30 +503,13 @@ static int tps6586x_regulator_probe(struct platform_device *pdev)  			if (err < 0) {  				dev_err(&pdev->dev,  					"Slew rate config failed, e %d\n", err); -				regulator_unregister(rdev[id]); -				goto fail; +				return err;  			}  		}  	}  	platform_set_drvdata(pdev, rdev);  	return 0; - -fail: -	while (--id >= 0) -		regulator_unregister(rdev[id]); -	return err; -} - -static int tps6586x_regulator_remove(struct platform_device *pdev) -{ -	struct regulator_dev **rdev = platform_get_drvdata(pdev); -	int id = TPS6586X_ID_MAX_REGULATOR; - -	while (--id >= 0) -		regulator_unregister(rdev[id]); - -	return 0;  }  static struct platform_driver tps6586x_regulator_driver = { @@ -443,7 +518,6 @@ static struct platform_driver tps6586x_regulator_driver = {  		.owner	= THIS_MODULE,  	},  	.probe		= tps6586x_regulator_probe, -	.remove		= tps6586x_regulator_remove,  };  static int __init tps6586x_regulator_init(void) diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index 45c16447744..fa7db884757 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -88,6 +88,11 @@ static const unsigned int VMMC_VSEL_table[] = {  	1800000, 2800000, 3000000, 3300000,  }; +/* supported BBCH voltages in microvolts */ +static const unsigned int VBB_VSEL_table[] = { +	3000000, 2520000, 3150000, 5000000, +}; +  struct tps_info {  	const char *name;  	const char *vin_name; @@ -183,6 +188,12 @@ static struct tps_info tps65910_regs[] = {  		.voltage_table = VMMC_VSEL_table,  		.enable_time_us = 100,  	}, +	{ +		.name = "vbb", +		.vin_name = "vcc7", +		.n_voltages = ARRAY_SIZE(VBB_VSEL_table), +		.voltage_table = VBB_VSEL_table, +	},  };  static struct tps_info tps65911_regs[] = { @@ -339,6 +350,8 @@ static int tps65910_get_ctrl_register(int id)  		return TPS65910_VAUX33;  	case TPS65910_REG_VMMC:  		return TPS65910_VMMC; +	case TPS65910_REG_VBB: +		return TPS65910_BBCH;  	default:  		return -EINVAL;  	} @@ -481,7 +494,7 @@ static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev)  	/* multiplier 0 == 1 but 2,3 normal */  	if (!mult) -		mult=1; +		mult = 1;  	if (sr) {  		/* normalise to valid range */ @@ -528,6 +541,10 @@ static int tps65910_get_voltage_sel(struct regulator_dev *dev)  		value &= LDO_SEL_MASK;  		value >>= LDO_SEL_SHIFT;  		break; +	case TPS65910_REG_VBB: +		value &= BBCH_BBSEL_MASK; +		value >>= BBCH_BBSEL_SHIFT; +		break;  	default:  		return -EINVAL;  	} @@ -638,6 +655,9 @@ static int tps65910_set_voltage_sel(struct regulator_dev *dev,  	case TPS65910_REG_VMMC:  		return tps65910_reg_update_bits(pmic->mfd, reg, LDO_SEL_MASK,  						selector << LDO_SEL_SHIFT); +	case TPS65910_REG_VBB: +		return tps65910_reg_update_bits(pmic->mfd, reg, BBCH_BBSEL_MASK, +						selector << BBCH_BBSEL_SHIFT);  	}  	return -EINVAL; @@ -669,6 +689,9 @@ static int tps65911_set_voltage_sel(struct regulator_dev *dev,  	case TPS65910_REG_VIO:  		return tps65910_reg_update_bits(pmic->mfd, reg, LDO_SEL_MASK,  						selector << LDO_SEL_SHIFT); +	case TPS65910_REG_VBB: +		return tps65910_reg_update_bits(pmic->mfd, reg, BBCH_BBSEL_MASK, +						selector << BBCH_BBSEL_SHIFT);  	}  	return -EINVAL; @@ -685,7 +708,7 @@ static int tps65910_list_voltage_dcdc(struct regulator_dev *dev,  	case TPS65910_REG_VDD2:  		mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1;  		volt = VDD1_2_MIN_VOLT + -				(selector % VDD1_2_NUM_VOLT_FINE) * VDD1_2_OFFSET; +			(selector % VDD1_2_NUM_VOLT_FINE) * VDD1_2_OFFSET;  		break;  	case TPS65911_REG_VDDCTRL:  		volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET); @@ -703,7 +726,7 @@ static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector)  	struct tps65910_reg *pmic = rdev_get_drvdata(dev);  	int step_mv = 0, id = rdev_get_id(dev); -	switch(id) { +	switch (id) {  	case TPS65911_REG_LDO1:  	case TPS65911_REG_LDO2:  	case TPS65911_REG_LDO4: @@ -762,6 +785,18 @@ static struct regulator_ops tps65910_ops_vdd3 = {  	.map_voltage		= regulator_map_voltage_ascend,  }; +static struct regulator_ops tps65910_ops_vbb = { +	.is_enabled		= regulator_is_enabled_regmap, +	.enable			= regulator_enable_regmap, +	.disable		= regulator_disable_regmap, +	.set_mode		= tps65910_set_mode, +	.get_mode		= tps65910_get_mode, +	.get_voltage_sel	= tps65910_get_voltage_sel, +	.set_voltage_sel	= tps65910_set_voltage_sel, +	.list_voltage		= regulator_list_voltage_table, +	.map_voltage		= regulator_map_voltage_iterate, +}; +  static struct regulator_ops tps65910_ops = {  	.is_enabled		= regulator_is_enabled_regmap,  	.enable			= regulator_enable_regmap, @@ -906,7 +941,7 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic,  		}  		ret = tps65910_reg_write(pmic->mfd, sr_reg_add, 0);  		if (ret < 0) { -			dev_err(mfd->dev, "Error in settting sr register\n"); +			dev_err(mfd->dev, "Error in setting sr register\n");  			return ret;  		}  	} @@ -944,6 +979,7 @@ static struct of_regulator_match tps65910_matches[] = {  	{ .name = "vaux2",	.driver_data = (void *) &tps65910_regs[10] },  	{ .name = "vaux33",	.driver_data = (void *) &tps65910_regs[11] },  	{ .name = "vmmc",	.driver_data = (void *) &tps65910_regs[12] }, +	{ .name = "vbb",	.driver_data = (void *) &tps65910_regs[13] },  };  static struct of_regulator_match tps65911_matches[] = { @@ -975,14 +1011,11 @@ static struct tps65910_board *tps65910_parse_dt_reg_data(  	pmic_plat_data = devm_kzalloc(&pdev->dev, sizeof(*pmic_plat_data),  					GFP_KERNEL); - -	if (!pmic_plat_data) { -		dev_err(&pdev->dev, "Failure to alloc pdata for regulators.\n"); +	if (!pmic_plat_data)  		return NULL; -	}  	np = of_node_get(pdev->dev.parent->of_node); -	regulators = of_find_node_by_name(np, "regulators"); +	regulators = of_get_child_by_name(np, "regulators");  	if (!regulators) {  		dev_err(&pdev->dev, "regulator node not found\n");  		return NULL; @@ -1062,10 +1095,8 @@ static int tps65910_probe(struct platform_device *pdev)  	}  	pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); -	if (!pmic) { -		dev_err(&pdev->dev, "Memory allocation failed for pmic\n"); +	if (!pmic)  		return -ENOMEM; -	}  	pmic->mfd = tps65910;  	platform_set_drvdata(pdev, pmic); @@ -1074,7 +1105,7 @@ static int tps65910_probe(struct platform_device *pdev)  	tps65910_reg_set_bits(pmic->mfd, TPS65910_DEVCTRL,  				DEVCTRL_SR_CTL_I2C_SEL_MASK); -	switch(tps65910_chip_id(tps65910)) { +	switch (tps65910_chip_id(tps65910)) {  	case TPS65910:  		pmic->get_ctrl_reg = &tps65910_get_ctrl_register;  		pmic->num_regulators = ARRAY_SIZE(tps65910_regs); @@ -1094,24 +1125,18 @@ static int tps65910_probe(struct platform_device *pdev)  	pmic->desc = devm_kzalloc(&pdev->dev, pmic->num_regulators *  			sizeof(struct regulator_desc), GFP_KERNEL); -	if (!pmic->desc) { -		dev_err(&pdev->dev, "Memory alloc fails for desc\n"); +	if (!pmic->desc)  		return -ENOMEM; -	}  	pmic->info = devm_kzalloc(&pdev->dev, pmic->num_regulators *  			sizeof(struct tps_info *), GFP_KERNEL); -	if (!pmic->info) { -		dev_err(&pdev->dev, "Memory alloc fails for info\n"); +	if (!pmic->info)  		return -ENOMEM; -	}  	pmic->rdev = devm_kzalloc(&pdev->dev, pmic->num_regulators *  			sizeof(struct regulator_dev *), GFP_KERNEL); -	if (!pmic->rdev) { -		dev_err(&pdev->dev, "Memory alloc fails for rdev\n"); +	if (!pmic->rdev)  		return -ENOMEM; -	}  	for (i = 0; i < pmic->num_regulators && i < TPS65910_NUM_REGS;  			i++, info++) { @@ -1145,6 +1170,10 @@ static int tps65910_probe(struct platform_device *pdev)  				pmic->desc[i].ops = &tps65910_ops_dcdc;  				pmic->desc[i].ramp_delay = 5000;  			} +		} else if (i == TPS65910_REG_VBB && +				tps65910_chip_id(tps65910) == TPS65910) { +			pmic->desc[i].ops = &tps65910_ops_vbb; +			pmic->desc[i].volt_table = info->voltage_table;  		} else {  			if (tps65910_chip_id(tps65910) == TPS65910) {  				pmic->desc[i].ops = &tps65910_ops; @@ -1177,35 +1206,19 @@ static int tps65910_probe(struct platform_device *pdev)  		if (tps65910_reg_matches)  			config.of_node = tps65910_reg_matches[i].of_node; -		rdev = regulator_register(&pmic->desc[i], &config); +		rdev = devm_regulator_register(&pdev->dev, &pmic->desc[i], +					       &config);  		if (IS_ERR(rdev)) {  			dev_err(tps65910->dev,  				"failed to register %s regulator\n",  				pdev->name); -			err = PTR_ERR(rdev); -			goto err_unregister_regulator; +			return PTR_ERR(rdev);  		}  		/* Save regulator for cleanup */  		pmic->rdev[i] = rdev;  	}  	return 0; - -err_unregister_regulator: -	while (--i >= 0) -		regulator_unregister(pmic->rdev[i]); -	return err; -} - -static int tps65910_remove(struct platform_device *pdev) -{ -	struct tps65910_reg *pmic = platform_get_drvdata(pdev); -	int i; - -	for (i = 0; i < pmic->num_regulators; i++) -		regulator_unregister(pmic->rdev[i]); - -	return 0;  }  static void tps65910_shutdown(struct platform_device *pdev) @@ -1244,7 +1257,6 @@ static struct platform_driver tps65910_driver = {  		.owner = THIS_MODULE,  	},  	.probe = tps65910_probe, -	.remove = tps65910_remove,  	.shutdown = tps65910_shutdown,  }; diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c index 281e52ac64b..9cafaa0f945 100644 --- a/drivers/regulator/tps65912-regulator.c +++ b/drivers/regulator/tps65912-regulator.c @@ -119,12 +119,9 @@ struct tps65912_reg {  };  static const struct regulator_linear_range tps65912_ldo_ranges[] = { -	{ .min_uV = 800000, .max_uV = 1600000, .min_sel =  0, .max_sel = 32, -	  .uV_step = 25000 }, -	{ .min_uV = 1650000, .max_uV = 3000000, .min_sel = 33, .max_sel = 60, -	  .uV_step = 50000 }, -	{ .min_uV = 3100000, .max_uV = 3300000, .min_sel = 61, .max_sel = 63, -	  .uV_step = 100000 }, +	REGULATOR_LINEAR_RANGE(800000, 0, 32, 25000), +	REGULATOR_LINEAR_RANGE(1650000, 33, 60, 50000), +	REGULATOR_LINEAR_RANGE(3100000, 61, 63, 100000),  };  static int tps65912_get_range(struct tps65912_reg *pmic, int id) @@ -461,7 +458,7 @@ static int tps65912_probe(struct platform_device *pdev)  	struct regulator_dev *rdev;  	struct tps65912_reg *pmic;  	struct tps65912_board *pmic_plat_data; -	int i, err; +	int i;  	pmic_plat_data = dev_get_platdata(tps65912->dev);  	if (!pmic_plat_data) @@ -504,34 +501,19 @@ static int tps65912_probe(struct platform_device *pdev)  		config.init_data = reg_data;  		config.driver_data = pmic; -		rdev = regulator_register(&pmic->desc[i], &config); +		rdev = devm_regulator_register(&pdev->dev, &pmic->desc[i], +					       &config);  		if (IS_ERR(rdev)) {  			dev_err(tps65912->dev,  				"failed to register %s regulator\n",  				pdev->name); -			err = PTR_ERR(rdev); -			goto err; +			return PTR_ERR(rdev);  		}  		/* Save regulator for cleanup */  		pmic->rdev[i] = rdev;  	}  	return 0; - -err: -	while (--i >= 0) -		regulator_unregister(pmic->rdev[i]); -	return err; -} - -static int tps65912_remove(struct platform_device *pdev) -{ -	struct tps65912_reg *tps65912_reg = platform_get_drvdata(pdev); -	int i; - -	for (i = 0; i < TPS65912_NUM_REGULATOR; i++) -		regulator_unregister(tps65912_reg->rdev[i]); -	return 0;  }  static struct platform_driver tps65912_driver = { @@ -540,7 +522,6 @@ static struct platform_driver tps65912_driver = {  		.owner = THIS_MODULE,  	},  	.probe = tps65912_probe, -	.remove = tps65912_remove,  };  static int __init tps65912_init(void) diff --git a/drivers/regulator/tps80031-regulator.c b/drivers/regulator/tps80031-regulator.c index 6511d0bfd89..26aa6d9c308 100644 --- a/drivers/regulator/tps80031-regulator.c +++ b/drivers/regulator/tps80031-regulator.c @@ -115,7 +115,7 @@ static int tps80031_reg_is_enabled(struct regulator_dev *rdev)  			ri->rinfo->state_reg, ret);  		return ret;  	} -	return ((reg_val & TPS80031_STATE_MASK) == TPS80031_STATE_ON); +	return (reg_val & TPS80031_STATE_MASK) == TPS80031_STATE_ON;  }  static int tps80031_reg_enable(struct regulator_dev *rdev) @@ -693,10 +693,8 @@ static int tps80031_regulator_probe(struct platform_device *pdev)  	pmic = devm_kzalloc(&pdev->dev,  			TPS80031_REGULATOR_MAX * sizeof(*pmic), GFP_KERNEL); -	if (!pmic) { -		dev_err(&pdev->dev, "mem alloc for pmic failed\n"); +	if (!pmic)  		return -ENOMEM; -	}  	for (num = 0; num < TPS80031_REGULATOR_MAX; ++num) {  		tps_pdata = pdata->regulator_pdata[num]; @@ -719,7 +717,7 @@ static int tps80031_regulator_probe(struct platform_device *pdev)  			if (ret < 0) {  				dev_err(&pdev->dev,  					"regulator config failed, e %d\n", ret); -				goto fail; +				return ret;  			}  			ret = tps80031_power_req_config(pdev->dev.parent, @@ -727,41 +725,22 @@ static int tps80031_regulator_probe(struct platform_device *pdev)  			if (ret < 0) {  				dev_err(&pdev->dev,  					"pwr_req config failed, err %d\n", ret); -				goto fail; +				return ret;  			}  		} -		rdev = regulator_register(&ri->rinfo->desc, &config); +		rdev = devm_regulator_register(&pdev->dev, &ri->rinfo->desc, +					       &config);  		if (IS_ERR(rdev)) {  			dev_err(&pdev->dev,  				"register regulator failed %s\n",  					ri->rinfo->desc.name); -			ret = PTR_ERR(rdev); -			goto fail; +			return PTR_ERR(rdev);  		}  		ri->rdev = rdev;  	}  	platform_set_drvdata(pdev, pmic);  	return 0; -fail: -	while (--num >= 0) { -		ri = &pmic[num]; -		regulator_unregister(ri->rdev); -	} -	return ret; -} - -static int tps80031_regulator_remove(struct platform_device *pdev) -{ -	struct tps80031_regulator *pmic = platform_get_drvdata(pdev); -	struct tps80031_regulator *ri = NULL; -	int num; - -	for (num = 0; num < TPS80031_REGULATOR_MAX; ++num) { -		ri = &pmic[num]; -		regulator_unregister(ri->rdev); -	} -	return 0;  }  static struct platform_driver tps80031_regulator_driver = { @@ -770,7 +749,6 @@ static struct platform_driver tps80031_regulator_driver = {  		.owner	= THIS_MODULE,  	},  	.probe		= tps80031_regulator_probe, -	.remove		= tps80031_regulator_remove,  };  static int __init tps80031_regulator_init(void) diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 78aae4cbb00..fed28abef41 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -58,7 +58,7 @@ struct twlreg_info {  	struct regulator_desc	desc;  	/* chip specific features */ -	unsigned long 		features; +	unsigned long		features;  	/*  	 * optional override functions for voltage set/get @@ -1128,7 +1128,7 @@ static int twlreg_probe(struct platform_device *pdev)  	if (!initdata)  		return -EINVAL; -	info = kmemdup(template, sizeof (*info), GFP_KERNEL); +	info = kmemdup(template, sizeof(*info), GFP_KERNEL);  	if (!info)  		return -ENOMEM; @@ -1188,7 +1188,7 @@ static int twlreg_probe(struct platform_device *pdev)  	config.driver_data = info;  	config.of_node = pdev->dev.of_node; -	rdev = regulator_register(&info->desc, &config); +	rdev = devm_regulator_register(&pdev->dev, &info->desc, &config);  	if (IS_ERR(rdev)) {  		dev_err(&pdev->dev, "can't register %s, %ld\n",  				info->desc.name, PTR_ERR(rdev)); @@ -1217,7 +1217,6 @@ static int twlreg_remove(struct platform_device *pdev)  	struct regulator_dev *rdev = platform_get_drvdata(pdev);  	struct twlreg_info *info = rdev->reg_data; -	regulator_unregister(rdev);  	kfree(info);  	return 0;  } diff --git a/drivers/regulator/vexpress.c b/drivers/regulator/vexpress.c index 4668c7f8133..02e7267ccf9 100644 --- a/drivers/regulator/vexpress.c +++ b/drivers/regulator/vexpress.c @@ -26,14 +26,14 @@  struct vexpress_regulator {  	struct regulator_desc desc;  	struct regulator_dev *regdev; -	struct vexpress_config_func *func; +	struct regmap *regmap;  };  static int vexpress_regulator_get_voltage(struct regulator_dev *regdev)  {  	struct vexpress_regulator *reg = rdev_get_drvdata(regdev);  	u32 uV; -	int err = vexpress_config_read(reg->func, 0, &uV); +	int err = regmap_read(reg->regmap, 0, &uV);  	return err ? err : uV;  } @@ -43,7 +43,7 @@ static int vexpress_regulator_set_voltage(struct regulator_dev *regdev,  {  	struct vexpress_regulator *reg = rdev_get_drvdata(regdev); -	return vexpress_config_write(reg->func, 0, min_uV); +	return regmap_write(reg->regmap, 0, min_uV);  }  static struct regulator_ops vexpress_regulator_ops_ro = { @@ -57,22 +57,17 @@ static struct regulator_ops vexpress_regulator_ops = {  static int vexpress_regulator_probe(struct platform_device *pdev)  { -	int err;  	struct vexpress_regulator *reg;  	struct regulator_init_data *init_data;  	struct regulator_config config = { };  	reg = devm_kzalloc(&pdev->dev, sizeof(*reg), GFP_KERNEL); -	if (!reg) { -		err = -ENOMEM; -		goto error_kzalloc; -	} +	if (!reg) +		return -ENOMEM; -	reg->func = vexpress_config_func_get_by_dev(&pdev->dev); -	if (!reg->func) { -		err = -ENXIO; -		goto error_get_func; -	} +	reg->regmap = devm_regmap_init_vexpress_config(&pdev->dev); +	if (IS_ERR(reg->regmap)) +		return PTR_ERR(reg->regmap);  	reg->desc.name = dev_name(&pdev->dev);  	reg->desc.type = REGULATOR_VOLTAGE; @@ -80,10 +75,8 @@ static int vexpress_regulator_probe(struct platform_device *pdev)  	reg->desc.continuous_voltage_range = true;  	init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node); -	if (!init_data) { -		err = -EINVAL; -		goto error_get_regulator_init_data; -	} +	if (!init_data) +		return -EINVAL;  	init_data->constraints.apply_uV = 0;  	if (init_data->constraints.min_uV && init_data->constraints.max_uV) @@ -96,42 +89,22 @@ static int vexpress_regulator_probe(struct platform_device *pdev)  	config.driver_data = reg;  	config.of_node = pdev->dev.of_node; -	reg->regdev = regulator_register(®->desc, &config); -	if (IS_ERR(reg->regdev)) { -		err = PTR_ERR(reg->regdev); -		goto error_regulator_register; -	} +	reg->regdev = devm_regulator_register(&pdev->dev, ®->desc, &config); +	if (IS_ERR(reg->regdev)) +		return PTR_ERR(reg->regdev);  	platform_set_drvdata(pdev, reg);  	return 0; - -error_regulator_register: -error_get_regulator_init_data: -	vexpress_config_func_put(reg->func); -error_get_func: -error_kzalloc: -	return err; -} - -static int vexpress_regulator_remove(struct platform_device *pdev) -{ -	struct vexpress_regulator *reg = platform_get_drvdata(pdev); - -	vexpress_config_func_put(reg->func); -	regulator_unregister(reg->regdev); - -	return 0;  } -static struct of_device_id vexpress_regulator_of_match[] = { +static const struct of_device_id vexpress_regulator_of_match[] = {  	{ .compatible = "arm,vexpress-volt", },  	{ }  };  static struct platform_driver vexpress_regulator_driver = {  	.probe = vexpress_regulator_probe, -	.remove = vexpress_regulator_remove,  	.driver	= {  		.name = DRVNAME,  		.owner = THIS_MODULE, diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index f53e78b9a84..6ff95b04598 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -266,11 +266,11 @@ static ssize_t set_mode(struct device *dev, struct device_attribute *attr,  	return count;  } -static DEVICE_ATTR(min_microvolts, 0666, show_min_uV, set_min_uV); -static DEVICE_ATTR(max_microvolts, 0666, show_max_uV, set_max_uV); -static DEVICE_ATTR(min_microamps, 0666, show_min_uA, set_min_uA); -static DEVICE_ATTR(max_microamps, 0666, show_max_uA, set_max_uA); -static DEVICE_ATTR(mode, 0666, show_mode, set_mode); +static DEVICE_ATTR(min_microvolts, 0664, show_min_uV, set_min_uV); +static DEVICE_ATTR(max_microvolts, 0664, show_max_uV, set_max_uV); +static DEVICE_ATTR(min_microamps, 0664, show_min_uA, set_min_uA); +static DEVICE_ATTR(max_microamps, 0664, show_max_uA, set_max_uA); +static DEVICE_ATTR(mode, 0664, show_mode, set_mode);  static struct attribute *regulator_virtual_attributes[] = {  	&dev_attr_min_microvolts.attr, diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 11861cb861d..0d88a82ab2a 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -387,8 +387,9 @@ static struct regulator_ops wm831x_buckv_ops = {   * Set up DVS control.  We just log errors since we can still run   * (with reduced performance) if we fail.   */ -static void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc, -					    struct wm831x_buckv_pdata *pdata) +static void wm831x_buckv_dvs_init(struct platform_device *pdev, +				  struct wm831x_dcdc *dcdc, +				  struct wm831x_buckv_pdata *pdata)  {  	struct wm831x *wm831x = dcdc->wm831x;  	int ret; @@ -402,9 +403,9 @@ static void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc,  	 */  	dcdc->dvs_gpio_state = pdata->dvs_init_state; -	ret = gpio_request_one(pdata->dvs_gpio, -			       dcdc->dvs_gpio_state ? GPIOF_INIT_HIGH : 0, -			       "DCDC DVS"); +	ret = devm_gpio_request_one(&pdev->dev, pdata->dvs_gpio, +				    dcdc->dvs_gpio_state ? GPIOF_INIT_HIGH : 0, +				    "DCDC DVS");  	if (ret < 0) {  		dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n",  			dcdc->name, ret); @@ -468,10 +469,8 @@ static int wm831x_buckv_probe(struct platform_device *pdev)  	dcdc = devm_kzalloc(&pdev->dev,  sizeof(struct wm831x_dcdc),  			    GFP_KERNEL); -	if (dcdc == NULL) { -		dev_err(&pdev->dev, "Unable to allocate private data\n"); +	if (!dcdc)  		return -ENOMEM; -	}  	dcdc->wm831x = wm831x; @@ -513,7 +512,8 @@ static int wm831x_buckv_probe(struct platform_device *pdev)  	dcdc->dvs_vsel = ret & WM831X_DC1_DVS_VSEL_MASK;  	if (pdata && pdata->dcdc[id]) -		wm831x_buckv_dvs_init(dcdc, pdata->dcdc[id]->driver_data); +		wm831x_buckv_dvs_init(pdev, dcdc, +				      pdata->dcdc[id]->driver_data);  	config.dev = pdev->dev.parent;  	if (pdata) @@ -521,7 +521,8 @@ static int wm831x_buckv_probe(struct platform_device *pdev)  	config.driver_data = dcdc;  	config.regmap = wm831x->regmap; -	dcdc->regulator = regulator_register(&dcdc->desc, &config); +	dcdc->regulator = devm_regulator_register(&pdev->dev, &dcdc->desc, +						  &config);  	if (IS_ERR(dcdc->regulator)) {  		ret = PTR_ERR(dcdc->regulator);  		dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n", @@ -530,57 +531,35 @@ static int wm831x_buckv_probe(struct platform_device *pdev)  	}  	irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV")); -	ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq, -				   IRQF_TRIGGER_RISING, dcdc->name, dcdc); +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, +					wm831x_dcdc_uv_irq, +					IRQF_TRIGGER_RISING, dcdc->name, dcdc);  	if (ret != 0) {  		dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",  			irq, ret); -		goto err_regulator; +		goto err;  	}  	irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "HC")); -	ret = request_threaded_irq(irq, NULL, wm831x_dcdc_oc_irq, -				   IRQF_TRIGGER_RISING, dcdc->name, dcdc); +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, +					wm831x_dcdc_oc_irq, +					IRQF_TRIGGER_RISING, dcdc->name, dcdc);  	if (ret != 0) {  		dev_err(&pdev->dev, "Failed to request HC IRQ %d: %d\n",  			irq, ret); -		goto err_uv; +		goto err;  	}  	platform_set_drvdata(pdev, dcdc);  	return 0; -err_uv: -	free_irq(wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV")), -		 dcdc); -err_regulator: -	regulator_unregister(dcdc->regulator);  err: -	if (dcdc->dvs_gpio) -		gpio_free(dcdc->dvs_gpio);  	return ret;  } -static int wm831x_buckv_remove(struct platform_device *pdev) -{ -	struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); -	struct wm831x *wm831x = dcdc->wm831x; - -	free_irq(wm831x_irq(wm831x, platform_get_irq_byname(pdev, "HC")), -			    dcdc); -	free_irq(wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV")), -			    dcdc); -	regulator_unregister(dcdc->regulator); -	if (dcdc->dvs_gpio) -		gpio_free(dcdc->dvs_gpio); - -	return 0; -} -  static struct platform_driver wm831x_buckv_driver = {  	.probe = wm831x_buckv_probe, -	.remove = wm831x_buckv_remove,  	.driver		= {  		.name	= "wm831x-buckv",  		.owner	= THIS_MODULE, @@ -641,10 +620,8 @@ static int wm831x_buckp_probe(struct platform_device *pdev)  	dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc),  			    GFP_KERNEL); -	if (dcdc == NULL) { -		dev_err(&pdev->dev, "Unable to allocate private data\n"); +	if (!dcdc)  		return -ENOMEM; -	}  	dcdc->wm831x = wm831x; @@ -681,7 +658,8 @@ static int wm831x_buckp_probe(struct platform_device *pdev)  	config.driver_data = dcdc;  	config.regmap = wm831x->regmap; -	dcdc->regulator = regulator_register(&dcdc->desc, &config); +	dcdc->regulator = devm_regulator_register(&pdev->dev, &dcdc->desc, +						  &config);  	if (IS_ERR(dcdc->regulator)) {  		ret = PTR_ERR(dcdc->regulator);  		dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n", @@ -690,38 +668,25 @@ static int wm831x_buckp_probe(struct platform_device *pdev)  	}  	irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV")); -	ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq, -				   IRQF_TRIGGER_RISING,	dcdc->name, dcdc); +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, +					wm831x_dcdc_uv_irq, +					IRQF_TRIGGER_RISING, dcdc->name, dcdc);  	if (ret != 0) {  		dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",  			irq, ret); -		goto err_regulator; +		goto err;  	}  	platform_set_drvdata(pdev, dcdc);  	return 0; -err_regulator: -	regulator_unregister(dcdc->regulator);  err:  	return ret;  } -static int wm831x_buckp_remove(struct platform_device *pdev) -{ -	struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); - -	free_irq(wm831x_irq(dcdc->wm831x, platform_get_irq_byname(pdev, "UV")), -			    dcdc); -	regulator_unregister(dcdc->regulator); - -	return 0; -} -  static struct platform_driver wm831x_buckp_driver = {  	.probe = wm831x_buckp_probe, -	.remove = wm831x_buckp_remove,  	.driver		= {  		.name	= "wm831x-buckp",  		.owner	= THIS_MODULE, @@ -783,18 +748,15 @@ static int wm831x_boostp_probe(struct platform_device *pdev)  		return -ENODEV;  	dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL); -	if (dcdc == NULL) { -		dev_err(&pdev->dev, "Unable to allocate private data\n"); +	if (!dcdc)  		return -ENOMEM; -	}  	dcdc->wm831x = wm831x;  	res = platform_get_resource(pdev, IORESOURCE_REG, 0);  	if (res == NULL) {  		dev_err(&pdev->dev, "No REG resource\n"); -		ret = -EINVAL; -		goto err; +		return -EINVAL;  	}  	dcdc->base = res->start; @@ -813,48 +775,33 @@ static int wm831x_boostp_probe(struct platform_device *pdev)  	config.driver_data = dcdc;  	config.regmap = wm831x->regmap; -	dcdc->regulator = regulator_register(&dcdc->desc, &config); +	dcdc->regulator = devm_regulator_register(&pdev->dev, &dcdc->desc, +						  &config);  	if (IS_ERR(dcdc->regulator)) {  		ret = PTR_ERR(dcdc->regulator);  		dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n",  			id + 1, ret); -		goto err; +		return ret;  	}  	irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV")); -	ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq, -				   IRQF_TRIGGER_RISING, dcdc->name, -				   dcdc); +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, +					wm831x_dcdc_uv_irq, +					IRQF_TRIGGER_RISING, dcdc->name, +					dcdc);  	if (ret != 0) {  		dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",  			irq, ret); -		goto err_regulator; +		return ret;  	}  	platform_set_drvdata(pdev, dcdc);  	return 0; - -err_regulator: -	regulator_unregister(dcdc->regulator); -err: -	return ret; -} - -static int wm831x_boostp_remove(struct platform_device *pdev) -{ -	struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); - -	free_irq(wm831x_irq(dcdc->wm831x, platform_get_irq_byname(pdev, "UV")), -		 dcdc); -	regulator_unregister(dcdc->regulator); - -	return 0;  }  static struct platform_driver wm831x_boostp_driver = {  	.probe = wm831x_boostp_probe, -	.remove = wm831x_boostp_remove,  	.driver		= {  		.name	= "wm831x-boostp",  		.owner	= THIS_MODULE, @@ -889,10 +836,8 @@ static int wm831x_epe_probe(struct platform_device *pdev)  	dev_dbg(&pdev->dev, "Probing EPE%d\n", id + 1);  	dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL); -	if (dcdc == NULL) { -		dev_err(&pdev->dev, "Unable to allocate private data\n"); +	if (!dcdc)  		return -ENOMEM; -	}  	dcdc->wm831x = wm831x; @@ -914,7 +859,8 @@ static int wm831x_epe_probe(struct platform_device *pdev)  	config.driver_data = dcdc;  	config.regmap = wm831x->regmap; -	dcdc->regulator = regulator_register(&dcdc->desc, &config); +	dcdc->regulator = devm_regulator_register(&pdev->dev, &dcdc->desc, +						  &config);  	if (IS_ERR(dcdc->regulator)) {  		ret = PTR_ERR(dcdc->regulator);  		dev_err(wm831x->dev, "Failed to register EPE%d: %d\n", @@ -930,18 +876,8 @@ err:  	return ret;  } -static int wm831x_epe_remove(struct platform_device *pdev) -{ -	struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); - -	regulator_unregister(dcdc->regulator); - -	return 0; -} -  static struct platform_driver wm831x_epe_driver = {  	.probe = wm831x_epe_probe, -	.remove = wm831x_epe_remove,  	.driver		= {  		.name	= "wm831x-epe",  		.owner	= THIS_MODULE, diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c index 4eb373de1fa..72e385e76a9 100644 --- a/drivers/regulator/wm831x-isink.c +++ b/drivers/regulator/wm831x-isink.c @@ -165,10 +165,8 @@ static int wm831x_isink_probe(struct platform_device *pdev)  	isink = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_isink),  			     GFP_KERNEL); -	if (isink == NULL) { -		dev_err(&pdev->dev, "Unable to allocate private data\n"); +	if (!isink)  		return -ENOMEM; -	}  	isink->wm831x = wm831x; @@ -194,7 +192,8 @@ static int wm831x_isink_probe(struct platform_device *pdev)  	config.init_data = pdata->isink[id];  	config.driver_data = isink; -	isink->regulator = regulator_register(&isink->desc, &config); +	isink->regulator = devm_regulator_register(&pdev->dev, &isink->desc, +						   &config);  	if (IS_ERR(isink->regulator)) {  		ret = PTR_ERR(isink->regulator);  		dev_err(wm831x->dev, "Failed to register ISINK%d: %d\n", @@ -203,38 +202,26 @@ static int wm831x_isink_probe(struct platform_device *pdev)  	}  	irq = wm831x_irq(wm831x, platform_get_irq(pdev, 0)); -	ret = request_threaded_irq(irq, NULL, wm831x_isink_irq, -				   IRQF_TRIGGER_RISING, isink->name, isink); +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, +					wm831x_isink_irq, +					IRQF_TRIGGER_RISING, isink->name, +					isink);  	if (ret != 0) {  		dev_err(&pdev->dev, "Failed to request ISINK IRQ %d: %d\n",  			irq, ret); -		goto err_regulator; +		goto err;  	}  	platform_set_drvdata(pdev, isink);  	return 0; -err_regulator: -	regulator_unregister(isink->regulator);  err:  	return ret;  } -static int wm831x_isink_remove(struct platform_device *pdev) -{ -	struct wm831x_isink *isink = platform_get_drvdata(pdev); - -	free_irq(wm831x_irq(isink->wm831x, platform_get_irq(pdev, 0)), isink); - -	regulator_unregister(isink->regulator); - -	return 0; -} -  static struct platform_driver wm831x_isink_driver = {  	.probe = wm831x_isink_probe, -	.remove = wm831x_isink_remove,  	.driver		= {  		.name	= "wm831x-isink",  		.owner	= THIS_MODULE, diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 1432b26ef2e..eca0eeb78ac 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -63,10 +63,8 @@ static irqreturn_t wm831x_ldo_uv_irq(int irq, void *data)   */  static const struct regulator_linear_range wm831x_gp_ldo_ranges[] = { -	{ .min_uV =  900000, .max_uV = 1650000, .min_sel =  0, .max_sel = 14, -	  .uV_step =  50000 }, -	{ .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31, -	  .uV_step = 100000 }, +	REGULATOR_LINEAR_RANGE(900000, 0, 14, 50000), +	REGULATOR_LINEAR_RANGE(1700000, 15, 31, 100000),  };  static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, @@ -237,10 +235,8 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev)  	dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);  	ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL); -	if (ldo == NULL) { -		dev_err(&pdev->dev, "Unable to allocate private data\n"); +	if (!ldo)  		return -ENOMEM; -	}  	ldo->wm831x = wm831x; @@ -279,7 +275,8 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev)  	config.driver_data = ldo;  	config.regmap = wm831x->regmap; -	ldo->regulator = regulator_register(&ldo->desc, &config); +	ldo->regulator = devm_regulator_register(&pdev->dev, &ldo->desc, +						 &config);  	if (IS_ERR(ldo->regulator)) {  		ret = PTR_ERR(ldo->regulator);  		dev_err(wm831x->dev, "Failed to register LDO%d: %d\n", @@ -288,39 +285,26 @@ static int wm831x_gp_ldo_probe(struct platform_device *pdev)  	}  	irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV")); -	ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq, -				   IRQF_TRIGGER_RISING, ldo->name, -				   ldo); +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, +					wm831x_ldo_uv_irq, +					IRQF_TRIGGER_RISING, ldo->name, +					ldo);  	if (ret != 0) {  		dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",  			irq, ret); -		goto err_regulator; +		goto err;  	}  	platform_set_drvdata(pdev, ldo);  	return 0; -err_regulator: -	regulator_unregister(ldo->regulator);  err:  	return ret;  } -static int wm831x_gp_ldo_remove(struct platform_device *pdev) -{ -	struct wm831x_ldo *ldo = platform_get_drvdata(pdev); - -	free_irq(wm831x_irq(ldo->wm831x, -			    platform_get_irq_byname(pdev, "UV")), ldo); -	regulator_unregister(ldo->regulator); - -	return 0; -} -  static struct platform_driver wm831x_gp_ldo_driver = {  	.probe = wm831x_gp_ldo_probe, -	.remove = wm831x_gp_ldo_remove,  	.driver		= {  		.name	= "wm831x-ldo",  		.owner	= THIS_MODULE, @@ -332,10 +316,8 @@ static struct platform_driver wm831x_gp_ldo_driver = {   */  static const struct regulator_linear_range wm831x_aldo_ranges[] = { -	{ .min_uV = 1000000, .max_uV = 1650000, .min_sel =  0, .max_sel = 12, -	  .uV_step =  50000 }, -	{ .min_uV = 1700000, .max_uV = 3500000, .min_sel = 13, .max_sel = 31, -	  .uV_step = 100000 }, +	REGULATOR_LINEAR_RANGE(1000000, 0, 12, 50000), +	REGULATOR_LINEAR_RANGE(1700000, 13, 31, 100000),  };  static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, @@ -463,10 +445,8 @@ static int wm831x_aldo_probe(struct platform_device *pdev)  	dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);  	ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL); -	if (ldo == NULL) { -		dev_err(&pdev->dev, "Unable to allocate private data\n"); +	if (!ldo)  		return -ENOMEM; -	}  	ldo->wm831x = wm831x; @@ -505,7 +485,8 @@ static int wm831x_aldo_probe(struct platform_device *pdev)  	config.driver_data = ldo;  	config.regmap = wm831x->regmap; -	ldo->regulator = regulator_register(&ldo->desc, &config); +	ldo->regulator = devm_regulator_register(&pdev->dev, &ldo->desc, +						 &config);  	if (IS_ERR(ldo->regulator)) {  		ret = PTR_ERR(ldo->regulator);  		dev_err(wm831x->dev, "Failed to register LDO%d: %d\n", @@ -514,38 +495,25 @@ static int wm831x_aldo_probe(struct platform_device *pdev)  	}  	irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV")); -	ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq, -				   IRQF_TRIGGER_RISING, ldo->name, ldo); +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, +					wm831x_ldo_uv_irq, +					IRQF_TRIGGER_RISING, ldo->name, ldo);  	if (ret != 0) {  		dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",  			irq, ret); -		goto err_regulator; +		goto err;  	}  	platform_set_drvdata(pdev, ldo);  	return 0; -err_regulator: -	regulator_unregister(ldo->regulator);  err:  	return ret;  } -static int wm831x_aldo_remove(struct platform_device *pdev) -{ -	struct wm831x_ldo *ldo = platform_get_drvdata(pdev); - -	free_irq(wm831x_irq(ldo->wm831x, platform_get_irq_byname(pdev, "UV")), -		 ldo); -	regulator_unregister(ldo->regulator); - -	return 0; -} -  static struct platform_driver wm831x_aldo_driver = {  	.probe = wm831x_aldo_probe, -	.remove = wm831x_aldo_remove,  	.driver		= {  		.name	= "wm831x-aldo",  		.owner	= THIS_MODULE, @@ -622,10 +590,8 @@ static int wm831x_alive_ldo_probe(struct platform_device *pdev)  	dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);  	ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL); -	if (ldo == NULL) { -		dev_err(&pdev->dev, "Unable to allocate private data\n"); +	if (!ldo)  		return -ENOMEM; -	}  	ldo->wm831x = wm831x; @@ -663,7 +629,8 @@ static int wm831x_alive_ldo_probe(struct platform_device *pdev)  	config.driver_data = ldo;  	config.regmap = wm831x->regmap; -	ldo->regulator = regulator_register(&ldo->desc, &config); +	ldo->regulator = devm_regulator_register(&pdev->dev, &ldo->desc, +						 &config);  	if (IS_ERR(ldo->regulator)) {  		ret = PTR_ERR(ldo->regulator);  		dev_err(wm831x->dev, "Failed to register LDO%d: %d\n", @@ -679,18 +646,8 @@ err:  	return ret;  } -static int wm831x_alive_ldo_remove(struct platform_device *pdev) -{ -	struct wm831x_ldo *ldo = platform_get_drvdata(pdev); - -	regulator_unregister(ldo->regulator); - -	return 0; -} -  static struct platform_driver wm831x_alive_ldo_driver = {  	.probe = wm831x_alive_ldo_probe, -	.remove = wm831x_alive_ldo_remove,  	.driver		= {  		.name	= "wm831x-alive-ldo",  		.owner	= THIS_MODULE, diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 835b5f0f344..7ec7c390eed 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -361,7 +361,7 @@ static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)  	sel = regulator_map_voltage_linear(rdev, uV, uV);  	if (sel < 0) -		return -EINVAL; +		return sel;  	/* all DCDCs have same mV bits */  	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK; @@ -543,10 +543,8 @@ static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev,  }  static const struct regulator_linear_range wm8350_ldo_ranges[] = { -	{ .min_uV =  900000, .max_uV = 1750000, .min_sel =  0, .max_sel = 15, -	  .uV_step =  50000 }, -	{ .min_uV = 1800000, .max_uV = 3300000, .min_sel = 16, .max_sel = 31, -	  .uV_step = 100000 }, +	REGULATOR_LINEAR_RANGE(900000, 0, 15, 50000), +	REGULATOR_LINEAR_RANGE(1800000, 16, 31, 100000),  };  static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) @@ -576,7 +574,7 @@ static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)  	sel = regulator_map_voltage_linear_range(rdev, uV, uV);  	if (sel < 0) -		return -EINVAL; +		return sel;  	/* all LDOs have same mV bits */  	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK; @@ -1206,7 +1204,8 @@ static int wm8350_regulator_probe(struct platform_device *pdev)  	config.regmap = wm8350->regmap;  	/* register regulator */ -	rdev = regulator_register(&wm8350_reg[pdev->id], &config); +	rdev = devm_regulator_register(&pdev->dev, &wm8350_reg[pdev->id], +				       &config);  	if (IS_ERR(rdev)) {  		dev_err(&pdev->dev, "failed to register %s\n",  			wm8350_reg[pdev->id].name); @@ -1217,7 +1216,6 @@ static int wm8350_regulator_probe(struct platform_device *pdev)  	ret = wm8350_register_irq(wm8350, wm8350_reg[pdev->id].irq,  				  pmic_uv_handler, 0, "UV", rdev);  	if (ret < 0) { -		regulator_unregister(rdev);  		dev_err(&pdev->dev, "failed to register regulator %s IRQ\n",  			wm8350_reg[pdev->id].name);  		return ret; @@ -1233,8 +1231,6 @@ static int wm8350_regulator_remove(struct platform_device *pdev)  	wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq, rdev); -	regulator_unregister(rdev); -  	return 0;  } diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 58f51bec13f..82d82900085 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -20,10 +20,8 @@  #include <linux/mfd/wm8400-private.h>  static const struct regulator_linear_range wm8400_ldo_ranges[] = { -	{ .min_uV =  900000, .max_uV = 1600000, .min_sel = 0, .max_sel = 14, -	  .uV_step =  50000 }, -	{ .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31, -	  .uV_step = 100000 }, +	REGULATOR_LINEAR_RANGE(900000, 0, 14, 50000), +	REGULATOR_LINEAR_RANGE(1700000, 15, 31, 100000),  };  static struct regulator_ops wm8400_ldo_ops = { @@ -219,7 +217,8 @@ static int wm8400_regulator_probe(struct platform_device *pdev)  	config.driver_data = wm8400;  	config.regmap = wm8400->regmap; -	rdev = regulator_register(®ulators[pdev->id], &config); +	rdev = devm_regulator_register(&pdev->dev, ®ulators[pdev->id], +				       &config);  	if (IS_ERR(rdev))  		return PTR_ERR(rdev); @@ -228,21 +227,11 @@ static int wm8400_regulator_probe(struct platform_device *pdev)  	return 0;  } -static int wm8400_regulator_remove(struct platform_device *pdev) -{ -	struct regulator_dev *rdev = platform_get_drvdata(pdev); - -	regulator_unregister(rdev); - -	return 0; -} -  static struct platform_driver wm8400_regulator_driver = {  	.driver = {  		.name = "wm8400-regulator",  	},  	.probe = wm8400_regulator_probe, -	.remove = wm8400_regulator_remove,  };  /** diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 5ee2a208457..c24346db8a7 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -134,10 +134,8 @@ static int wm8994_ldo_probe(struct platform_device *pdev)  	dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);  	ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm8994_ldo), GFP_KERNEL); -	if (ldo == NULL) { -		dev_err(&pdev->dev, "Unable to allocate private data\n"); +	if (!ldo)  		return -ENOMEM; -	}  	ldo->wm8994 = wm8994;  	ldo->supply = wm8994_ldo_consumer[id]; @@ -165,7 +163,9 @@ static int wm8994_ldo_probe(struct platform_device *pdev)  		ldo->init_data = *pdata->ldo[id].init_data;  	} -	ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &config); +	ldo->regulator = devm_regulator_register(&pdev->dev, +						 &wm8994_ldo_desc[id], +						 &config);  	if (IS_ERR(ldo->regulator)) {  		ret = PTR_ERR(ldo->regulator);  		dev_err(wm8994->dev, "Failed to register LDO%d: %d\n", @@ -181,18 +181,8 @@ err:  	return ret;  } -static int wm8994_ldo_remove(struct platform_device *pdev) -{ -	struct wm8994_ldo *ldo = platform_get_drvdata(pdev); - -	regulator_unregister(ldo->regulator); - -	return 0; -} -  static struct platform_driver wm8994_ldo_driver = {  	.probe = wm8994_ldo_probe, -	.remove = wm8994_ldo_remove,  	.driver		= {  		.name	= "wm8994-ldo",  		.owner	= THIS_MODULE,  | 
