1// SPDX-License-Identifier: GPL-2.0+ 2/* Copyright (C) 2019 Stephan Gerhold */ 3 4#include <common.h> 5#include <dm.h> 6#include <asm/gpio.h> 7#include <asm/io.h> 8 9struct nmk_gpio_regs { 10 u32 dat; /* data */ 11 u32 dats; /* data set */ 12 u32 datc; /* data clear */ 13 u32 pdis; /* pull disable */ 14 u32 dir; /* direction */ 15 u32 dirs; /* direction set */ 16 u32 dirc; /* direction clear */ 17 u32 slpm; /* sleep mode */ 18 u32 afsla; /* alternate function select A */ 19 u32 afslb; /* alternate function select B */ 20 u32 lowemi; /* low EMI mode */ 21}; 22 23struct nmk_gpio { 24 struct nmk_gpio_regs *regs; 25}; 26 27static int nmk_gpio_get_value(struct udevice *dev, unsigned offset) 28{ 29 struct nmk_gpio *priv = dev_get_priv(dev); 30 31 return !!(readl(&priv->regs->dat) & BIT(offset)); 32} 33 34static int nmk_gpio_set_value(struct udevice *dev, unsigned offset, int value) 35{ 36 struct nmk_gpio *priv = dev_get_priv(dev); 37 38 if (value) 39 writel(BIT(offset), &priv->regs->dats); 40 else 41 writel(BIT(offset), &priv->regs->datc); 42 43 return 0; 44} 45 46static int nmk_gpio_get_function(struct udevice *dev, unsigned offset) 47{ 48 struct nmk_gpio *priv = dev_get_priv(dev); 49 50 if (readl(&priv->regs->afsla) & BIT(offset) || 51 readl(&priv->regs->afslb) & BIT(offset)) 52 return GPIOF_FUNC; 53 54 if (readl(&priv->regs->dir) & BIT(offset)) 55 return GPIOF_OUTPUT; 56 else 57 return GPIOF_INPUT; 58} 59 60static int nmk_gpio_direction_input(struct udevice *dev, unsigned offset) 61{ 62 struct nmk_gpio *priv = dev_get_priv(dev); 63 64 writel(BIT(offset), &priv->regs->dirc); 65 return 0; 66} 67 68static int nmk_gpio_direction_output(struct udevice *dev, unsigned offset, 69 int value) 70{ 71 struct nmk_gpio *priv = dev_get_priv(dev); 72 73 writel(BIT(offset), &priv->regs->dirs); 74 return nmk_gpio_set_value(dev, offset, value); 75} 76 77static const struct dm_gpio_ops nmk_gpio_ops = { 78 .get_value = nmk_gpio_get_value, 79 .set_value = nmk_gpio_set_value, 80 .get_function = nmk_gpio_get_function, 81 .direction_input = nmk_gpio_direction_input, 82 .direction_output = nmk_gpio_direction_output, 83}; 84 85static int nmk_gpio_probe(struct udevice *dev) 86{ 87 struct nmk_gpio *priv = dev_get_priv(dev); 88 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 89 char buf[20]; 90 u32 bank; 91 int ret; 92 93 priv->regs = dev_read_addr_ptr(dev); 94 if (!priv->regs) 95 return -EINVAL; 96 97 ret = dev_read_u32(dev, "gpio-bank", &bank); 98 if (ret < 0) { 99 printf("nmk_gpio(%s): Failed to read gpio-bank\n", dev->name); 100 return ret; 101 } 102 103 sprintf(buf, "nmk%u-gpio", bank); 104 uc_priv->bank_name = strdup(buf); 105 if (!uc_priv->bank_name) 106 return -ENOMEM; 107 108 uc_priv->gpio_count = sizeof(priv->regs->dat) * BITS_PER_BYTE; 109 110 return 0; 111} 112 113static const struct udevice_id nmk_gpio_ids[] = { 114 { .compatible = "st,nomadik-gpio" }, 115 { } 116}; 117 118U_BOOT_DRIVER(gpio_nmk) = { 119 .name = "nmk_gpio", 120 .id = UCLASS_GPIO, 121 .of_match = nmk_gpio_ids, 122 .probe = nmk_gpio_probe, 123 .ops = &nmk_gpio_ops, 124 .priv_auto = sizeof(struct nmk_gpio), 125}; 126