1/* 2 * @TAG(OTHER_GPL) 3 */ 4 5/* 6 * Copyright (C) 2009 7 * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de> 8 * 9 * Copyright (C) 2011 10 * Stefano Babic, DENX Software Engineering, <sbabic@denx.de> 11 * 12 * See file CREDITS for list of people who contributed to this 13 * project. 14 * 15 * This program is free software; you can redistribute it and/or 16 * modify it under the terms of the GNU General Public License as 17 * published by the Free Software Foundation; either version 2 of 18 * the License, or (at your option) any later version. 19 * 20 * This program is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * GNU General Public License for more details. 24 * 25 * You should have received a copy of the GNU General Public License 26 * along with this program; if not, write to the Free Software 27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 28 * MA 02111-1307 USA 29 */ 30#include "common.h" 31#include "imx-regs.h" 32#include "gpio.h" 33#include "../io.h" 34#include "../unimplemented.h" 35 36enum mxc_gpio_direction { 37 MXC_GPIO_DIRECTION_IN, 38 MXC_GPIO_DIRECTION_OUT, 39}; 40 41#define GPIO_TO_PORT(n) (n / 32) 42 43#define GPIO_SIZE 0x4000 44 45/* GPIO port description */ 46 47#ifdef CONFIG_PLAT_IMX6 48static unsigned long gpio_ports[] = { 49 [0] = 0, 50 [1] = 0, 51 [2] = 0, 52 [3] = 0, 53 [4] = 0, 54 [5] = 0, 55 [6] = 0, 56}; 57 58static unsigned long gpio_paddr[] = { 59 [0] = GPIO1_BASE_ADDR, 60 [1] = GPIO2_BASE_ADDR, 61 [2] = GPIO3_BASE_ADDR, /* Used by ethernet */ 62 [3] = GPIO4_BASE_ADDR, 63 [4] = GPIO5_BASE_ADDR, 64 [5] = GPIO6_BASE_ADDR, 65 [6] = GPIO7_BASE_ADDR, 66}; 67#endif 68#ifdef CONFIG_PLAT_IMX8MQ_EVK 69static unsigned long gpio_ports[] = { 70 [0] = 0, 71 [1] = 0, 72 [2] = 0, 73 [3] = 0, 74 [4] = 0, 75}; 76 77static unsigned long gpio_paddr[] = { 78 [0] = 0x30200000, 79 [1] = 0x30210000, 80 [2] = 0x30220000, 81 [3] = 0x30230000, 82 [4] = 0x30240000, 83}; 84#endif 85 86static int mxc_gpio_direction(unsigned int gpio, 87 enum mxc_gpio_direction direction, ps_io_ops_t *io_ops) 88{ 89 unsigned int port = GPIO_TO_PORT(gpio); 90 struct gpio_regs *regs; 91 uint32_t l; 92 93 if (port >= ARRAY_SIZE(gpio_ports)) { 94 return -1; 95 } 96 97 gpio &= 0x1f; 98 99 if (gpio_ports[port] == 0) { 100 uintptr_t gpio_phys = (uintptr_t)gpio_paddr[port]; 101 gpio_ports[port] = (unsigned long)ps_io_map(&io_ops->io_mapper, gpio_phys, GPIO_SIZE, 0, PS_MEM_NORMAL); 102 if (gpio_ports[port] == 0) { 103 LOG_ERROR("Warning: No map for GPIO %d. Assuming that it is already configured\n", port); 104 return 0; 105 } 106 } 107 108 regs = (struct gpio_regs *)gpio_ports[port]; 109 l = readl(®s->gpio_dir); 110 111 switch (direction) { 112 case MXC_GPIO_DIRECTION_OUT: 113 l |= 1 << gpio; 114 break; 115 case MXC_GPIO_DIRECTION_IN: 116 l &= ~(BIT(gpio)); 117 } 118 writel(l, ®s->gpio_dir); 119 120 return 0; 121} 122 123int gpio_set_value(unsigned gpio, int value) 124{ 125 unsigned int port = GPIO_TO_PORT(gpio); 126 struct gpio_regs *regs; 127 uint32_t l; 128 129 if (port >= ARRAY_SIZE(gpio_ports)) { 130 return -1; 131 } 132 133 gpio &= 0x1f; 134 135 regs = (struct gpio_regs *)gpio_ports[port]; 136 137 l = readl(®s->gpio_dr); 138 if (value) { 139 l |= 1 << gpio; 140 } else { 141 l &= ~(BIT(gpio)); 142 } 143 writel(l, ®s->gpio_dr); 144 145 return 0; 146} 147 148int gpio_get_value(unsigned gpio) 149{ 150 unsigned int port = GPIO_TO_PORT(gpio); 151 struct gpio_regs *regs; 152 uint32_t val; 153 154 if (port >= ARRAY_SIZE(gpio_ports)) { 155 return -1; 156 } 157 158 gpio &= 0x1f; 159 160 regs = (struct gpio_regs *)gpio_ports[port]; 161 162 val = (readl(®s->gpio_psr) >> gpio) & 0x01; 163 164 return val; 165} 166 167int gpio_request(unsigned gpio, const char *label) 168{ 169 unsigned int port = GPIO_TO_PORT(gpio); 170 if (port >= ARRAY_SIZE(gpio_ports)) { 171 return -1; 172 } 173 return 0; 174} 175 176int gpio_free(unsigned gpio) 177{ 178 return 0; 179} 180 181int gpio_direction_input(unsigned gpio, ps_io_ops_t *io_ops) 182{ 183 return mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_IN, io_ops); 184} 185 186int gpio_direction_output(unsigned gpio, int value, ps_io_ops_t *io_ops) 187{ 188 int ret = mxc_gpio_direction(gpio, MXC_GPIO_DIRECTION_OUT, io_ops); 189 190 if (ret < 0) { 191 return ret; 192 } 193 194 return gpio_set_value(gpio, value); 195} 196