| // SPDX-License-Identifier: GPL-2.0+ |
| /* |
| * Faraday Technology's FTGPIO010 controller. |
| */ |
| |
| #include <dm.h> |
| #include <asm/io.h> |
| #include <asm/gpio.h> |
| |
| struct ftgpio010_regs { |
| u32 out; |
| u32 in; |
| u32 direction; // 1 - output |
| u32 reserved; |
| u32 set; |
| u32 clear; |
| }; |
| |
| struct ftgpio010_plat { |
| struct ftgpio010_regs __iomem *regs; |
| }; |
| |
| static int ftgpio010_direction_input(struct udevice *dev, unsigned int pin) |
| { |
| struct ftgpio010_plat *plat = dev_get_plat(dev); |
| struct ftgpio010_regs *const regs = plat->regs; |
| |
| clrbits_le32(®s->direction, 1 << pin); |
| return 0; |
| } |
| |
| static int ftgpio010_direction_output(struct udevice *dev, unsigned int pin, |
| int val) |
| { |
| struct ftgpio010_plat *plat = dev_get_plat(dev); |
| struct ftgpio010_regs *const regs = plat->regs; |
| |
| /* change the data first, then the direction. to avoid glitch */ |
| out_le32(val ? ®s->set : ®s->clear, 1 << pin); |
| setbits_le32(®s->direction, 1 << pin); |
| |
| return 0; |
| } |
| |
| static int ftgpio010_get_value(struct udevice *dev, unsigned int pin) |
| { |
| struct ftgpio010_plat *plat = dev_get_plat(dev); |
| struct ftgpio010_regs *const regs = plat->regs; |
| |
| return in_le32(®s->in) >> pin & 1; |
| } |
| |
| static int ftgpio010_set_value(struct udevice *dev, unsigned int pin, int val) |
| { |
| struct ftgpio010_plat *plat = dev_get_plat(dev); |
| struct ftgpio010_regs *const regs = plat->regs; |
| |
| out_le32(val ? ®s->set : ®s->clear, 1 << pin); |
| return 0; |
| } |
| |
| static int ftgpio010_get_function(struct udevice *dev, unsigned int pin) |
| { |
| struct ftgpio010_plat *plat = dev_get_plat(dev); |
| struct ftgpio010_regs *const regs = plat->regs; |
| |
| if (in_le32(®s->direction) >> pin & 1) |
| return GPIOF_OUTPUT; |
| return GPIOF_INPUT; |
| } |
| |
| static int ftgpio010_probe(struct udevice *dev) |
| { |
| struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); |
| |
| uc_priv->gpio_count = ofnode_read_u32_default(dev_ofnode(dev), |
| "nr-gpios", 32); |
| return 0; |
| } |
| |
| static int ftgpio010_of_to_plat(struct udevice *dev) |
| { |
| struct ftgpio010_plat *plat = dev_get_plat(dev); |
| |
| plat->regs = dev_read_addr_ptr(dev); |
| return 0; |
| } |
| |
| static const struct dm_gpio_ops ftgpio010_ops = { |
| .direction_input = ftgpio010_direction_input, |
| .direction_output = ftgpio010_direction_output, |
| .get_value = ftgpio010_get_value, |
| .set_value = ftgpio010_set_value, |
| .get_function = ftgpio010_get_function, |
| }; |
| |
| static const struct udevice_id ftgpio010_ids[] = { |
| { .compatible = "faraday,ftgpio010" }, |
| { } |
| }; |
| |
| U_BOOT_DRIVER(ftgpio010) = { |
| .name = "ftgpio010", |
| .id = UCLASS_GPIO, |
| .of_match = ftgpio010_ids, |
| .ops = &ftgpio010_ops, |
| .of_to_plat = ftgpio010_of_to_plat, |
| .plat_auto = sizeof(struct ftgpio010_plat), |
| .probe = ftgpio010_probe, |
| }; |