9
0
Fork 0

Merge branch 'for-next/regulator'

Conflicts:
	commands/Makefile
This commit is contained in:
Sascha Hauer 2014-05-05 13:33:06 +02:00
commit 845f765b6e
12 changed files with 489 additions and 2 deletions

View File

@ -696,6 +696,14 @@ config CMD_GPIO
include gpio_set_value, gpio_get_value, gpio_direction_input and
gpio_direction_output commands to control gpios.
config CMD_REGULATOR
bool
depends on REGULATOR
prompt "regulator command"
help
the regulator command lists the currently registered regulators and
their current state.
config CMD_UNCOMPRESS
bool
select UNCOMPRESS

View File

@ -96,3 +96,4 @@ obj-$(CONFIG_CMD_DEVINFO) += devinfo.o
obj-$(CONFIG_CMD_READF) += readf.o
obj-$(CONFIG_CMD_MENUTREE) += menutree.o
obj-$(CONFIG_CMD_2048) += 2048.o
obj-$(CONFIG_CMD_REGULATOR) += regulator.o

33
commands/regulator.c Normal file
View File

@ -0,0 +1,33 @@
/*
* regulator command
*
* Copyright (c) 2014 Sascha Hauer <s.hauer@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 <common.h>
#include <command.h>
#include <regulator.h>
static int do_regulator(int argc, char *argv[])
{
regulators_print();
return 0;
}
BAREBOX_CMD_START(regulator)
.cmd = do_regulator,
.usage = "list regulators",
BAREBOX_CMD_END

View File

@ -25,5 +25,6 @@ source "drivers/gpio/Kconfig"
source "drivers/w1/Kconfig"
source "drivers/pinctrl/Kconfig"
source "drivers/bus/Kconfig"
source "drivers/regulator/Kconfig"
endmenu

View File

@ -24,3 +24,4 @@ obj-$(CONFIG_OFTREE) += of/
obj-$(CONFIG_W1) += w1/
obj-y += pinctrl/
obj-y += bus/
obj-$(CONFIG_REGULATOR) += regulator/

View File

@ -1570,18 +1570,25 @@ static const char *mci_boot_names[] = {
static int mci_card_probe(struct mci *mci)
{
struct mci_host *host = mci->host;
int i, rc, disknum;
int i, rc, disknum, ret;
if (host->card_present && !host->card_present(host)) {
dev_err(&mci->dev, "no card inserted\n");
return -ENODEV;
}
ret = regulator_enable(host->supply);
if (ret) {
dev_err(&mci->dev, "failed to enable regulator: %s\n",
strerror(-ret));
return ret;
}
/* start with a host interface reset */
rc = (host->init)(host, &mci->dev);
if (rc) {
dev_err(&mci->dev, "Cannot reset the SD/MMC interface\n");
return rc;
goto on_error;
}
mci_set_bus_width(mci, MMC_BUS_WIDTH_1);
@ -1665,6 +1672,7 @@ on_error:
if (rc != 0) {
host->clock = 0; /* disable the MCI clock */
mci_set_ios(mci);
regulator_disable(host->supply);
}
return rc;
@ -1750,6 +1758,12 @@ int mci_register(struct mci_host *host)
host->mci = mci;
mci->dev.detect = mci_detect;
host->supply = regulator_get(host->hw_dev, "vmmc");
if (IS_ERR(host->supply)) {
ret = PTR_ERR(host->supply);
goto err_free;
}
ret = register_device(&mci->dev);
if (ret)
goto err_free;

13
drivers/regulator/Kconfig Normal file
View File

@ -0,0 +1,13 @@
menuconfig REGULATOR
depends on OFDEVICE
bool "voltage regulator support"
if REGULATOR
config REGULATOR_FIXED
bool "fixed/gpio regulator"
help
This enables a simple fixed regulator. It is used for regulators
which are not software controllable or controllable via gpio.
endif

View File

@ -0,0 +1,2 @@
obj-$(CONFIG_REGULATOR) += core.o
obj-$(CONFIG_REGULATOR_FIXED) += fixed.o

262
drivers/regulator/core.c Normal file
View File

@ -0,0 +1,262 @@
/*
* barebox regulator support
*
* Copyright (c) 2014 Sascha Hauer <s.hauer@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 <common.h>
#include <regulator.h>
#include <of.h>
#include <malloc.h>
#include <linux/err.h>
static LIST_HEAD(regulator_list);
struct regulator_internal {
struct list_head list;
struct device_node *node;
struct regulator_dev *rdev;
int enable_count;
int enable_time_us;
int min_uv;
int max_uv;
char *name;
struct list_head consumer_list;
};
struct regulator {
struct regulator_internal *ri;
struct list_head list;
struct device_d *dev;
};
/*
* of_regulator_register - register a regulator corresponding to a device_node
* @rd: the regulator device providing the ops
* @node: the device_node this regulator corresponds to
*
* Return: 0 for success or a negative error code
*/
int of_regulator_register(struct regulator_dev *rd, struct device_node *node)
{
struct regulator_internal *ri;
const char *name;
ri = xzalloc(sizeof(*ri));
ri->rdev = rd;
ri->node = node;
INIT_LIST_HEAD(&ri->consumer_list);
list_add_tail(&ri->list, &regulator_list);
name = of_get_property(node, "regulator-name", NULL);
if (name)
ri->name = xstrdup(name);
of_property_read_u32(node, "regulator-enable-ramp-delay",
&ri->enable_time_us);
of_property_read_u32(node, "regulator-min-microvolt",
&ri->min_uv);
of_property_read_u32(node, "regulator-max-microvolt",
&ri->max_uv);
return 0;
}
static struct regulator_internal *of_regulator_get(struct device_d *dev, const char *supply)
{
char *propname;
struct regulator_internal *ri;
struct device_node *node;
propname = asprintf("%s-supply", supply);
/*
* If the device does have a device node return the dummy regulator.
*/
if (!dev->device_node)
return NULL;
/*
* If the device node does not contain a supply property, this device doesn't
* need a regulator. Return the dummy regulator in this case.
*/
if (!of_get_property(dev->device_node, propname, NULL)) {
dev_dbg(dev, "No %s-supply node found, using dummy regulator\n",
supply);
ri = NULL;
goto out;
}
/*
* The device node specifies a supply, so it's mandatory. Return an error when
* something goes wrong below.
*/
node = of_parse_phandle(dev->device_node, propname, 0);
if (!node) {
dev_dbg(dev, "No %s node found\n", propname);
ri = ERR_PTR(-EINVAL);
goto out;
}
list_for_each_entry(ri, &regulator_list, list) {
if (ri->node == node) {
dev_dbg(dev, "Using %s regulator from %s\n",
propname, node->full_name);
goto out;
}
}
ri = ERR_PTR(-ENODEV);
out:
free(propname);
return ri;
}
/*
* regulator_get - get the supply for a device.
* @dev: the device a supply is requested for
* @supply: the supply name
*
* This returns a supply for a device. Check the result with IS_ERR().
* NULL is a valid regulator, the dummy regulator.
*
* Return: a regulator object or an error pointer
*/
struct regulator *regulator_get(struct device_d *dev, const char *supply)
{
struct regulator_internal *ri;
struct regulator *r;
if (!dev->device_node)
return NULL;
ri = of_regulator_get(dev, supply);
if (IS_ERR(ri))
return ERR_CAST(ri);
if (!ri)
return NULL;
r = xzalloc(sizeof(*r));
r->ri = ri;
r->dev = dev;
list_add_tail(&r->list, &ri->consumer_list);
return r;
}
/*
* regulator_enable - enable a regulator.
* @r: the regulator to enable
*
* This enables a regulator. Regulators are reference counted, only the
* first enable operation will enable the regulator.
*
* Return: 0 for success or a negative error code
*/
int regulator_enable(struct regulator *r)
{
struct regulator_internal *ri;
int ret;
if (!r)
return 0;
ri = r->ri;
if (ri->enable_count) {
ri->enable_count++;
return 0;
}
if (!ri->rdev->ops->enable)
return -ENOSYS;
ret = ri->rdev->ops->enable(ri->rdev);
if (ret)
return ret;
if (ri->enable_time_us)
udelay(ri->enable_time_us);
ri->enable_count++;
return 0;
}
/*
* regulator_disable - disable a regulator.
* @r: the regulator to disable
*
* This disables a regulator. Regulators are reference counted, only the
* when balanced with regulator_enable the regulator will be disabled.
*
* Return: 0 for success or a negative error code
*/
int regulator_disable(struct regulator *r)
{
struct regulator_internal *ri;
int ret;
if (!r)
return 0;
ri = r->ri;
if (!ri->enable_count)
return -EINVAL;
if (!ri->rdev->ops->disable)
return -ENOSYS;
ret = ri->rdev->ops->disable(ri->rdev);
if (ret)
return ret;
ri->enable_count--;
return 0;
}
static void regulator_print_one(struct regulator_internal *ri)
{
struct regulator *r;
printf("%-20s %6d %10d %10d\n", ri->name, ri->enable_count, ri->min_uv, ri->max_uv);
if (!list_empty(&ri->consumer_list)) {
printf(" consumers:\n");
list_for_each_entry(r, &ri->consumer_list, list)
printf(" %s\n", dev_name(r->dev));
}
}
/*
* regulators_print - print informations about all regulators
*/
void regulators_print(void)
{
struct regulator_internal *ri;
printf("%-20s %6s %10s %10s\n", "name", "enable", "min_uv", "max_uv");
list_for_each_entry(ri, &regulator_list, list)
regulator_print_one(ri);
}

103
drivers/regulator/fixed.c Normal file
View File

@ -0,0 +1,103 @@
/*
* fixed regulator support
*
* Copyright (c) 2014 Sascha Hauer <s.hauer@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 <common.h>
#include <malloc.h>
#include <init.h>
#include <regulator.h>
#include <of.h>
#include <of_gpio.h>
#include <gpio.h>
struct regulator_fixed {
int gpio;
int active_low;
struct regulator_dev rdev;
};
static int regulator_fixed_enable(struct regulator_dev *rdev)
{
struct regulator_fixed *fix = container_of(rdev, struct regulator_fixed, rdev);
if (!gpio_is_valid(fix->gpio))
return 0;
return gpio_direction_output(fix->gpio, !fix->active_low);
}
static int regulator_fixed_disable(struct regulator_dev *rdev)
{
struct regulator_fixed *fix = container_of(rdev, struct regulator_fixed, rdev);
if (!gpio_is_valid(fix->gpio))
return 0;
return gpio_direction_output(fix->gpio, fix->active_low);
}
static struct regulator_ops fixed_ops = {
.enable = regulator_fixed_enable,
.disable = regulator_fixed_disable,
};
static int regulator_fixed_probe(struct device_d *dev)
{
struct regulator_fixed *fix;
enum of_gpio_flags gpioflags;
int ret;
if (!dev->device_node)
return -EINVAL;
fix = xzalloc(sizeof(*fix));
if (of_get_property(dev->device_node, "gpio", NULL)) {
fix->gpio = of_get_named_gpio_flags(dev->device_node, "gpio", 0, &gpioflags);
if (fix->gpio < 0) {
ret = fix->gpio;
goto err;
}
if (gpioflags & OF_GPIO_ACTIVE_LOW)
fix->active_low = 1;
}
fix->rdev.ops = &fixed_ops;
ret = of_regulator_register(&fix->rdev, dev->device_node);
if (ret)
return ret;
return 0;
err:
free(fix);
return ret;
}
static struct of_device_id regulator_fixed_of_ids[] = {
{ .compatible = "regulator-fixed", },
{ }
};
static struct driver_d regulator_fixed_driver = {
.name = "regulator-fixed",
.probe = regulator_fixed_probe,
.of_compatible = DRV_OF_COMPAT(regulator_fixed_of_ids),
};
coredevice_platform_driver(regulator_fixed_driver);

View File

@ -28,6 +28,7 @@
#include <linux/list.h>
#include <block.h>
#include <regulator.h>
/* Firmware revisions for SD cards */
#define SD_VERSION_SD 0x20000
@ -301,6 +302,7 @@ struct mci_host {
unsigned max_req_size;
unsigned dsr_val; /**< optional dsr value */
int use_dsr; /**< optional dsr usage flag */
struct regulator *supply;
/** init the host interface */
int (*init)(struct mci_host*, struct device_d*);

47
include/regulator.h Normal file
View File

@ -0,0 +1,47 @@
#ifndef __REGULATOR_H
#define __REGULATOR_H
/* struct regulator is an opaque object for consumers */
struct regulator;
struct regulator_dev {
struct regulator_ops *ops;
};
struct regulator_ops {
/* enable/disable regulator */
int (*enable) (struct regulator_dev *);
int (*disable) (struct regulator_dev *);
int (*is_enabled) (struct regulator_dev *);
};
int of_regulator_register(struct regulator_dev *rd, struct device_node *node);
void regulators_print(void);
#ifdef CONFIG_REGULATOR
struct regulator *regulator_get(struct device_d *, const char *);
int regulator_enable(struct regulator *);
int regulator_disable(struct regulator *);
#else
static inline struct regulator *regulator_get(struct device_d *dev, const char *id)
{
return NULL;
}
static inline int regulator_enable(struct regulator *r)
{
return 0;
}
static inline int regulator_disable(struct regulator *r)
{
return 0;
}
#endif
#endif /* __REGULATOR_H */