Merge branch 'master' of git://git.denx.de/u-boot-mpc85xx

This commit is contained in:
Tom Rini
2016-06-04 12:12:26 -04:00
53 changed files with 478 additions and 107 deletions

View File

@@ -188,4 +188,30 @@ config DM_PCA953X
Now, max 24 bits chips and PCA953X compatible chips are
supported
config MPC85XX_GPIO
bool "Freescale MPC85XX GPIO driver"
depends on DM_GPIO
help
This driver supports the built-in GPIO controller of MPC85XX CPUs.
Each GPIO bank is identified by its own entry in the device tree,
i.e.
gpio-controller@fc00 {
#gpio-cells = <2>;
compatible = "fsl,pq3-gpio";
reg = <0xfc00 0x100>
}
By default, each bank is assumed to have 32 GPIOs, but the ngpios
setting is honored, so the number of GPIOs for each bank is
configurable to match the actual GPIO count of the SoC (e.g. the
32/32/23 banks of the P1022 SoC).
Aside from the standard functions of input/output mode, and output
value setting, the open-drain feature, which can configure individual
GPIOs to work as open-drain outputs, is supported.
The driver has been tested on MPC85XX, but it is likely that other
PowerQUICC III devices will work as well.
endmenu

View File

@@ -36,6 +36,7 @@ obj-$(CONFIG_DA8XX_GPIO) += da8xx_gpio.o
obj-$(CONFIG_DM644X_GPIO) += da8xx_gpio.o
obj-$(CONFIG_ALTERA_PIO) += altera_pio.o
obj-$(CONFIG_MPC83XX_GPIO) += mpc83xx_gpio.o
obj-$(CONFIG_MPC85XX_GPIO) += mpc85xx_gpio.o
obj-$(CONFIG_SH_GPIO_PFC) += sh_pfc.o
obj-$(CONFIG_OMAP_GPIO) += omap_gpio.o
obj-$(CONFIG_DB8500_GPIO) += db8500_gpio.o

View File

@@ -367,6 +367,38 @@ int dm_gpio_set_value(const struct gpio_desc *desc, int value)
return 0;
}
int dm_gpio_get_open_drain(struct gpio_desc *desc)
{
struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
int ret;
ret = check_reserved(desc, "get_open_drain");
if (ret)
return ret;
if (ops->set_open_drain)
return ops->get_open_drain(desc->dev, desc->offset);
else
return -ENOSYS;
}
int dm_gpio_set_open_drain(struct gpio_desc *desc, int value)
{
struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
int ret;
ret = check_reserved(desc, "set_open_drain");
if (ret)
return ret;
if (ops->set_open_drain)
ret = ops->set_open_drain(desc->dev, desc->offset, value);
else
return 0; /* feature not supported -> ignore setting */
return ret;
}
int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
{
struct udevice *dev = desc->dev;

228
drivers/gpio/mpc85xx_gpio.c Normal file
View File

@@ -0,0 +1,228 @@
/*
* (C) Copyright 2016
* Mario Six, Guntermann & Drunck GmbH, six@gdsys.de
*
* based on arch/powerpc/include/asm/mpc85xx_gpio.h, which is
*
* Copyright 2010 eXMeritus, A Boeing Company
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <asm/gpio.h>
#include <mapmem.h>
DECLARE_GLOBAL_DATA_PTR;
struct ccsr_gpio {
u32 gpdir;
u32 gpodr;
u32 gpdat;
u32 gpier;
u32 gpimr;
u32 gpicr;
};
struct mpc85xx_gpio_data {
/* The bank's register base in memory */
struct ccsr_gpio __iomem *base;
/* The address of the registers; used to identify the bank */
ulong addr;
/* The GPIO count of the bank */
uint gpio_count;
/* The GPDAT register cannot be used to determine the value of output
* pins on MPC8572/MPC8536, so we shadow it and use the shadowed value
* for output pins */
u32 dat_shadow;
};
inline u32 gpio_mask(unsigned gpio) {
return (1U << (31 - (gpio)));
}
static inline u32 mpc85xx_gpio_get_val(struct ccsr_gpio *base, u32 mask)
{
return in_be32(&base->gpdat) & mask;
}
static inline u32 mpc85xx_gpio_get_dir(struct ccsr_gpio *base, u32 mask)
{
return in_be32(&base->gpdir) & mask;
}
static inline void mpc85xx_gpio_set_in(struct ccsr_gpio *base, u32 gpios)
{
clrbits_be32(&base->gpdat, gpios);
/* GPDIR register 0 -> input */
clrbits_be32(&base->gpdir, gpios);
}
static inline void mpc85xx_gpio_set_low(struct ccsr_gpio *base, u32 gpios)
{
clrbits_be32(&base->gpdat, gpios);
/* GPDIR register 1 -> output */
setbits_be32(&base->gpdir, gpios);
}
static inline void mpc85xx_gpio_set_high(struct ccsr_gpio *base, u32 gpios)
{
setbits_be32(&base->gpdat, gpios);
/* GPDIR register 1 -> output */
setbits_be32(&base->gpdir, gpios);
}
static inline int mpc85xx_gpio_open_drain_val(struct ccsr_gpio *base, u32 mask)
{
return in_be32(&base->gpodr) & mask;
}
static inline void mpc85xx_gpio_open_drain_on(struct ccsr_gpio *base, u32
gpios)
{
/* GPODR register 1 -> open drain on */
setbits_be32(&base->gpodr, gpios);
}
static inline void mpc85xx_gpio_open_drain_off(struct ccsr_gpio *base,
u32 gpios)
{
/* GPODR register 0 -> open drain off (actively driven) */
clrbits_be32(&base->gpodr, gpios);
}
static int mpc85xx_gpio_direction_input(struct udevice *dev, unsigned gpio)
{
struct mpc85xx_gpio_data *data = dev_get_priv(dev);
mpc85xx_gpio_set_in(data->base, gpio_mask(gpio));
return 0;
}
static int mpc85xx_gpio_set_value(struct udevice *dev, unsigned gpio,
int value)
{
struct mpc85xx_gpio_data *data = dev_get_priv(dev);
if (value) {
data->dat_shadow |= gpio_mask(gpio);
mpc85xx_gpio_set_high(data->base, gpio_mask(gpio));
} else {
data->dat_shadow &= ~gpio_mask(gpio);
mpc85xx_gpio_set_low(data->base, gpio_mask(gpio));
}
return 0;
}
static int mpc85xx_gpio_direction_output(struct udevice *dev, unsigned gpio,
int value)
{
return mpc85xx_gpio_set_value(dev, gpio, value);
}
static int mpc85xx_gpio_get_value(struct udevice *dev, unsigned gpio)
{
struct mpc85xx_gpio_data *data = dev_get_priv(dev);
if (!!mpc85xx_gpio_get_dir(data->base, gpio_mask(gpio))) {
/* Output -> use shadowed value */
return !!(data->dat_shadow & gpio_mask(gpio));
} else {
/* Input -> read value from GPDAT register */
return !!mpc85xx_gpio_get_val(data->base, gpio_mask(gpio));
}
}
static int mpc85xx_gpio_get_open_drain(struct udevice *dev, unsigned gpio)
{
struct mpc85xx_gpio_data *data = dev_get_priv(dev);
return !!mpc85xx_gpio_open_drain_val(data->base, gpio_mask(gpio));
}
static int mpc85xx_gpio_set_open_drain(struct udevice *dev, unsigned gpio,
int value)
{
struct mpc85xx_gpio_data *data = dev_get_priv(dev);
if (value) {
mpc85xx_gpio_open_drain_on(data->base, gpio_mask(gpio));
} else {
mpc85xx_gpio_open_drain_off(data->base, gpio_mask(gpio));
}
return 0;
}
static int mpc85xx_gpio_get_function(struct udevice *dev, unsigned gpio)
{
struct mpc85xx_gpio_data *data = dev_get_priv(dev);
int dir;
dir = !!mpc85xx_gpio_get_dir(data->base, gpio_mask(gpio));
return dir ? GPIOF_OUTPUT : GPIOF_INPUT;
}
static int mpc85xx_gpio_ofdata_to_platdata(struct udevice *dev) {
struct mpc85xx_gpio_data *data = dev_get_priv(dev);
fdt_addr_t addr;
fdt_size_t size;
addr = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev->of_offset,
"reg", 0, &size);
data->addr = addr;
data->base = map_sysmem(CONFIG_SYS_IMMR + addr, size);
if (!data->base)
return -ENOMEM;
data->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
"ngpios", 32);
data->dat_shadow = 0;
return 0;
}
static int mpc85xx_gpio_probe(struct udevice *dev)
{
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct mpc85xx_gpio_data *data = dev_get_priv(dev);
char name[32], *str;
snprintf(name, sizeof(name), "MPC@%lx_", data->addr);
str = strdup(name);
if (!str)
return -ENOMEM;
uc_priv->bank_name = str;
uc_priv->gpio_count = data->gpio_count;
return 0;
}
static const struct dm_gpio_ops gpio_mpc85xx_ops = {
.direction_input = mpc85xx_gpio_direction_input,
.direction_output = mpc85xx_gpio_direction_output,
.get_value = mpc85xx_gpio_get_value,
.set_value = mpc85xx_gpio_set_value,
.get_open_drain = mpc85xx_gpio_get_open_drain,
.set_open_drain = mpc85xx_gpio_set_open_drain,
.get_function = mpc85xx_gpio_get_function,
};
static const struct udevice_id mpc85xx_gpio_ids[] = {
{ .compatible = "fsl,pq3-gpio" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(gpio_mpc85xx) = {
.name = "gpio_mpc85xx",
.id = UCLASS_GPIO,
.ops = &gpio_mpc85xx_ops,
.ofdata_to_platdata = mpc85xx_gpio_ofdata_to_platdata,
.of_match = mpc85xx_gpio_ids,
.probe = mpc85xx_gpio_probe,
.priv_auto_alloc_size = sizeof(struct mpc85xx_gpio_data),
};

View File

@@ -15,6 +15,7 @@ DECLARE_GLOBAL_DATA_PTR;
/* Flags for each GPIO */
#define GPIOF_OUTPUT (1 << 0) /* Currently set as an output */
#define GPIOF_HIGH (1 << 1) /* Currently set high */
#define GPIOF_ODR (1 << 2) /* Currently set to open drain mode */
struct gpio_state {
const char *label; /* label given by requester */
@@ -70,6 +71,16 @@ int sandbox_gpio_set_value(struct udevice *dev, unsigned offset, int value)
return set_gpio_flag(dev, offset, GPIOF_HIGH, value);
}
int sandbox_gpio_get_open_drain(struct udevice *dev, unsigned offset)
{
return get_gpio_flag(dev, offset, GPIOF_ODR);
}
int sandbox_gpio_set_open_drain(struct udevice *dev, unsigned offset, int value)
{
return set_gpio_flag(dev, offset, GPIOF_ODR, value);
}
int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
{
return get_gpio_flag(dev, offset, GPIOF_OUTPUT);
@@ -124,6 +135,28 @@ static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value)
return sandbox_gpio_set_value(dev, offset, value);
}
/* read GPIO ODR value of port 'offset' */
static int sb_gpio_get_open_drain(struct udevice *dev, unsigned offset)
{
debug("%s: offset:%u\n", __func__, offset);
return sandbox_gpio_get_open_drain(dev, offset);
}
/* write GPIO ODR value to port 'offset' */
static int sb_gpio_set_open_drain(struct udevice *dev, unsigned offset, int value)
{
debug("%s: offset:%u, value = %d\n", __func__, offset, value);
if (!sandbox_gpio_get_direction(dev, offset)) {
printf("sandbox_gpio: error: set_open_drain on input gpio %u\n",
offset);
return -1;
}
return sandbox_gpio_set_open_drain(dev, offset, value);
}
static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
{
if (get_gpio_flag(dev, offset, GPIOF_OUTPUT))
@@ -154,6 +187,8 @@ static const struct dm_gpio_ops gpio_sandbox_ops = {
.direction_output = sb_gpio_direction_output,
.get_value = sb_gpio_get_value,
.set_value = sb_gpio_set_value,
.get_open_drain = sb_gpio_get_open_drain,
.set_open_drain = sb_gpio_set_open_drain,
.get_function = sb_gpio_get_function,
.xlate = sb_gpio_xlate,
};