103d67e12SJoachim Foerster /*
288d5ecf4SThomas Chou * Copyright (C) 2015 Thomas Chou <thomas@wytron.com.tw>
303d67e12SJoachim Foerster * Copyright (C) 2011 Missing Link Electronics
403d67e12SJoachim Foerster * Joachim Foerster <joachim@missinglinkelectronics.com>
503d67e12SJoachim Foerster *
61a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+
703d67e12SJoachim Foerster */
803d67e12SJoachim Foerster #include <common.h>
988d5ecf4SThomas Chou #include <dm.h>
1088d5ecf4SThomas Chou #include <errno.h>
1188d5ecf4SThomas Chou #include <malloc.h>
1288d5ecf4SThomas Chou #include <fdtdec.h>
1303d67e12SJoachim Foerster #include <asm/io.h>
1403d67e12SJoachim Foerster #include <asm/gpio.h>
1503d67e12SJoachim Foerster
1688d5ecf4SThomas Chou DECLARE_GLOBAL_DATA_PTR;
1703d67e12SJoachim Foerster
1888d5ecf4SThomas Chou struct altera_pio_regs {
1988d5ecf4SThomas Chou u32 data; /* Data register */
2088d5ecf4SThomas Chou u32 direction; /* Direction register */
2188d5ecf4SThomas Chou };
2203d67e12SJoachim Foerster
2388d5ecf4SThomas Chou struct altera_pio_platdata {
2488d5ecf4SThomas Chou struct altera_pio_regs *regs;
2588d5ecf4SThomas Chou int gpio_count;
2688d5ecf4SThomas Chou const char *bank_name;
2788d5ecf4SThomas Chou };
2803d67e12SJoachim Foerster
altera_pio_direction_input(struct udevice * dev,unsigned pin)2988d5ecf4SThomas Chou static int altera_pio_direction_input(struct udevice *dev, unsigned pin)
3003d67e12SJoachim Foerster {
3188d5ecf4SThomas Chou struct altera_pio_platdata *plat = dev_get_platdata(dev);
3288d5ecf4SThomas Chou struct altera_pio_regs *const regs = plat->regs;
3303d67e12SJoachim Foerster
3488d5ecf4SThomas Chou clrbits_le32(®s->direction, 1 << pin);
3503d67e12SJoachim Foerster
3603d67e12SJoachim Foerster return 0;
3703d67e12SJoachim Foerster }
3803d67e12SJoachim Foerster
altera_pio_direction_output(struct udevice * dev,unsigned pin,int val)3988d5ecf4SThomas Chou static int altera_pio_direction_output(struct udevice *dev, unsigned pin,
4088d5ecf4SThomas Chou int val)
4103d67e12SJoachim Foerster {
4288d5ecf4SThomas Chou struct altera_pio_platdata *plat = dev_get_platdata(dev);
4388d5ecf4SThomas Chou struct altera_pio_regs *const regs = plat->regs;
4403d67e12SJoachim Foerster
4588d5ecf4SThomas Chou if (val)
4688d5ecf4SThomas Chou setbits_le32(®s->data, 1 << pin);
4703d67e12SJoachim Foerster else
4888d5ecf4SThomas Chou clrbits_le32(®s->data, 1 << pin);
4988d5ecf4SThomas Chou /* change the data first, then the direction. to avoid glitch */
5088d5ecf4SThomas Chou setbits_le32(®s->direction, 1 << pin);
5188d5ecf4SThomas Chou
5203d67e12SJoachim Foerster return 0;
5303d67e12SJoachim Foerster }
5403d67e12SJoachim Foerster
altera_pio_get_value(struct udevice * dev,unsigned pin)5588d5ecf4SThomas Chou static int altera_pio_get_value(struct udevice *dev, unsigned pin)
5603d67e12SJoachim Foerster {
5788d5ecf4SThomas Chou struct altera_pio_platdata *plat = dev_get_platdata(dev);
5888d5ecf4SThomas Chou struct altera_pio_regs *const regs = plat->regs;
5903d67e12SJoachim Foerster
6088d5ecf4SThomas Chou return readl(®s->data) & (1 << pin);
6103d67e12SJoachim Foerster }
6203d67e12SJoachim Foerster
6388d5ecf4SThomas Chou
altera_pio_set_value(struct udevice * dev,unsigned pin,int val)6488d5ecf4SThomas Chou static int altera_pio_set_value(struct udevice *dev, unsigned pin, int val)
6503d67e12SJoachim Foerster {
6688d5ecf4SThomas Chou struct altera_pio_platdata *plat = dev_get_platdata(dev);
6788d5ecf4SThomas Chou struct altera_pio_regs *const regs = plat->regs;
6803d67e12SJoachim Foerster
6988d5ecf4SThomas Chou if (val)
7088d5ecf4SThomas Chou setbits_le32(®s->data, 1 << pin);
7103d67e12SJoachim Foerster else
7288d5ecf4SThomas Chou clrbits_le32(®s->data, 1 << pin);
7303d67e12SJoachim Foerster
7403d67e12SJoachim Foerster return 0;
7503d67e12SJoachim Foerster }
7688d5ecf4SThomas Chou
altera_pio_probe(struct udevice * dev)7788d5ecf4SThomas Chou static int altera_pio_probe(struct udevice *dev)
7888d5ecf4SThomas Chou {
7988d5ecf4SThomas Chou struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
8088d5ecf4SThomas Chou struct altera_pio_platdata *plat = dev_get_platdata(dev);
8188d5ecf4SThomas Chou
8288d5ecf4SThomas Chou uc_priv->gpio_count = plat->gpio_count;
8388d5ecf4SThomas Chou uc_priv->bank_name = plat->bank_name;
8488d5ecf4SThomas Chou
8588d5ecf4SThomas Chou return 0;
8688d5ecf4SThomas Chou }
8788d5ecf4SThomas Chou
altera_pio_ofdata_to_platdata(struct udevice * dev)8888d5ecf4SThomas Chou static int altera_pio_ofdata_to_platdata(struct udevice *dev)
8988d5ecf4SThomas Chou {
9088d5ecf4SThomas Chou struct altera_pio_platdata *plat = dev_get_platdata(dev);
9188d5ecf4SThomas Chou
92*a821c4afSSimon Glass plat->regs = map_physmem(devfdt_get_addr(dev),
93079bfc5dSThomas Chou sizeof(struct altera_pio_regs),
94079bfc5dSThomas Chou MAP_NOCACHE);
95e160f7d4SSimon Glass plat->gpio_count = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
9688d5ecf4SThomas Chou "altr,gpio-bank-width", 32);
97e160f7d4SSimon Glass plat->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
9888d5ecf4SThomas Chou "gpio-bank-name", NULL);
9988d5ecf4SThomas Chou
10088d5ecf4SThomas Chou return 0;
10188d5ecf4SThomas Chou }
10288d5ecf4SThomas Chou
10388d5ecf4SThomas Chou static const struct dm_gpio_ops altera_pio_ops = {
10488d5ecf4SThomas Chou .direction_input = altera_pio_direction_input,
10588d5ecf4SThomas Chou .direction_output = altera_pio_direction_output,
10688d5ecf4SThomas Chou .get_value = altera_pio_get_value,
10788d5ecf4SThomas Chou .set_value = altera_pio_set_value,
10888d5ecf4SThomas Chou };
10988d5ecf4SThomas Chou
11088d5ecf4SThomas Chou static const struct udevice_id altera_pio_ids[] = {
11188d5ecf4SThomas Chou { .compatible = "altr,pio-1.0" },
11288d5ecf4SThomas Chou { }
11388d5ecf4SThomas Chou };
11488d5ecf4SThomas Chou
11588d5ecf4SThomas Chou U_BOOT_DRIVER(altera_pio) = {
11688d5ecf4SThomas Chou .name = "altera_pio",
11788d5ecf4SThomas Chou .id = UCLASS_GPIO,
11888d5ecf4SThomas Chou .of_match = altera_pio_ids,
11988d5ecf4SThomas Chou .ops = &altera_pio_ops,
12088d5ecf4SThomas Chou .ofdata_to_platdata = altera_pio_ofdata_to_platdata,
12188d5ecf4SThomas Chou .platdata_auto_alloc_size = sizeof(struct altera_pio_platdata),
12288d5ecf4SThomas Chou .probe = altera_pio_probe,
12388d5ecf4SThomas Chou };
124