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