107d31f8fSmario.six@gdsys.cc /*
207d31f8fSmario.six@gdsys.cc * (C) Copyright 2016
307d31f8fSmario.six@gdsys.cc * Mario Six, Guntermann & Drunck GmbH, six@gdsys.de
407d31f8fSmario.six@gdsys.cc *
507d31f8fSmario.six@gdsys.cc * based on arch/powerpc/include/asm/mpc85xx_gpio.h, which is
607d31f8fSmario.six@gdsys.cc *
707d31f8fSmario.six@gdsys.cc * Copyright 2010 eXMeritus, A Boeing Company
807d31f8fSmario.six@gdsys.cc *
907d31f8fSmario.six@gdsys.cc * SPDX-License-Identifier: GPL-2.0+
1007d31f8fSmario.six@gdsys.cc */
1107d31f8fSmario.six@gdsys.cc
1207d31f8fSmario.six@gdsys.cc #include <common.h>
1307d31f8fSmario.six@gdsys.cc #include <dm.h>
1407d31f8fSmario.six@gdsys.cc #include <asm/gpio.h>
1507d31f8fSmario.six@gdsys.cc #include <mapmem.h>
1607d31f8fSmario.six@gdsys.cc
1707d31f8fSmario.six@gdsys.cc DECLARE_GLOBAL_DATA_PTR;
1807d31f8fSmario.six@gdsys.cc
1907d31f8fSmario.six@gdsys.cc struct ccsr_gpio {
2007d31f8fSmario.six@gdsys.cc u32 gpdir;
2107d31f8fSmario.six@gdsys.cc u32 gpodr;
2207d31f8fSmario.six@gdsys.cc u32 gpdat;
2307d31f8fSmario.six@gdsys.cc u32 gpier;
2407d31f8fSmario.six@gdsys.cc u32 gpimr;
2507d31f8fSmario.six@gdsys.cc u32 gpicr;
2607d31f8fSmario.six@gdsys.cc };
2707d31f8fSmario.six@gdsys.cc
2807d31f8fSmario.six@gdsys.cc struct mpc85xx_gpio_data {
2907d31f8fSmario.six@gdsys.cc /* The bank's register base in memory */
3007d31f8fSmario.six@gdsys.cc struct ccsr_gpio __iomem *base;
3107d31f8fSmario.six@gdsys.cc /* The address of the registers; used to identify the bank */
3207d31f8fSmario.six@gdsys.cc ulong addr;
3307d31f8fSmario.six@gdsys.cc /* The GPIO count of the bank */
3407d31f8fSmario.six@gdsys.cc uint gpio_count;
3507d31f8fSmario.six@gdsys.cc /* The GPDAT register cannot be used to determine the value of output
3607d31f8fSmario.six@gdsys.cc * pins on MPC8572/MPC8536, so we shadow it and use the shadowed value
3707d31f8fSmario.six@gdsys.cc * for output pins */
3807d31f8fSmario.six@gdsys.cc u32 dat_shadow;
3907d31f8fSmario.six@gdsys.cc };
4007d31f8fSmario.six@gdsys.cc
gpio_mask(unsigned gpio)4107d31f8fSmario.six@gdsys.cc inline u32 gpio_mask(unsigned gpio) {
4207d31f8fSmario.six@gdsys.cc return (1U << (31 - (gpio)));
4307d31f8fSmario.six@gdsys.cc }
4407d31f8fSmario.six@gdsys.cc
mpc85xx_gpio_get_val(struct ccsr_gpio * base,u32 mask)4507d31f8fSmario.six@gdsys.cc static inline u32 mpc85xx_gpio_get_val(struct ccsr_gpio *base, u32 mask)
4607d31f8fSmario.six@gdsys.cc {
4707d31f8fSmario.six@gdsys.cc return in_be32(&base->gpdat) & mask;
4807d31f8fSmario.six@gdsys.cc }
4907d31f8fSmario.six@gdsys.cc
mpc85xx_gpio_get_dir(struct ccsr_gpio * base,u32 mask)5007d31f8fSmario.six@gdsys.cc static inline u32 mpc85xx_gpio_get_dir(struct ccsr_gpio *base, u32 mask)
5107d31f8fSmario.six@gdsys.cc {
5207d31f8fSmario.six@gdsys.cc return in_be32(&base->gpdir) & mask;
5307d31f8fSmario.six@gdsys.cc }
5407d31f8fSmario.six@gdsys.cc
mpc85xx_gpio_set_in(struct ccsr_gpio * base,u32 gpios)5507d31f8fSmario.six@gdsys.cc static inline void mpc85xx_gpio_set_in(struct ccsr_gpio *base, u32 gpios)
5607d31f8fSmario.six@gdsys.cc {
5707d31f8fSmario.six@gdsys.cc clrbits_be32(&base->gpdat, gpios);
5807d31f8fSmario.six@gdsys.cc /* GPDIR register 0 -> input */
5907d31f8fSmario.six@gdsys.cc clrbits_be32(&base->gpdir, gpios);
6007d31f8fSmario.six@gdsys.cc }
6107d31f8fSmario.six@gdsys.cc
mpc85xx_gpio_set_low(struct ccsr_gpio * base,u32 gpios)6207d31f8fSmario.six@gdsys.cc static inline void mpc85xx_gpio_set_low(struct ccsr_gpio *base, u32 gpios)
6307d31f8fSmario.six@gdsys.cc {
6407d31f8fSmario.six@gdsys.cc clrbits_be32(&base->gpdat, gpios);
6507d31f8fSmario.six@gdsys.cc /* GPDIR register 1 -> output */
6607d31f8fSmario.six@gdsys.cc setbits_be32(&base->gpdir, gpios);
6707d31f8fSmario.six@gdsys.cc }
6807d31f8fSmario.six@gdsys.cc
mpc85xx_gpio_set_high(struct ccsr_gpio * base,u32 gpios)6907d31f8fSmario.six@gdsys.cc static inline void mpc85xx_gpio_set_high(struct ccsr_gpio *base, u32 gpios)
7007d31f8fSmario.six@gdsys.cc {
7107d31f8fSmario.six@gdsys.cc setbits_be32(&base->gpdat, gpios);
7207d31f8fSmario.six@gdsys.cc /* GPDIR register 1 -> output */
7307d31f8fSmario.six@gdsys.cc setbits_be32(&base->gpdir, gpios);
7407d31f8fSmario.six@gdsys.cc }
7507d31f8fSmario.six@gdsys.cc
mpc85xx_gpio_open_drain_val(struct ccsr_gpio * base,u32 mask)7651781783Smario.six@gdsys.cc static inline int mpc85xx_gpio_open_drain_val(struct ccsr_gpio *base, u32 mask)
7751781783Smario.six@gdsys.cc {
7851781783Smario.six@gdsys.cc return in_be32(&base->gpodr) & mask;
7951781783Smario.six@gdsys.cc }
8051781783Smario.six@gdsys.cc
mpc85xx_gpio_open_drain_on(struct ccsr_gpio * base,u32 gpios)8151781783Smario.six@gdsys.cc static inline void mpc85xx_gpio_open_drain_on(struct ccsr_gpio *base, u32
8251781783Smario.six@gdsys.cc gpios)
8351781783Smario.six@gdsys.cc {
8451781783Smario.six@gdsys.cc /* GPODR register 1 -> open drain on */
8551781783Smario.six@gdsys.cc setbits_be32(&base->gpodr, gpios);
8651781783Smario.six@gdsys.cc }
8751781783Smario.six@gdsys.cc
mpc85xx_gpio_open_drain_off(struct ccsr_gpio * base,u32 gpios)8851781783Smario.six@gdsys.cc static inline void mpc85xx_gpio_open_drain_off(struct ccsr_gpio *base,
8951781783Smario.six@gdsys.cc u32 gpios)
9051781783Smario.six@gdsys.cc {
9151781783Smario.six@gdsys.cc /* GPODR register 0 -> open drain off (actively driven) */
9251781783Smario.six@gdsys.cc clrbits_be32(&base->gpodr, gpios);
9351781783Smario.six@gdsys.cc }
9451781783Smario.six@gdsys.cc
mpc85xx_gpio_direction_input(struct udevice * dev,unsigned gpio)9507d31f8fSmario.six@gdsys.cc static int mpc85xx_gpio_direction_input(struct udevice *dev, unsigned gpio)
9607d31f8fSmario.six@gdsys.cc {
9707d31f8fSmario.six@gdsys.cc struct mpc85xx_gpio_data *data = dev_get_priv(dev);
9807d31f8fSmario.six@gdsys.cc
9907d31f8fSmario.six@gdsys.cc mpc85xx_gpio_set_in(data->base, gpio_mask(gpio));
10007d31f8fSmario.six@gdsys.cc return 0;
10107d31f8fSmario.six@gdsys.cc }
10207d31f8fSmario.six@gdsys.cc
mpc85xx_gpio_set_value(struct udevice * dev,unsigned gpio,int value)10307d31f8fSmario.six@gdsys.cc static int mpc85xx_gpio_set_value(struct udevice *dev, unsigned gpio,
10407d31f8fSmario.six@gdsys.cc int value)
10507d31f8fSmario.six@gdsys.cc {
10607d31f8fSmario.six@gdsys.cc struct mpc85xx_gpio_data *data = dev_get_priv(dev);
10707d31f8fSmario.six@gdsys.cc
10807d31f8fSmario.six@gdsys.cc if (value) {
10907d31f8fSmario.six@gdsys.cc data->dat_shadow |= gpio_mask(gpio);
11007d31f8fSmario.six@gdsys.cc mpc85xx_gpio_set_high(data->base, gpio_mask(gpio));
11107d31f8fSmario.six@gdsys.cc } else {
11207d31f8fSmario.six@gdsys.cc data->dat_shadow &= ~gpio_mask(gpio);
11307d31f8fSmario.six@gdsys.cc mpc85xx_gpio_set_low(data->base, gpio_mask(gpio));
11407d31f8fSmario.six@gdsys.cc }
11507d31f8fSmario.six@gdsys.cc return 0;
11607d31f8fSmario.six@gdsys.cc }
11707d31f8fSmario.six@gdsys.cc
mpc85xx_gpio_direction_output(struct udevice * dev,unsigned gpio,int value)11807d31f8fSmario.six@gdsys.cc static int mpc85xx_gpio_direction_output(struct udevice *dev, unsigned gpio,
11907d31f8fSmario.six@gdsys.cc int value)
12007d31f8fSmario.six@gdsys.cc {
12107d31f8fSmario.six@gdsys.cc return mpc85xx_gpio_set_value(dev, gpio, value);
12207d31f8fSmario.six@gdsys.cc }
12307d31f8fSmario.six@gdsys.cc
mpc85xx_gpio_get_value(struct udevice * dev,unsigned gpio)12407d31f8fSmario.six@gdsys.cc static int mpc85xx_gpio_get_value(struct udevice *dev, unsigned gpio)
12507d31f8fSmario.six@gdsys.cc {
12607d31f8fSmario.six@gdsys.cc struct mpc85xx_gpio_data *data = dev_get_priv(dev);
12707d31f8fSmario.six@gdsys.cc
12807d31f8fSmario.six@gdsys.cc if (!!mpc85xx_gpio_get_dir(data->base, gpio_mask(gpio))) {
12907d31f8fSmario.six@gdsys.cc /* Output -> use shadowed value */
13007d31f8fSmario.six@gdsys.cc return !!(data->dat_shadow & gpio_mask(gpio));
13107d31f8fSmario.six@gdsys.cc } else {
13207d31f8fSmario.six@gdsys.cc /* Input -> read value from GPDAT register */
13307d31f8fSmario.six@gdsys.cc return !!mpc85xx_gpio_get_val(data->base, gpio_mask(gpio));
13407d31f8fSmario.six@gdsys.cc }
13507d31f8fSmario.six@gdsys.cc }
13607d31f8fSmario.six@gdsys.cc
mpc85xx_gpio_get_open_drain(struct udevice * dev,unsigned gpio)13751781783Smario.six@gdsys.cc static int mpc85xx_gpio_get_open_drain(struct udevice *dev, unsigned gpio)
13851781783Smario.six@gdsys.cc {
13951781783Smario.six@gdsys.cc struct mpc85xx_gpio_data *data = dev_get_priv(dev);
14051781783Smario.six@gdsys.cc
14151781783Smario.six@gdsys.cc return !!mpc85xx_gpio_open_drain_val(data->base, gpio_mask(gpio));
14251781783Smario.six@gdsys.cc }
14351781783Smario.six@gdsys.cc
mpc85xx_gpio_set_open_drain(struct udevice * dev,unsigned gpio,int value)14451781783Smario.six@gdsys.cc static int mpc85xx_gpio_set_open_drain(struct udevice *dev, unsigned gpio,
14551781783Smario.six@gdsys.cc int value)
14651781783Smario.six@gdsys.cc {
14751781783Smario.six@gdsys.cc struct mpc85xx_gpio_data *data = dev_get_priv(dev);
14851781783Smario.six@gdsys.cc
14951781783Smario.six@gdsys.cc if (value) {
15051781783Smario.six@gdsys.cc mpc85xx_gpio_open_drain_on(data->base, gpio_mask(gpio));
15151781783Smario.six@gdsys.cc } else {
15251781783Smario.six@gdsys.cc mpc85xx_gpio_open_drain_off(data->base, gpio_mask(gpio));
15351781783Smario.six@gdsys.cc }
15451781783Smario.six@gdsys.cc return 0;
15551781783Smario.six@gdsys.cc }
15651781783Smario.six@gdsys.cc
mpc85xx_gpio_get_function(struct udevice * dev,unsigned gpio)15707d31f8fSmario.six@gdsys.cc static int mpc85xx_gpio_get_function(struct udevice *dev, unsigned gpio)
15807d31f8fSmario.six@gdsys.cc {
15907d31f8fSmario.six@gdsys.cc struct mpc85xx_gpio_data *data = dev_get_priv(dev);
16007d31f8fSmario.six@gdsys.cc int dir;
16107d31f8fSmario.six@gdsys.cc
16207d31f8fSmario.six@gdsys.cc dir = !!mpc85xx_gpio_get_dir(data->base, gpio_mask(gpio));
16307d31f8fSmario.six@gdsys.cc return dir ? GPIOF_OUTPUT : GPIOF_INPUT;
16407d31f8fSmario.six@gdsys.cc }
16507d31f8fSmario.six@gdsys.cc
1664b689f02SHamish Martin #if CONFIG_IS_ENABLED(OF_CONTROL)
mpc85xx_gpio_ofdata_to_platdata(struct udevice * dev)16707d31f8fSmario.six@gdsys.cc static int mpc85xx_gpio_ofdata_to_platdata(struct udevice *dev) {
1684b689f02SHamish Martin struct mpc85xx_gpio_plat *plat = dev_get_platdata(dev);
16907d31f8fSmario.six@gdsys.cc fdt_addr_t addr;
17007d31f8fSmario.six@gdsys.cc fdt_size_t size;
17107d31f8fSmario.six@gdsys.cc
172*e160f7d4SSimon Glass addr = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob,
173*e160f7d4SSimon Glass dev_of_offset(dev), "reg", 0, &size, false);
17407d31f8fSmario.six@gdsys.cc
1754b689f02SHamish Martin plat->addr = addr;
1764b689f02SHamish Martin plat->size = size;
177*e160f7d4SSimon Glass plat->ngpios = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
1784b689f02SHamish Martin "ngpios", 32);
17907d31f8fSmario.six@gdsys.cc
1804b689f02SHamish Martin return 0;
1814b689f02SHamish Martin }
1824b689f02SHamish Martin #endif
1834b689f02SHamish Martin
mpc85xx_gpio_platdata_to_priv(struct udevice * dev)1844b689f02SHamish Martin static int mpc85xx_gpio_platdata_to_priv(struct udevice *dev)
1854b689f02SHamish Martin {
1864b689f02SHamish Martin struct mpc85xx_gpio_data *priv = dev_get_priv(dev);
1874b689f02SHamish Martin struct mpc85xx_gpio_plat *plat = dev_get_platdata(dev);
1884b689f02SHamish Martin unsigned long size = plat->size;
1894b689f02SHamish Martin
1904b689f02SHamish Martin if (size == 0)
1914b689f02SHamish Martin size = 0x100;
1924b689f02SHamish Martin
1934b689f02SHamish Martin priv->addr = plat->addr;
1944b689f02SHamish Martin priv->base = map_sysmem(CONFIG_SYS_IMMR + plat->addr, size);
1954b689f02SHamish Martin
1964b689f02SHamish Martin if (!priv->base)
19707d31f8fSmario.six@gdsys.cc return -ENOMEM;
19807d31f8fSmario.six@gdsys.cc
1994b689f02SHamish Martin priv->gpio_count = plat->ngpios;
2004b689f02SHamish Martin priv->dat_shadow = 0;
20107d31f8fSmario.six@gdsys.cc
20207d31f8fSmario.six@gdsys.cc return 0;
20307d31f8fSmario.six@gdsys.cc }
20407d31f8fSmario.six@gdsys.cc
mpc85xx_gpio_probe(struct udevice * dev)20507d31f8fSmario.six@gdsys.cc static int mpc85xx_gpio_probe(struct udevice *dev)
20607d31f8fSmario.six@gdsys.cc {
20707d31f8fSmario.six@gdsys.cc struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
20807d31f8fSmario.six@gdsys.cc struct mpc85xx_gpio_data *data = dev_get_priv(dev);
20907d31f8fSmario.six@gdsys.cc char name[32], *str;
21007d31f8fSmario.six@gdsys.cc
2114b689f02SHamish Martin mpc85xx_gpio_platdata_to_priv(dev);
2124b689f02SHamish Martin
21307d31f8fSmario.six@gdsys.cc snprintf(name, sizeof(name), "MPC@%lx_", data->addr);
21407d31f8fSmario.six@gdsys.cc str = strdup(name);
21507d31f8fSmario.six@gdsys.cc
21607d31f8fSmario.six@gdsys.cc if (!str)
21707d31f8fSmario.six@gdsys.cc return -ENOMEM;
21807d31f8fSmario.six@gdsys.cc
21907d31f8fSmario.six@gdsys.cc uc_priv->bank_name = str;
22007d31f8fSmario.six@gdsys.cc uc_priv->gpio_count = data->gpio_count;
22107d31f8fSmario.six@gdsys.cc
22207d31f8fSmario.six@gdsys.cc return 0;
22307d31f8fSmario.six@gdsys.cc }
22407d31f8fSmario.six@gdsys.cc
22507d31f8fSmario.six@gdsys.cc static const struct dm_gpio_ops gpio_mpc85xx_ops = {
22607d31f8fSmario.six@gdsys.cc .direction_input = mpc85xx_gpio_direction_input,
22707d31f8fSmario.six@gdsys.cc .direction_output = mpc85xx_gpio_direction_output,
22807d31f8fSmario.six@gdsys.cc .get_value = mpc85xx_gpio_get_value,
22907d31f8fSmario.six@gdsys.cc .set_value = mpc85xx_gpio_set_value,
23051781783Smario.six@gdsys.cc .get_open_drain = mpc85xx_gpio_get_open_drain,
23151781783Smario.six@gdsys.cc .set_open_drain = mpc85xx_gpio_set_open_drain,
23207d31f8fSmario.six@gdsys.cc .get_function = mpc85xx_gpio_get_function,
23307d31f8fSmario.six@gdsys.cc };
23407d31f8fSmario.six@gdsys.cc
23507d31f8fSmario.six@gdsys.cc static const struct udevice_id mpc85xx_gpio_ids[] = {
23607d31f8fSmario.six@gdsys.cc { .compatible = "fsl,pq3-gpio" },
23707d31f8fSmario.six@gdsys.cc { /* sentinel */ }
23807d31f8fSmario.six@gdsys.cc };
23907d31f8fSmario.six@gdsys.cc
24007d31f8fSmario.six@gdsys.cc U_BOOT_DRIVER(gpio_mpc85xx) = {
24107d31f8fSmario.six@gdsys.cc .name = "gpio_mpc85xx",
24207d31f8fSmario.six@gdsys.cc .id = UCLASS_GPIO,
24307d31f8fSmario.six@gdsys.cc .ops = &gpio_mpc85xx_ops,
2444b689f02SHamish Martin #if CONFIG_IS_ENABLED(OF_CONTROL)
24507d31f8fSmario.six@gdsys.cc .ofdata_to_platdata = mpc85xx_gpio_ofdata_to_platdata,
2464b689f02SHamish Martin .platdata_auto_alloc_size = sizeof(struct mpc85xx_gpio_plat),
24707d31f8fSmario.six@gdsys.cc .of_match = mpc85xx_gpio_ids,
2484b689f02SHamish Martin #endif
24907d31f8fSmario.six@gdsys.cc .probe = mpc85xx_gpio_probe,
25007d31f8fSmario.six@gdsys.cc .priv_auto_alloc_size = sizeof(struct mpc85xx_gpio_data),
25107d31f8fSmario.six@gdsys.cc };
252