Hi Simon, On Mon, Mar 7, 2016 at 10:28 AM, Simon Glass <s...@chromium.org> wrote: > Add a GPIO driver for the GPIO peripheral found on broadwell devices. > > Signed-off-by: Simon Glass <s...@chromium.org> > --- > > drivers/gpio/Kconfig | 9 ++ > drivers/gpio/Makefile | 1 + > drivers/gpio/intel_broadwell_gpio.c | 198 > ++++++++++++++++++++++++++++++++++++ > 3 files changed, 208 insertions(+) > create mode 100644 drivers/gpio/intel_broadwell_gpio.c > > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig > index 845dc72..e7ec384 100644 > --- a/drivers/gpio/Kconfig > +++ b/drivers/gpio/Kconfig > @@ -39,6 +39,15 @@ config ATMEL_PIO4 > may be dedicated as a general purpose I/O or be assigned to > a function of an embedded peripheral. > > +config INTEL_BROADWELL_GPIO > + bool "Intel Broadwell GPIO driver" > + depends on DM > + help > + This driver supports Broadwell U devices which have an expanded > + GPIO feature set. The difference is large enough to merit a separate > + driver from the common Intel ICH6 driver. It supports a total of > + 95 GPIOs which can be configure from the device tree.
typo: configured > + > config LPC32XX_GPIO > bool "LPC32XX GPIO driver" > depends on DM > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile > index 845a6d4..5ac381a 100644 > --- a/drivers/gpio/Makefile > +++ b/drivers/gpio/Makefile > @@ -14,6 +14,7 @@ obj-$(CONFIG_DM_GPIO) += gpio-uclass.o > obj-$(CONFIG_AT91_GPIO) += at91_gpio.o > obj-$(CONFIG_ATMEL_PIO4) += atmel_pio4.o > obj-$(CONFIG_INTEL_ICH6_GPIO) += intel_ich6_gpio.o > +obj-$(CONFIG_INTEL_BROADWELL_GPIO) += intel_broadwell_gpio.o > obj-$(CONFIG_KIRKWOOD_GPIO) += kw_gpio.o > obj-$(CONFIG_KONA_GPIO) += kona_gpio.o > obj-$(CONFIG_MARVELL_GPIO) += mvgpio.o > diff --git a/drivers/gpio/intel_broadwell_gpio.c > b/drivers/gpio/intel_broadwell_gpio.c > new file mode 100644 > index 0000000..06bf46b > --- /dev/null > +++ b/drivers/gpio/intel_broadwell_gpio.c > @@ -0,0 +1,198 @@ > +/* > + * Copyright (c) 2012 The Chromium OS Authors. > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <dm.h> > +#include <errno.h> > +#include <fdtdec.h> > +#include <pch.h> > +#include <pci.h> > +#include <syscon.h> > +#include <asm/cpu.h> > +#include <asm/gpio.h> > +#include <asm/io.h> > +#include <asm/pci.h> > +#include <asm/arch/gpio.h> > +#include <dt-bindings/gpio/x86-gpio.h> > + > +DECLARE_GLOBAL_DATA_PTR; > + > +/** > + * struct broadwell_bank_priv - Private driver data > + * > + * @regs: Pointer to GPIO registers > + * @bank: Bank number for this bank (0, 1 or 2) > + * @offset: GPIO offset for this bank (0, 32 or 64) > + */ > +struct broadwell_bank_priv { > + struct pch_lp_gpio_regs *regs; > + int bank; > + int offset; > +}; > + > +static int broadwell_gpio_request(struct udevice *dev, unsigned offset, > + const char *label) > +{ > + struct broadwell_bank_priv *priv = dev_get_priv(dev); > + struct pch_lp_gpio_regs *regs = priv->regs; > + u32 val; > + > + /* > + * Make sure that the GPIO pin we want isn't already in use for some > + * built-in hardware function. We have to check this for every > + * requested pin. > + */ > + debug("%s: request bank %d offset %d: ", __func__, priv->bank, > offset); > + val = inl(®s->own[priv->bank]); > + if (!(val & (1UL << offset))) { > + debug("gpio is reserved for internal use\n"); > + return -EPERM; > + } > + debug("ok\n"); > + > + return 0; > +} > + > +static int broadwell_gpio_direction_input(struct udevice *dev, unsigned > offset) > +{ > + struct broadwell_bank_priv *priv = dev_get_priv(dev); > + struct pch_lp_gpio_regs *regs = priv->regs; > + > + setio_le32(®s->config[priv->offset + offset], CONFA_DIR_INPUT); > + > + return 0; > +} > + > +static int broadwell_gpio_get_value(struct udevice *dev, unsigned offset) > +{ > + struct broadwell_bank_priv *priv = dev_get_priv(dev); > + struct pch_lp_gpio_regs *regs = priv->regs; > + > + return inl(®s->config[priv->offset + offset]) & CONFA_LEVEL_HIGH ? > + 1 : 0; > +} > + > +static int broadwell_gpio_set_value(struct udevice *dev, unsigned offset, > + int value) > +{ > + struct broadwell_bank_priv *priv = dev_get_priv(dev); > + struct pch_lp_gpio_regs *regs = priv->regs; > + > + debug("%s: dev=%s, offset=%d, value=%d\n", __func__, dev->name, > offset, > + value); > + clrsetio_le32(®s->config[priv->offset + offset], CONFA_OUTPUT_HIGH, > + value ? CONFA_OUTPUT_HIGH : 0); > + > + return 0; > +} > + > +static int broadwell_gpio_direction_output(struct udevice *dev, unsigned > offset, > + int value) > +{ > + struct broadwell_bank_priv *priv = dev_get_priv(dev); > + struct pch_lp_gpio_regs *regs = priv->regs; > + > + broadwell_gpio_set_value(dev, offset, value); > + clrio_le32(®s->config[priv->offset + offset], CONFA_DIR_INPUT); > + > + return 0; > +} > + > +static int broadwell_gpio_get_function(struct udevice *dev, unsigned offset) > +{ > + struct broadwell_bank_priv *priv = dev_get_priv(dev); > + struct pch_lp_gpio_regs *regs = priv->regs; > + u32 mask = 1UL << offset; > + > + if (!(inl(®s->own[priv->bank]) & mask)) > + return GPIOF_FUNC; > + if (inl(®s->config[priv->offset + offset]) & CONFA_DIR_INPUT) > + return GPIOF_INPUT; > + else > + return GPIOF_OUTPUT; > +} > + > +static int broadwell_gpio_probe(struct udevice *dev) > +{ > + struct broadwell_bank_platdata *plat = dev_get_platdata(dev); > + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); > + struct broadwell_bank_priv *priv = dev_get_priv(dev); > + struct udevice *pinctrl; > + int ret; > + > + /* Set up pin control if available */ > + ret = syscon_get_by_driver_data(X86_SYSCON_PINCONF, &pinctrl); > + debug("%s, pinctrl=%p, ret=%d\n", __func__, pinctrl, ret); > + > + uc_priv->gpio_count = GPIO_PER_BANK; > + uc_priv->bank_name = plat->bank_name; > + > + priv->regs = (struct pch_lp_gpio_regs *)(uintptr_t)plat->base_addr; > + priv->bank = plat->bank; > + priv->offset = priv->bank * 32; > + debug("%s: probe done, regs %p, bank %d\n", __func__, priv->regs, > + priv->bank); > + > + return 0; > +} > + > +static int broadwell_gpio_ofdata_to_platdata(struct udevice *dev) > +{ > + struct broadwell_bank_platdata *plat = dev_get_platdata(dev); > + u32 gpiobase; > + int bank; > + int ret; > + > + ret = pch_get_gpio_base(dev->parent, &gpiobase); > + if (ret) > + return ret; > + > + bank = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", -1); > + if (bank == -1) { > + debug("%s: Invalid bank number %d\n", __func__, bank); > + return -EINVAL; > + } > + plat->bank = bank; > + plat->base_addr = gpiobase; > + plat->bank_name = fdt_getprop(gd->fdt_blob, dev->of_offset, > + "bank-name", NULL); > + > + return 0; > +} > + > +static int broadwell_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, > + struct fdtdec_phandle_args *args) > +{ > + desc->offset = args->args[0]; > + desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0; > + > + return 0; > +} > + > +static const struct dm_gpio_ops gpio_broadwell_ops = { > + .request = broadwell_gpio_request, > + .direction_input = broadwell_gpio_direction_input, > + .direction_output = broadwell_gpio_direction_output, > + .get_value = broadwell_gpio_get_value, > + .set_value = broadwell_gpio_set_value, > + .get_function = broadwell_gpio_get_function, > + .xlate = broadwell_gpio_xlate, > +}; > + > +static const struct udevice_id intel_broadwell_gpio_ids[] = { > + { .compatible = "intel,broadwell-gpio" }, > + { } > +}; > + > +U_BOOT_DRIVER(gpio_broadwell) = { > + .name = "gpio_broadwell", > + .id = UCLASS_GPIO, > + .of_match = intel_broadwell_gpio_ids, > + .ops = &gpio_broadwell_ops, > + .ofdata_to_platdata = broadwell_gpio_ofdata_to_platdata, > + .probe = broadwell_gpio_probe, > + .priv_auto_alloc_size = sizeof(struct broadwell_bank_priv), > + .platdata_auto_alloc_size = sizeof(struct broadwell_bank_platdata), > +}; > -- Acked-by: Bin Meng <bmeng...@gmail.com> Regards, Bin _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot