Merge branch 'for-next/regulator'
Conflicts: commands/Makefile
This commit is contained in:
commit
845f765b6e
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -24,3 +24,4 @@ obj-$(CONFIG_OFTREE) += of/
|
|||
obj-$(CONFIG_W1) += w1/
|
||||
obj-y += pinctrl/
|
||||
obj-y += bus/
|
||||
obj-$(CONFIG_REGULATOR) += regulator/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
obj-$(CONFIG_REGULATOR) += core.o
|
||||
obj-$(CONFIG_REGULATOR_FIXED) += fixed.o
|
|
@ -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, ®ulator_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, ®ulator_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, ®ulator_list, list)
|
||||
regulator_print_one(ri);
|
||||
}
|
|
@ -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);
|
|
@ -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*);
|
||||
|
|
|
@ -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 */
|
Loading…
Reference in New Issue