diff options
Diffstat (limited to 'roms/u-boot/drivers/gpio/mxs_gpio.c')
-rw-r--r-- | roms/u-boot/drivers/gpio/mxs_gpio.c | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/gpio/mxs_gpio.c b/roms/u-boot/drivers/gpio/mxs_gpio.c new file mode 100644 index 000000000..5775a22ab --- /dev/null +++ b/roms/u-boot/drivers/gpio/mxs_gpio.c @@ -0,0 +1,311 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Freescale i.MX28 GPIO control code + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + */ + +#include <common.h> +#include <log.h> +#include <malloc.h> +#include <asm/global_data.h> +#include <linux/bitops.h> +#include <linux/errno.h> +#include <asm/io.h> +#include <asm/arch/iomux.h> +#include <asm/arch/imx-regs.h> + +#if defined(CONFIG_MX23) +#define PINCTRL_BANKS 3 +#define PINCTRL_DOUT(n) (0x0500 + ((n) * 0x10)) +#define PINCTRL_DIN(n) (0x0600 + ((n) * 0x10)) +#define PINCTRL_DOE(n) (0x0700 + ((n) * 0x10)) +#define PINCTRL_PIN2IRQ(n) (0x0800 + ((n) * 0x10)) +#define PINCTRL_IRQEN(n) (0x0900 + ((n) * 0x10)) +#define PINCTRL_IRQSTAT(n) (0x0c00 + ((n) * 0x10)) +#elif defined(CONFIG_MX28) +#define PINCTRL_BANKS 5 +#define PINCTRL_DOUT(n) (0x0700 + ((n) * 0x10)) +#define PINCTRL_DIN(n) (0x0900 + ((n) * 0x10)) +#define PINCTRL_DOE(n) (0x0b00 + ((n) * 0x10)) +#define PINCTRL_PIN2IRQ(n) (0x1000 + ((n) * 0x10)) +#define PINCTRL_IRQEN(n) (0x1100 + ((n) * 0x10)) +#define PINCTRL_IRQSTAT(n) (0x1400 + ((n) * 0x10)) +#else +#error "Please select CONFIG_MX23 or CONFIG_MX28" +#endif + +#define GPIO_INT_FALL_EDGE 0x0 +#define GPIO_INT_LOW_LEV 0x1 +#define GPIO_INT_RISE_EDGE 0x2 +#define GPIO_INT_HIGH_LEV 0x3 +#define GPIO_INT_LEV_MASK (1 << 0) +#define GPIO_INT_POL_MASK (1 << 1) + +void mxs_gpio_init(void) +{ + int i; + + for (i = 0; i < PINCTRL_BANKS; i++) { + writel(0, MXS_PINCTRL_BASE + PINCTRL_PIN2IRQ(i)); + writel(0, MXS_PINCTRL_BASE + PINCTRL_IRQEN(i)); + /* Use SCT address here to clear the IRQSTAT bits */ + writel(0xffffffff, MXS_PINCTRL_BASE + PINCTRL_IRQSTAT(i) + 8); + } +} + +#if !CONFIG_IS_ENABLED(DM_GPIO) +int gpio_get_value(unsigned gpio) +{ + uint32_t bank = PAD_BANK(gpio); + uint32_t offset = PINCTRL_DIN(bank); + struct mxs_register_32 *reg = + (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset); + + return (readl(®->reg) >> PAD_PIN(gpio)) & 1; +} + +void gpio_set_value(unsigned gpio, int value) +{ + uint32_t bank = PAD_BANK(gpio); + uint32_t offset = PINCTRL_DOUT(bank); + struct mxs_register_32 *reg = + (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset); + + if (value) + writel(1 << PAD_PIN(gpio), ®->reg_set); + else + writel(1 << PAD_PIN(gpio), ®->reg_clr); +} + +int gpio_direction_input(unsigned gpio) +{ + uint32_t bank = PAD_BANK(gpio); + uint32_t offset = PINCTRL_DOE(bank); + struct mxs_register_32 *reg = + (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset); + + writel(1 << PAD_PIN(gpio), ®->reg_clr); + + return 0; +} + +int gpio_direction_output(unsigned gpio, int value) +{ + uint32_t bank = PAD_BANK(gpio); + uint32_t offset = PINCTRL_DOE(bank); + struct mxs_register_32 *reg = + (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset); + + gpio_set_value(gpio, value); + + writel(1 << PAD_PIN(gpio), ®->reg_set); + + return 0; +} + +int gpio_request(unsigned gpio, const char *label) +{ + if (PAD_BANK(gpio) >= PINCTRL_BANKS) + return -1; + + return 0; +} + +int gpio_free(unsigned gpio) +{ + return 0; +} + +int name_to_gpio(const char *name) +{ + unsigned bank, pin; + char *end; + + bank = simple_strtoul(name, &end, 10); + + if (!*end || *end != ':') + return bank; + + pin = simple_strtoul(end + 1, NULL, 10); + + return (bank << MXS_PAD_BANK_SHIFT) | (pin << MXS_PAD_PIN_SHIFT); +} +#else /* DM_GPIO */ +#include <dm.h> +#include <asm/gpio.h> +#include <dt-structs.h> +#include <asm/arch/gpio.h> +#define MXS_MAX_GPIO_PER_BANK 32 + +DECLARE_GLOBAL_DATA_PTR; +/* + * According to i.MX28 Reference Manual: + * 'i.MX28 Applications Processor Reference Manual, Rev. 1, 2010' + * The i.MX28 has following number of GPIOs available: + * Bank 0: 0-28 -> 29 PINS + * Bank 1: 0-31 -> 32 PINS + * Bank 2: 0-27 -> 28 PINS + * Bank 3: 0-30 -> 31 PINS + * Bank 4: 0-20 -> 21 PINS + */ + +struct mxs_gpio_plat { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_fsl_imx23_gpio dtplat; +#endif + unsigned int bank; + int gpio_ranges; +}; + +struct mxs_gpio_priv { + unsigned int bank; +}; + +static int mxs_gpio_get_value(struct udevice *dev, unsigned offset) +{ + struct mxs_gpio_priv *priv = dev_get_priv(dev); + struct mxs_register_32 *reg = + (struct mxs_register_32 *)(MXS_PINCTRL_BASE + + PINCTRL_DIN(priv->bank)); + + return (readl(®->reg) >> offset) & 1; +} + +static int mxs_gpio_set_value(struct udevice *dev, unsigned offset, + int value) +{ + struct mxs_gpio_priv *priv = dev_get_priv(dev); + struct mxs_register_32 *reg = + (struct mxs_register_32 *)(MXS_PINCTRL_BASE + + PINCTRL_DOUT(priv->bank)); + if (value) + writel(BIT(offset), ®->reg_set); + else + writel(BIT(offset), ®->reg_clr); + + return 0; +} + +static int mxs_gpio_direction_input(struct udevice *dev, unsigned offset) +{ + struct mxs_gpio_priv *priv = dev_get_priv(dev); + struct mxs_register_32 *reg = + (struct mxs_register_32 *)(MXS_PINCTRL_BASE + + PINCTRL_DOE(priv->bank)); + + writel(BIT(offset), ®->reg_clr); + + return 0; +} + +static int mxs_gpio_direction_output(struct udevice *dev, unsigned offset, + int value) +{ + struct mxs_gpio_priv *priv = dev_get_priv(dev); + struct mxs_register_32 *reg = + (struct mxs_register_32 *)(MXS_PINCTRL_BASE + + PINCTRL_DOE(priv->bank)); + + mxs_gpio_set_value(dev, offset, value); + + writel(BIT(offset), ®->reg_set); + + return 0; +} + +static int mxs_gpio_get_function(struct udevice *dev, unsigned offset) +{ + struct mxs_gpio_priv *priv = dev_get_priv(dev); + struct mxs_register_32 *reg = + (struct mxs_register_32 *)(MXS_PINCTRL_BASE + + PINCTRL_DOE(priv->bank)); + bool is_output = !!(readl(®->reg) >> offset); + + return is_output ? GPIOF_OUTPUT : GPIOF_INPUT; +} + +static const struct dm_gpio_ops gpio_mxs_ops = { + .direction_input = mxs_gpio_direction_input, + .direction_output = mxs_gpio_direction_output, + .get_value = mxs_gpio_get_value, + .set_value = mxs_gpio_set_value, + .get_function = mxs_gpio_get_function, +}; + +static int mxs_gpio_probe(struct udevice *dev) +{ + struct mxs_gpio_plat *plat = dev_get_plat(dev); + struct mxs_gpio_priv *priv = dev_get_priv(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + char name[16], *str; + +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_fsl_imx23_gpio *dtplat = &plat->dtplat; + priv->bank = (unsigned int)dtplat->reg[0]; + uc_priv->gpio_count = dtplat->gpio_ranges[3]; +#else + priv->bank = (unsigned int)plat->bank; + uc_priv->gpio_count = plat->gpio_ranges; +#endif + snprintf(name, sizeof(name), "GPIO%d_", priv->bank); + str = strdup(name); + if (!str) + return -ENOMEM; + + uc_priv->bank_name = str; + + debug("%s: %s: %d pins base: 0x%x\n", __func__, uc_priv->bank_name, + uc_priv->gpio_count, priv->bank); + + return 0; +} + +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) +static int mxs_of_to_plat(struct udevice *dev) +{ + struct mxs_gpio_plat *plat = dev_get_plat(dev); + struct fdtdec_phandle_args args; + int node = dev_of_offset(dev); + int ret; + + plat->bank = dev_read_addr(dev); + if (plat->bank == FDT_ADDR_T_NONE) { + printf("%s: No 'reg' property defined!\n", __func__); + return -EINVAL; + } + + ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, node, "gpio-ranges", + NULL, 3, 0, &args); + if (ret) + printf("%s: 'gpio-ranges' not defined - using default!\n", + __func__); + + plat->gpio_ranges = ret == 0 ? args.args[2] : MXS_MAX_GPIO_PER_BANK; + + return 0; +} + +static const struct udevice_id mxs_gpio_ids[] = { + { .compatible = "fsl,imx23-gpio" }, + { .compatible = "fsl,imx28-gpio" }, + { } +}; +#endif + +U_BOOT_DRIVER(fsl_imx23_gpio) = { + .name = "fsl_imx23_gpio", + .id = UCLASS_GPIO, + .ops = &gpio_mxs_ops, + .probe = mxs_gpio_probe, + .priv_auto = sizeof(struct mxs_gpio_priv), + .plat_auto = sizeof(struct mxs_gpio_plat), +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) + .of_match = mxs_gpio_ids, + .of_to_plat = mxs_of_to_plat, +#endif +}; + +DM_DRIVER_ALIAS(fsl_imx23_gpio, fsl_imx28_gpio) +#endif /* DM_GPIO */ |