1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (c) 2015 Microchip Technology Inc 4 * Purna Chandra Mandal <purna.mandal@microchip.com> 5 */ 6 7#include <common.h> 8#include <dm.h> 9#include <errno.h> 10#include <malloc.h> 11#include <asm/global_data.h> 12#include <asm/io.h> 13#include <asm/gpio.h> 14#include <linux/bitops.h> 15#include <linux/compat.h> 16#include <mach/pic32.h> 17 18DECLARE_GLOBAL_DATA_PTR; 19 20/* Peripheral Pin Control */ 21struct 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 32enum { 33 MICROCHIP_GPIO_DIR_OUT, 34 MICROCHIP_GPIO_DIR_IN, 35 MICROCHIP_GPIOS_PER_BANK = 16, 36}; 37 38struct pic32_gpio_priv { 39 struct pic32_reg_port *regs; 40 char name[2]; 41}; 42 43static 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 50static 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 64static 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 78static 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 89static 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 102static int pic32_gpio_get_function(struct udevice *dev, unsigned offset) 103{ 104 int ret = GPIOF_UNUSED; 105 106 switch (pic32_gpio_direction(dev, offset)) { 107 case MICROCHIP_GPIO_DIR_OUT: 108 ret = GPIOF_OUTPUT; 109 break; 110 case MICROCHIP_GPIO_DIR_IN: 111 ret = GPIOF_INPUT; 112 break; 113 default: 114 ret = GPIOF_UNUSED; 115 break; 116 } 117 return ret; 118} 119 120static const struct dm_gpio_ops gpio_pic32_ops = { 121 .direction_input = pic32_gpio_direction_input, 122 .direction_output = pic32_gpio_direction_output, 123 .get_value = pic32_gpio_get_value, 124 .set_value = pic32_gpio_set_value, 125 .get_function = pic32_gpio_get_function, 126}; 127 128static int pic32_gpio_probe(struct udevice *dev) 129{ 130 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 131 struct pic32_gpio_priv *priv = dev_get_priv(dev); 132 fdt_addr_t addr; 133 fdt_size_t size; 134 char *end; 135 int bank; 136 137 addr = fdtdec_get_addr_size(gd->fdt_blob, dev_of_offset(dev), "reg", 138 &size); 139 if (addr == FDT_ADDR_T_NONE) 140 return -EINVAL; 141 142 priv->regs = ioremap(addr, size); 143 144 uc_priv->gpio_count = MICROCHIP_GPIOS_PER_BANK; 145 /* extract bank name */ 146 end = strrchr(dev->name, '@'); 147 bank = trailing_strtoln(dev->name, end); 148 priv->name[0] = 'A' + bank; 149 uc_priv->bank_name = priv->name; 150 151 return 0; 152} 153 154static const struct udevice_id pic32_gpio_ids[] = { 155 { .compatible = "microchip,pic32mzda-gpio" }, 156 { } 157}; 158 159U_BOOT_DRIVER(gpio_pic32) = { 160 .name = "gpio_pic32", 161 .id = UCLASS_GPIO, 162 .of_match = pic32_gpio_ids, 163 .ops = &gpio_pic32_ops, 164 .probe = pic32_gpio_probe, 165 .priv_auto = sizeof(struct pic32_gpio_priv), 166}; 167