1 /* 2 * Copyright (c) 2015 Microchip Technology Inc 3 * Purna Chandra Mandal <purna.mandal@microchip.com> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <dm.h> 10 #include <errno.h> 11 #include <malloc.h> 12 #include <asm/io.h> 13 #include <asm/gpio.h> 14 #include <linux/compat.h> 15 #include <dt-bindings/gpio/gpio.h> 16 #include <mach/pic32.h> 17 18 DECLARE_GLOBAL_DATA_PTR; 19 20 /* Peripheral Pin Control */ 21 struct pic32_reg_port { 22 struct pic32_reg_atomic ansel; 23 struct pic32_reg_atomic tris; 24 struct pic32_reg_atomic port; 25 struct pic32_reg_atomic lat; 26 struct pic32_reg_atomic open_drain; 27 struct pic32_reg_atomic cnpu; 28 struct pic32_reg_atomic cnpd; 29 struct pic32_reg_atomic cncon; 30 }; 31 32 enum { 33 MICROCHIP_GPIO_DIR_OUT, 34 MICROCHIP_GPIO_DIR_IN, 35 MICROCHIP_GPIOS_PER_BANK = 16, 36 }; 37 38 struct pic32_gpio_priv { 39 struct pic32_reg_port *regs; 40 char name[2]; 41 }; 42 43 static int pic32_gpio_get_value(struct udevice *dev, unsigned offset) 44 { 45 struct pic32_gpio_priv *priv = dev_get_priv(dev); 46 47 return !!(readl(&priv->regs->port.raw) & BIT(offset)); 48 } 49 50 static int pic32_gpio_set_value(struct udevice *dev, unsigned offset, 51 int value) 52 { 53 struct pic32_gpio_priv *priv = dev_get_priv(dev); 54 int mask = BIT(offset); 55 56 if (value) 57 writel(mask, &priv->regs->port.set); 58 else 59 writel(mask, &priv->regs->port.clr); 60 61 return 0; 62 } 63 64 static int pic32_gpio_direction(struct udevice *dev, unsigned offset) 65 { 66 struct pic32_gpio_priv *priv = dev_get_priv(dev); 67 68 /* pin in analog mode ? */ 69 if (readl(&priv->regs->ansel.raw) & BIT(offset)) 70 return -EPERM; 71 72 if (readl(&priv->regs->tris.raw) & BIT(offset)) 73 return MICROCHIP_GPIO_DIR_IN; 74 else 75 return MICROCHIP_GPIO_DIR_OUT; 76 } 77 78 static int pic32_gpio_direction_input(struct udevice *dev, unsigned offset) 79 { 80 struct pic32_gpio_priv *priv = dev_get_priv(dev); 81 int mask = BIT(offset); 82 83 writel(mask, &priv->regs->ansel.clr); 84 writel(mask, &priv->regs->tris.set); 85 86 return 0; 87 } 88 89 static int pic32_gpio_direction_output(struct udevice *dev, 90 unsigned offset, int value) 91 { 92 struct pic32_gpio_priv *priv = dev_get_priv(dev); 93 int mask = BIT(offset); 94 95 writel(mask, &priv->regs->ansel.clr); 96 writel(mask, &priv->regs->tris.clr); 97 98 pic32_gpio_set_value(dev, offset, value); 99 return 0; 100 } 101 102 static int pic32_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, 103 struct fdtdec_phandle_args *args) 104 { 105 desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0; 106 107 return 0; 108 } 109 110 static int pic32_gpio_get_function(struct udevice *dev, unsigned offset) 111 { 112 int ret = GPIOF_UNUSED; 113 114 switch (pic32_gpio_direction(dev, offset)) { 115 case MICROCHIP_GPIO_DIR_OUT: 116 ret = GPIOF_OUTPUT; 117 break; 118 case MICROCHIP_GPIO_DIR_IN: 119 ret = GPIOF_INPUT; 120 break; 121 default: 122 ret = GPIOF_UNUSED; 123 break; 124 } 125 return ret; 126 } 127 128 static const struct dm_gpio_ops gpio_pic32_ops = { 129 .direction_input = pic32_gpio_direction_input, 130 .direction_output = pic32_gpio_direction_output, 131 .get_value = pic32_gpio_get_value, 132 .set_value = pic32_gpio_set_value, 133 .get_function = pic32_gpio_get_function, 134 .xlate = pic32_gpio_xlate, 135 }; 136 137 static int pic32_gpio_probe(struct udevice *dev) 138 { 139 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 140 struct pic32_gpio_priv *priv = dev_get_priv(dev); 141 fdt_addr_t addr; 142 fdt_size_t size; 143 char *end; 144 int bank; 145 146 addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", &size); 147 if (addr == FDT_ADDR_T_NONE) 148 return -EINVAL; 149 150 priv->regs = ioremap(addr, size); 151 152 uc_priv->gpio_count = MICROCHIP_GPIOS_PER_BANK; 153 /* extract bank name */ 154 end = strrchr(dev->name, '@'); 155 bank = trailing_strtoln(dev->name, end); 156 priv->name[0] = 'A' + bank; 157 uc_priv->bank_name = priv->name; 158 159 return 0; 160 } 161 162 static const struct udevice_id pic32_gpio_ids[] = { 163 { .compatible = "microchip,pic32mzda-gpio" }, 164 { } 165 }; 166 167 U_BOOT_DRIVER(gpio_pic32) = { 168 .name = "gpio_pic32", 169 .id = UCLASS_GPIO, 170 .of_match = pic32_gpio_ids, 171 .ops = &gpio_pic32_ops, 172 .probe = pic32_gpio_probe, 173 .priv_auto_alloc_size = sizeof(struct pic32_gpio_priv), 174 }; 175