X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fgpio%2Fmxs_gpio.c;h=77778e9ce57fa51a45e6dce684b6d5c40dfb15c9;hb=9d5d74c3ccdc78bac969d25e98eab96872e33b5c;hp=38dbc81b4510d1aca23f83d8d73076208894b3c9;hpb=5c877b1ae0a4219ed6bd8d32cf3f7106b81ecb3b;p=oweals%2Fu-boot.git diff --git a/drivers/gpio/mxs_gpio.c b/drivers/gpio/mxs_gpio.c index 38dbc81b45..77778e9ce5 100644 --- a/drivers/gpio/mxs_gpio.c +++ b/drivers/gpio/mxs_gpio.c @@ -1,31 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Freescale i.MX28 GPIO control code * * Copyright (C) 2011 Marek Vasut * on behalf of DENX Software Engineering GmbH - * - * 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 as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA */ #include -#include -#include +#include #include #include #include @@ -69,12 +51,13 @@ void mxs_gpio_init(void) } } +#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 mx28_register_32 *reg = - (struct mx28_register_32 *)(MXS_PINCTRL_BASE + offset); + struct mxs_register_32 *reg = + (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset); return (readl(®->reg) >> PAD_PIN(gpio)) & 1; } @@ -83,8 +66,8 @@ void gpio_set_value(unsigned gpio, int value) { uint32_t bank = PAD_BANK(gpio); uint32_t offset = PINCTRL_DOUT(bank); - struct mx28_register_32 *reg = - (struct mx28_register_32 *)(MXS_PINCTRL_BASE + offset); + struct mxs_register_32 *reg = + (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset); if (value) writel(1 << PAD_PIN(gpio), ®->reg_set); @@ -96,8 +79,8 @@ int gpio_direction_input(unsigned gpio) { uint32_t bank = PAD_BANK(gpio); uint32_t offset = PINCTRL_DOE(bank); - struct mx28_register_32 *reg = - (struct mx28_register_32 *)(MXS_PINCTRL_BASE + offset); + struct mxs_register_32 *reg = + (struct mxs_register_32 *)(MXS_PINCTRL_BASE + offset); writel(1 << PAD_PIN(gpio), ®->reg_clr); @@ -108,13 +91,13 @@ int gpio_direction_output(unsigned gpio, int value) { uint32_t bank = PAD_BANK(gpio); uint32_t offset = PINCTRL_DOE(bank); - struct mx28_register_32 *reg = - (struct mx28_register_32 *)(MXS_PINCTRL_BASE + offset); - - writel(1 << PAD_PIN(gpio), ®->reg_set); + 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; } @@ -130,3 +113,203 @@ 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 +#include +#include +#include +#define MXS_MAX_GPIO_PER_BANK 32 + +#ifdef CONFIG_MX28 +#define dtd_fsl_imx_gpio dtd_fsl_imx28_gpio +#else /* CONFIG_MX23 */ +#define dtd_fsl_imx_gpio dtd_fsl_imx23_gpio +#endif + +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_platdata { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_fsl_imx_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_platdata *plat = dev_get_platdata(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_imx_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_ofdata_to_platdata(struct udevice *dev) +{ + struct mxs_gpio_platdata *plat = dev->platdata; + struct fdtdec_phandle_args args; + int node = dev_of_offset(dev); + int ret; + + plat->bank = devfdt_get_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(gpio_mxs) = { +#ifdef CONFIG_MX28 + .name = "fsl_imx28_gpio", +#else /* CONFIG_MX23 */ + .name = "fsl_imx23_gpio", +#endif + .id = UCLASS_GPIO, + .ops = &gpio_mxs_ops, + .probe = mxs_gpio_probe, + .priv_auto_alloc_size = sizeof(struct mxs_gpio_priv), + .platdata_auto_alloc_size = sizeof(struct mxs_gpio_platdata), +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) + .of_match = mxs_gpio_ids, + .ofdata_to_platdata = mxs_ofdata_to_platdata, +#endif +}; +#endif /* DM_GPIO */