u-boot-brain/drivers/gpio/mxs_gpio.c
Simon Glass caa4daa2ae dm: treewide: Rename 'platdata' variables to just 'plat'
We use 'priv' for private data but often use 'platdata' for platform data.
We can't really use 'pdata' since that is ambiguous (it could mean private
or platform data).

Rename some of the latter variables to end with 'plat' for consistency.

Signed-off-by: Simon Glass <sjg@chromium.org>
2020-12-13 16:51:08 -07:00

311 lines
7.6 KiB
C

// 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 <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->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->reg_set);
else
writel(1 << PAD_PIN(gpio), &reg->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->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->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_platdata {
#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->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->reg_set);
else
writel(BIT(offset), &reg->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->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->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->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_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_ofdata_to_platdata(struct udevice *dev)
{
struct mxs_gpio_platdata *plat = dev->plat;
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_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
};
U_BOOT_DRIVER_ALIAS(fsl_imx23_gpio, fsl_imx28_gpio)
#endif /* DM_GPIO */