diff options
| -rw-r--r-- | Documentation/power/regulator/machine.txt | 140 | ||||
| -rw-r--r-- | Documentation/power/regulator/regulator.txt | 8 | ||||
| -rw-r--r-- | drivers/regulator/bq24022.c | 21 | ||||
| -rw-r--r-- | drivers/regulator/core.c | 457 | ||||
| -rw-r--r-- | include/linux/regulator/driver.h | 8 | ||||
| -rw-r--r-- | include/linux/regulator/machine.h | 30 | 
6 files changed, 334 insertions, 330 deletions
diff --git a/Documentation/power/regulator/machine.txt b/Documentation/power/regulator/machine.txt index c9a3566..ce3487d 100644 --- a/Documentation/power/regulator/machine.txt +++ b/Documentation/power/regulator/machine.txt @@ -2,17 +2,8 @@ Regulator Machine Driver Interface  ===================================  The regulator machine driver interface is intended for board/machine specific -initialisation code to configure the regulator subsystem. Typical things that -machine drivers would do are :- +initialisation code to configure the regulator subsystem. - 1. Regulator -> Device mapping. - 2. Regulator supply configuration. - 3. Power Domain constraint setting. - - - -1. Regulator -> device mapping -==============================  Consider the following machine :-    Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V] @@ -21,81 +12,82 @@ Consider the following machine :-  The drivers for consumers A & B must be mapped to the correct regulator in  order to control their power supply. This mapping can be achieved in machine -initialisation code by calling :- +initialisation code by creating a struct regulator_consumer_supply for +each regulator. + +struct regulator_consumer_supply { +	struct device *dev;	/* consumer */ +	const char *supply;	/* consumer supply - e.g. "vcc" */ +}; -int regulator_set_device_supply(const char *regulator, struct device *dev, -				const char *supply); +e.g. for the machine above -and is shown with the following code :- +static struct regulator_consumer_supply regulator1_consumers[] = { +{ +	.dev	= &platform_consumerB_device.dev, +	.supply	= "Vcc", +},}; -regulator_set_device_supply("Regulator-1", devB, "Vcc"); -regulator_set_device_supply("Regulator-2", devA, "Vcc"); +static struct regulator_consumer_supply regulator2_consumers[] = { +{ +	.dev	= &platform_consumerA_device.dev, +	.supply	= "Vcc", +},};  This maps Regulator-1 to the 'Vcc' supply for Consumer B and maps Regulator-2  to the 'Vcc' supply for Consumer A. - -2. Regulator supply configuration. -================================== -Consider the following machine (again) :- - -  Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V] -               | -               +-> [Consumer B @ 3.3V] +Constraints can now be registered by defining a struct regulator_init_data +for each regulator power domain. This structure also maps the consumers +to their supply regulator :- + +static struct regulator_init_data regulator1_data = { +	.constraints = { +		.min_uV = 3300000, +		.max_uV = 3300000, +		.valid_modes_mask = REGULATOR_MODE_NORMAL, +	}, +	.num_consumer_supplies = ARRAY_SIZE(regulator1_consumers), +	.consumer_supplies = regulator1_consumers, +};  Regulator-1 supplies power to Regulator-2. This relationship must be registered  with the core so that Regulator-1 is also enabled when Consumer A enables it's -supply (Regulator-2). - -This relationship can be register with the core via :- - -int regulator_set_supply(const char *regulator, const char *regulator_supply); - -In this example we would use the following code :- - -regulator_set_supply("Regulator-2", "Regulator-1"); - -Relationships can be queried by calling :- - -const char *regulator_get_supply(const char *regulator); - - -3. Power Domain constraint setting. -=================================== -Each power domain within a system has physical constraints on voltage and -current. This must be defined in software so that the power domain is always -operated within specifications. - -Consider the following machine (again) :- - -  Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V] -               | -               +-> [Consumer B @ 3.3V] - -This gives us two regulators and two power domains: - -                   Domain 1: Regulator-2, Consumer B. -                   Domain 2: Consumer A. - -Constraints can be registered by calling :- - -int regulator_set_platform_constraints(const char *regulator, -	struct regulation_constraints *constraints); - -The example is defined as follows :- - -struct regulation_constraints domain_1 = { -	.min_uV = 3300000, -	.max_uV = 3300000, -	.valid_modes_mask = REGULATOR_MODE_NORMAL, +supply (Regulator-2). The supply regulator is set by the supply_regulator_dev +field below:- + +static struct regulator_init_data regulator2_data = { +	.supply_regulator_dev = &platform_regulator1_device.dev, +	.constraints = { +		.min_uV = 1800000, +		.max_uV = 2000000, +		.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, +		.valid_modes_mask = REGULATOR_MODE_NORMAL, +	}, +	.num_consumer_supplies = ARRAY_SIZE(regulator2_consumers), +	.consumer_supplies = regulator2_consumers,  }; -struct regulation_constraints domain_2 = { -	.min_uV = 1800000, -	.max_uV = 2000000, -	.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, -	.valid_modes_mask = REGULATOR_MODE_NORMAL, +Finally the regulator devices must be registered in the usual manner. + +static struct platform_device regulator_devices[] = { +{ +	.name = "regulator", +	.id = DCDC_1, +	.dev = { +		.platform_data = ®ulator1_data, +	}, +}, +{ +	.name = "regulator", +	.id = DCDC_2, +	.dev = { +		.platform_data = ®ulator2_data, +	}, +},  }; +/* register regulator 1 device */ +platform_device_register(&wm8350_regulator_devices[0]); -regulator_set_platform_constraints("Regulator-1", &domain_1); -regulator_set_platform_constraints("Regulator-2", &domain_2); +/* register regulator 2 device */ +platform_device_register(&wm8350_regulator_devices[1]); diff --git a/Documentation/power/regulator/regulator.txt b/Documentation/power/regulator/regulator.txt index a690501..4200acc 100644 --- a/Documentation/power/regulator/regulator.txt +++ b/Documentation/power/regulator/regulator.txt @@ -10,11 +10,11 @@ Registration  Drivers can register a regulator by calling :- -struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, -					  void *reg_data); +struct regulator_dev *regulator_register(struct device *dev, +	struct regulator_desc *regulator_desc); -This will register the regulators capabilities and operations the regulator -core. The core does not touch reg_data (private to regulator driver). +This will register the regulators capabilities and operations to the regulator +core.  Regulators can be unregistered by calling :- diff --git a/drivers/regulator/bq24022.c b/drivers/regulator/bq24022.c index 263699d..366565a 100644 --- a/drivers/regulator/bq24022.c +++ b/drivers/regulator/bq24022.c @@ -18,13 +18,13 @@  #include <linux/regulator/bq24022.h>  #include <linux/regulator/driver.h> +  static int bq24022_set_current_limit(struct regulator_dev *rdev,  					int min_uA, int max_uA)  { -	struct platform_device *pdev = rdev_get_drvdata(rdev); -	struct bq24022_mach_info *pdata = pdev->dev.platform_data; +	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev); -	dev_dbg(&pdev->dev, "setting current limit to %s mA\n", +	dev_dbg(rdev_get_dev(rdev), "setting current limit to %s mA\n",  		max_uA >= 500000 ? "500" : "100");  	/* REVISIT: maybe return error if min_uA != 0 ? */ @@ -34,18 +34,16 @@ static int bq24022_set_current_limit(struct regulator_dev *rdev,  static int bq24022_get_current_limit(struct regulator_dev *rdev)  { -	struct platform_device *pdev = rdev_get_drvdata(rdev); -	struct bq24022_mach_info *pdata = pdev->dev.platform_data; +	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);  	return gpio_get_value(pdata->gpio_iset2) ? 500000 : 100000;  }  static int bq24022_enable(struct regulator_dev *rdev)  { -	struct platform_device *pdev = rdev_get_drvdata(rdev); -	struct bq24022_mach_info *pdata = pdev->dev.platform_data; +	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev); -	dev_dbg(&pdev->dev, "enabling charger\n"); +	dev_dbg(rdev_get_dev(rdev), "enabling charger\n");  	gpio_set_value(pdata->gpio_nce, 0);  	return 0; @@ -53,10 +51,9 @@ static int bq24022_enable(struct regulator_dev *rdev)  static int bq24022_disable(struct regulator_dev *rdev)  { -	struct platform_device *pdev = rdev_get_drvdata(rdev); -	struct bq24022_mach_info *pdata = pdev->dev.platform_data; +	struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev); -	dev_dbg(&pdev->dev, "disabling charger\n"); +	dev_dbg(rdev_get_dev(rdev), "disabling charger\n");  	gpio_set_value(pdata->gpio_nce, 1);  	return 0; @@ -108,7 +105,7 @@ static int __init bq24022_probe(struct platform_device *pdev)  	ret = gpio_direction_output(pdata->gpio_iset2, 0);  	ret = gpio_direction_output(pdata->gpio_nce, 1); -	bq24022 = regulator_register(&bq24022_desc, pdev); +	bq24022 = regulator_register(&bq24022_desc, &pdev->dev, pdata);  	if (IS_ERR(bq24022)) {  		dev_dbg(&pdev->dev, "couldn't register regulator\n");  		ret = PTR_ERR(bq24022); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 9c79862..84202ea 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2,8 +2,9 @@   * core.c  --  Voltage/Current Regulator framework.   *   * Copyright 2007, 2008 Wolfson Microelectronics PLC. + * Copyright 2008 SlimLogic Ltd.   * - * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com> + * 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 @@ -64,14 +65,9 @@ struct regulator_map {  	struct list_head list;  	struct device *dev;  	const char *supply; -	const char *regulator; +	struct regulator_dev *regulator;  }; -static inline struct regulator_dev *to_rdev(struct device *d) -{ -	return container_of(d, struct regulator_dev, dev); -} -  /*   * struct regulator   * @@ -227,7 +223,7 @@ static ssize_t device_requested_uA_show(struct device *dev,  static ssize_t regulator_uV_show(struct device *dev,  				struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	ssize_t ret;  	mutex_lock(&rdev->mutex); @@ -240,7 +236,7 @@ static ssize_t regulator_uV_show(struct device *dev,  static ssize_t regulator_uA_show(struct device *dev,  				struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev));  } @@ -248,7 +244,7 @@ static ssize_t regulator_uA_show(struct device *dev,  static ssize_t regulator_opmode_show(struct device *dev,  				    struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	int mode = _regulator_get_mode(rdev);  	switch (mode) { @@ -267,7 +263,7 @@ static ssize_t regulator_opmode_show(struct device *dev,  static ssize_t regulator_state_show(struct device *dev,  				   struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	int state = _regulator_is_enabled(rdev);  	if (state > 0) @@ -281,7 +277,7 @@ static ssize_t regulator_state_show(struct device *dev,  static ssize_t regulator_min_uA_show(struct device *dev,  				    struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	if (!rdev->constraints)  		return sprintf(buf, "constraint not defined\n"); @@ -292,7 +288,7 @@ static ssize_t regulator_min_uA_show(struct device *dev,  static ssize_t regulator_max_uA_show(struct device *dev,  				    struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	if (!rdev->constraints)  		return sprintf(buf, "constraint not defined\n"); @@ -303,7 +299,7 @@ static ssize_t regulator_max_uA_show(struct device *dev,  static ssize_t regulator_min_uV_show(struct device *dev,  				    struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	if (!rdev->constraints)  		return sprintf(buf, "constraint not defined\n"); @@ -314,7 +310,7 @@ static ssize_t regulator_min_uV_show(struct device *dev,  static ssize_t regulator_max_uV_show(struct device *dev,  				    struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	if (!rdev->constraints)  		return sprintf(buf, "constraint not defined\n"); @@ -325,7 +321,7 @@ static ssize_t regulator_max_uV_show(struct device *dev,  static ssize_t regulator_total_uA_show(struct device *dev,  				      struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	struct regulator *regulator;  	int uA = 0; @@ -339,14 +335,14 @@ static ssize_t regulator_total_uA_show(struct device *dev,  static ssize_t regulator_num_users_show(struct device *dev,  				      struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	return sprintf(buf, "%d\n", rdev->use_count);  }  static ssize_t regulator_type_show(struct device *dev,  				  struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	switch (rdev->desc->type) {  	case REGULATOR_VOLTAGE: @@ -360,7 +356,7 @@ static ssize_t regulator_type_show(struct device *dev,  static ssize_t regulator_suspend_mem_uV_show(struct device *dev,  				struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	if (!rdev->constraints)  		return sprintf(buf, "not defined\n"); @@ -370,7 +366,7 @@ static ssize_t regulator_suspend_mem_uV_show(struct device *dev,  static ssize_t regulator_suspend_disk_uV_show(struct device *dev,  				struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	if (!rdev->constraints)  		return sprintf(buf, "not defined\n"); @@ -380,7 +376,7 @@ static ssize_t regulator_suspend_disk_uV_show(struct device *dev,  static ssize_t regulator_suspend_standby_uV_show(struct device *dev,  				struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	if (!rdev->constraints)  		return sprintf(buf, "not defined\n"); @@ -406,7 +402,7 @@ static ssize_t suspend_opmode_show(struct regulator_dev *rdev,  static ssize_t regulator_suspend_mem_mode_show(struct device *dev,  				struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	if (!rdev->constraints)  		return sprintf(buf, "not defined\n"); @@ -417,7 +413,7 @@ static ssize_t regulator_suspend_mem_mode_show(struct device *dev,  static ssize_t regulator_suspend_disk_mode_show(struct device *dev,  				struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	if (!rdev->constraints)  		return sprintf(buf, "not defined\n"); @@ -428,7 +424,7 @@ static ssize_t regulator_suspend_disk_mode_show(struct device *dev,  static ssize_t regulator_suspend_standby_mode_show(struct device *dev,  				struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	if (!rdev->constraints)  		return sprintf(buf, "not defined\n"); @@ -439,7 +435,7 @@ static ssize_t regulator_suspend_standby_mode_show(struct device *dev,  static ssize_t regulator_suspend_mem_state_show(struct device *dev,  				   struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	if (!rdev->constraints)  		return sprintf(buf, "not defined\n"); @@ -453,7 +449,7 @@ static ssize_t regulator_suspend_mem_state_show(struct device *dev,  static ssize_t regulator_suspend_disk_state_show(struct device *dev,  				   struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	if (!rdev->constraints)  		return sprintf(buf, "not defined\n"); @@ -467,7 +463,7 @@ static ssize_t regulator_suspend_disk_state_show(struct device *dev,  static ssize_t regulator_suspend_standby_state_show(struct device *dev,  				   struct device_attribute *attr, char *buf)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	if (!rdev->constraints)  		return sprintf(buf, "not defined\n"); @@ -512,7 +508,7 @@ static struct device_attribute regulator_dev_attrs[] = {  static void regulator_dev_release(struct device *dev)  { -	struct regulator_dev *rdev = to_rdev(dev); +	struct regulator_dev *rdev = dev_get_drvdata(dev);  	kfree(rdev);  } @@ -569,8 +565,11 @@ static int suspend_set_state(struct regulator_dev *rdev,  	/* enable & disable are mandatory for suspend control */  	if (!rdev->desc->ops->set_suspend_enable || -		!rdev->desc->ops->set_suspend_disable) +		!rdev->desc->ops->set_suspend_disable) { +		printk(KERN_ERR "%s: no way to set suspend state\n", +			__func__);  		return -EINVAL; +	}  	if (rstate->enabled)  		ret = rdev->desc->ops->set_suspend_enable(rdev); @@ -656,6 +655,125 @@ static void print_constraints(struct regulator_dev *rdev)  	printk(KERN_INFO "regulator: %s: %s\n", rdev->desc->name, buf);  } +/** + * set_machine_constraints - sets regulator constraints + * @regulator: regulator source + * + * Allows platform initialisation code to define and constrain + * regulator circuits e.g. valid voltage/current ranges, etc.  NOTE: + * Constraints *must* be set by platform code in order for some + * regulator operations to proceed i.e. set_voltage, set_current_limit, + * set_mode. + */ +static int set_machine_constraints(struct regulator_dev *rdev, +	struct regulation_constraints *constraints) +{ +	int ret = 0; + +	rdev->constraints = constraints; + +	/* do we need to apply the constraint voltage */ +	if (rdev->constraints->apply_uV && +		rdev->constraints->min_uV == rdev->constraints->max_uV && +		rdev->desc->ops->set_voltage) { +		ret = rdev->desc->ops->set_voltage(rdev, +			rdev->constraints->min_uV, rdev->constraints->max_uV); +			if (ret < 0) { +				printk(KERN_ERR "%s: failed to apply %duV" +					" constraint\n", __func__, +					rdev->constraints->min_uV); +				rdev->constraints = NULL; +				goto out; +			} +	} + +	/* are we enabled at boot time by firmware / bootloader */ +	if (rdev->constraints->boot_on) +		rdev->use_count = 1; + +	/* do we need to setup our suspend state */ +	if (constraints->initial_state) +		ret = suspend_prepare(rdev, constraints->initial_state); + +	print_constraints(rdev); +out: +	return ret; +} + +/** + * set_supply - set regulator supply regulator + * @regulator: regulator name + * @supply: supply regulator name + * + * Called by platform initialisation code to set the supply regulator for this + * regulator. This ensures that a regulators supply will also be enabled by the + * core if it's child is enabled. + */ +static int set_supply(struct regulator_dev *rdev, +	struct regulator_dev *supply_rdev) +{ +	int err; + +	err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj, +				"supply"); +	if (err) { +		printk(KERN_ERR +		       "%s: could not add device link %s err %d\n", +		       __func__, supply_rdev->dev.kobj.name, err); +		       goto out; +	} +	rdev->supply = supply_rdev; +	list_add(&rdev->slist, &supply_rdev->supply_list); +out: +	return err; +} + +/** + * set_consumer_device_supply: Bind a regulator to a symbolic supply + * @regulator: regulator source + * @dev:       device the supply applies to + * @supply:    symbolic name for supply + * + * Allows platform initialisation code to map physical regulator + * sources to symbolic names for supplies for use by devices.  Devices + * should use these symbolic names to request regulators, avoiding the + * need to provide board-specific regulator names as platform data. + */ +static int set_consumer_device_supply(struct regulator_dev *rdev, +	struct device *consumer_dev, const char *supply) +{ +	struct regulator_map *node; + +	if (supply == NULL) +		return -EINVAL; + +	node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL); +	if (node == NULL) +		return -ENOMEM; + +	node->regulator = rdev; +	node->dev = consumer_dev; +	node->supply = supply; + +	list_add(&node->list, ®ulator_map_list); +	return 0; +} + +static void unset_consumer_device_supply(struct regulator_dev *rdev, +	struct device *consumer_dev) +{ +	struct regulator_map *node, *n; + +	list_for_each_entry_safe(node, n, ®ulator_map_list, list) { +		if (rdev == node->regulator && +			consumer_dev == node->dev) { +			list_del(&node->list); +			kfree(node); +			return; +		} +	} +} +  #define REG_STR_SIZE	32  static struct regulator *create_regulator(struct regulator_dev *rdev, @@ -746,7 +864,6 @@ struct regulator *regulator_get(struct device *dev, const char *id)  	struct regulator_dev *rdev;  	struct regulator_map *map;  	struct regulator *regulator = ERR_PTR(-ENODEV); -	const char *supply = id;  	if (id == NULL) {  		printk(KERN_ERR "regulator: get() with no identifier\n"); @@ -758,15 +875,9 @@ struct regulator *regulator_get(struct device *dev, const char *id)  	list_for_each_entry(map, ®ulator_map_list, list) {  		if (dev == map->dev &&  		    strcmp(map->supply, id) == 0) { -			supply = map->regulator; -			break; -		} -	} - -	list_for_each_entry(rdev, ®ulator_list, list) { -		if (strcmp(supply, rdev->desc->name) == 0 && -		    try_module_get(rdev->owner)) +			rdev = map->regulator;  			goto found; +		}  	}  	printk(KERN_ERR "regulator: Unable to get requested regulator: %s\n",  	       id); @@ -774,12 +885,16 @@ struct regulator *regulator_get(struct device *dev, const char *id)  	return regulator;  found: +	if (!try_module_get(rdev->owner)) +		goto out; +  	regulator = create_regulator(rdev, dev, id);  	if (regulator == NULL) {  		regulator = ERR_PTR(-ENOMEM);  		module_put(rdev->owner);  	} +out:  	mutex_unlock(®ulator_list_mutex);  	return regulator;  } @@ -1559,11 +1674,12 @@ EXPORT_SYMBOL_GPL(regulator_notifier_call_chain);   * Returns 0 on success.   */  struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, -					  void *reg_data) +	struct device *dev, void *driver_data)  {  	static atomic_t regulator_no = ATOMIC_INIT(0);  	struct regulator_dev *rdev; -	int ret; +	struct regulator_init_data *init_data = dev->platform_data; +	int ret, i;  	if (regulator_desc == NULL)  		return ERR_PTR(-EINVAL); @@ -1582,7 +1698,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,  	mutex_lock(®ulator_list_mutex);  	mutex_init(&rdev->mutex); -	rdev->reg_data = reg_data; +	rdev->reg_data = driver_data;  	rdev->owner = regulator_desc->owner;  	rdev->desc = regulator_desc;  	INIT_LIST_HEAD(&rdev->consumer_list); @@ -1591,20 +1707,68 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,  	INIT_LIST_HEAD(&rdev->slist);  	BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); +	/* preform any regulator specific init */ +	if (init_data->regulator_init) { +		ret = init_data->regulator_init(rdev->reg_data); +		if (ret < 0) { +			kfree(rdev); +			rdev = ERR_PTR(ret); +			goto out; +		} +	} + +	/* set regulator constraints */ +	ret = set_machine_constraints(rdev, &init_data->constraints); +	if (ret < 0) { +		kfree(rdev); +		rdev = ERR_PTR(ret); +		goto out; +	} + +	/* register with sysfs */  	rdev->dev.class = ®ulator_class; -	device_initialize(&rdev->dev); +	rdev->dev.parent = dev;  	snprintf(rdev->dev.bus_id, sizeof(rdev->dev.bus_id), -		 "regulator_%ld_%s", -		 (unsigned long)atomic_inc_return(®ulator_no) - 1, -		 regulator_desc->name); - -	ret = device_add(&rdev->dev); -	if (ret == 0) -		list_add(&rdev->list, ®ulator_list); -	else { +		 "regulator.%d", atomic_inc_return(®ulator_no) - 1); +	ret = device_register(&rdev->dev); +	if (ret != 0) {  		kfree(rdev);  		rdev = ERR_PTR(ret); +		goto out; +	} + +	dev_set_drvdata(&rdev->dev, rdev); + +	/* set supply regulator if it exists */ +	if (init_data->supply_regulator_dev) { +		ret = set_supply(rdev, +			dev_get_drvdata(init_data->supply_regulator_dev)); +		if (ret < 0) { +			device_unregister(&rdev->dev); +			kfree(rdev); +			rdev = ERR_PTR(ret); +			goto out; +		} +	} + +	/* add consumers devices */ +	for (i = 0; i < init_data->num_consumer_supplies; i++) { +		ret = set_consumer_device_supply(rdev, +			init_data->consumer_supplies[i].dev, +			init_data->consumer_supplies[i].supply); +		if (ret < 0) { +			for (--i; i >= 0; i--) +				unset_consumer_device_supply(rdev, +					init_data->consumer_supplies[i].dev); +			device_unregister(&rdev->dev); +			kfree(rdev); +			rdev = ERR_PTR(ret); +			goto out; +		}  	} + +	list_add(&rdev->list, ®ulator_list); +out:  	mutex_unlock(®ulator_list_mutex);  	return rdev;  } @@ -1631,187 +1795,6 @@ void regulator_unregister(struct regulator_dev *rdev)  EXPORT_SYMBOL_GPL(regulator_unregister);  /** - * regulator_set_supply - set regulator supply regulator - * @regulator: regulator name - * @supply: supply regulator name - * - * Called by platform initialisation code to set the supply regulator for this - * regulator. This ensures that a regulators supply will also be enabled by the - * core if it's child is enabled. - */ -int regulator_set_supply(const char *regulator, const char *supply) -{ -	struct regulator_dev *rdev, *supply_rdev; -	int err; - -	if (regulator == NULL || supply == NULL) -		return -EINVAL; - -	mutex_lock(®ulator_list_mutex); - -	list_for_each_entry(rdev, ®ulator_list, list) { -		if (!strcmp(rdev->desc->name, regulator)) -			goto found_regulator; -	} -	mutex_unlock(®ulator_list_mutex); -	return -ENODEV; - -found_regulator: -	list_for_each_entry(supply_rdev, ®ulator_list, list) { -		if (!strcmp(supply_rdev->desc->name, supply)) -			goto found_supply; -	} -	mutex_unlock(®ulator_list_mutex); -	return -ENODEV; - -found_supply: -	err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj, -				"supply"); -	if (err) { -		printk(KERN_ERR -		       "%s: could not add device link %s err %d\n", -		       __func__, supply_rdev->dev.kobj.name, err); -		       goto out; -	} -	rdev->supply = supply_rdev; -	list_add(&rdev->slist, &supply_rdev->supply_list); -out: -	mutex_unlock(®ulator_list_mutex); -	return err; -} -EXPORT_SYMBOL_GPL(regulator_set_supply); - -/** - * regulator_get_supply - get regulator supply regulator - * @regulator: regulator name - * - * Returns the supply supply regulator name or NULL if no supply regulator - * exists (i.e the regulator is supplied directly from USB, Line, Battery, etc) - */ -const char *regulator_get_supply(const char *regulator) -{ -	struct regulator_dev *rdev; - -	if (regulator == NULL) -		return NULL; - -	mutex_lock(®ulator_list_mutex); -	list_for_each_entry(rdev, ®ulator_list, list) { -		if (!strcmp(rdev->desc->name, regulator)) -			goto found; -	} -	mutex_unlock(®ulator_list_mutex); -	return NULL; - -found: -	mutex_unlock(®ulator_list_mutex); -	if (rdev->supply) -		return rdev->supply->desc->name; -	else -		return NULL; -} -EXPORT_SYMBOL_GPL(regulator_get_supply); - -/** - * regulator_set_machine_constraints - sets regulator constraints - * @regulator: regulator source - * - * Allows platform initialisation code to define and constrain - * regulator circuits e.g. valid voltage/current ranges, etc.  NOTE: - * Constraints *must* be set by platform code in order for some - * regulator operations to proceed i.e. set_voltage, set_current_limit, - * set_mode. - */ -int regulator_set_machine_constraints(const char *regulator_name, -	struct regulation_constraints *constraints) -{ -	struct regulator_dev *rdev; -	int ret = 0; - -	if (regulator_name == NULL) -		return -EINVAL; - -	mutex_lock(®ulator_list_mutex); - -	list_for_each_entry(rdev, ®ulator_list, list) { -		if (!strcmp(regulator_name, rdev->desc->name)) -			goto found; -	} -	ret = -ENODEV; -	goto out; - -found: -	mutex_lock(&rdev->mutex); -	rdev->constraints = constraints; - -	/* do we need to apply the constraint voltage */ -	if (rdev->constraints->apply_uV && -		rdev->constraints->min_uV == rdev->constraints->max_uV && -		rdev->desc->ops->set_voltage) { -		ret = rdev->desc->ops->set_voltage(rdev, -			rdev->constraints->min_uV, rdev->constraints->max_uV); -			if (ret < 0) { -				printk(KERN_ERR "%s: failed to apply %duV" -					" constraint\n", __func__, -					rdev->constraints->min_uV); -				rdev->constraints = NULL; -				goto out; -			} -	} - -	/* are we enabled at boot time by firmware / bootloader */ -	if (rdev->constraints->boot_on) -		rdev->use_count = 1; - -	/* do we need to setup our suspend state */ -	if (constraints->initial_state) -		ret = suspend_prepare(rdev, constraints->initial_state); - -	print_constraints(rdev); -	mutex_unlock(&rdev->mutex); - -out: -	mutex_unlock(®ulator_list_mutex); -	return ret; -} -EXPORT_SYMBOL_GPL(regulator_set_machine_constraints); - - -/** - * regulator_set_device_supply: Bind a regulator to a symbolic supply - * @regulator: regulator source - * @dev:       device the supply applies to - * @supply:    symbolic name for supply - * - * Allows platform initialisation code to map physical regulator - * sources to symbolic names for supplies for use by devices.  Devices - * should use these symbolic names to request regulators, avoiding the - * need to provide board-specific regulator names as platform data. - */ -int regulator_set_device_supply(const char *regulator, struct device *dev, -				const char *supply) -{ -	struct regulator_map *node; - -	if (regulator == NULL || supply == NULL) -		return -EINVAL; - -	node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL); -	if (node == NULL) -		return -ENOMEM; - -	node->regulator = regulator; -	node->dev = dev; -	node->supply = supply; - -	mutex_lock(®ulator_list_mutex); -	list_add(&node->list, ®ulator_map_list); -	mutex_unlock(®ulator_list_mutex); -	return 0; -} -EXPORT_SYMBOL_GPL(regulator_set_device_supply); - -/**   * regulator_suspend_prepare: prepare regulators for system wide suspend   * @state: system suspend state   * @@ -1893,6 +1876,18 @@ int rdev_get_id(struct regulator_dev *rdev)  }  EXPORT_SYMBOL_GPL(rdev_get_id); +struct device *rdev_get_dev(struct regulator_dev *rdev) +{ +	return &rdev->dev; +} +EXPORT_SYMBOL_GPL(rdev_get_dev); + +void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data) +{ +	return reg_init_data->driver_data; +} +EXPORT_SYMBOL_GPL(regulator_get_init_drvdata); +  static int __init regulator_init(void)  {  	printk(KERN_INFO "regulator: core version %s\n", REGULATOR_VERSION); diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 1d712c7..bc01b42 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -18,8 +18,8 @@  #include <linux/device.h>  #include <linux/regulator/consumer.h> -struct regulator_constraints;  struct regulator_dev; +struct regulator_init_data;  /**   * struct regulator_ops - regulator operations. @@ -85,15 +85,17 @@ struct regulator_desc {  	struct module *owner;  }; -  struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, -					  void *reg_data); +	struct device *dev, void *driver_data);  void regulator_unregister(struct regulator_dev *rdev);  int regulator_notifier_call_chain(struct regulator_dev *rdev,  				  unsigned long event, void *data);  void *rdev_get_drvdata(struct regulator_dev *rdev); +struct device *rdev_get_dev(struct regulator_dev *rdev);  int rdev_get_id(struct regulator_dev *rdev); +void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data); +  #endif diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index 11e737d..c6d6933 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h @@ -89,15 +89,33 @@ struct regulation_constraints {  	unsigned apply_uV:1;	/* apply uV constraint iff min == max */  }; -int regulator_set_supply(const char *regulator, const char *regulator_supply); +/** + * struct regulator_consumer_supply - supply -> device mapping + * + * This maps a supply name to a device. + */ +struct regulator_consumer_supply { +	struct device *dev;	/* consumer */ +	const char *supply;	/* consumer supply - e.g. "vcc" */ +}; -const char *regulator_get_supply(const char *regulator); +/** + * struct regulator_init_data - regulator platform initialisation data. + * + * Initialisation constraints, our supply and consumers supplies. + */ +struct regulator_init_data { +	struct device *supply_regulator_dev; /* or NULL for LINE */ -int regulator_set_machine_constraints(const char *regulator, -	struct regulation_constraints *constraints); +	struct regulation_constraints constraints; -int regulator_set_device_supply(const char *regulator, struct device *dev, -				const char *supply); +	int num_consumer_supplies; +	struct regulator_consumer_supply *consumer_supplies; + +	/* optional regulator machine specific init */ +	int (*regulator_init)(void *driver_data); +	void *driver_data;	/* core does not touch this */ +};  int regulator_suspend_prepare(suspend_state_t state);  | 
