blob: 83a2c465d011d42a13b4633230efd82eecc34649 [file] [log] [blame]
Andrea Scian4bbf3ca2015-03-20 16:00:25 +01001/*
2 * Xilinx Zynq GPIO device driver
3 *
4 * Copyright (C) 2015 DAVE Embedded Systems <devel@dave.eu>
5 *
6 * Most of code taken from linux kernel driver (linux/drivers/gpio/gpio-zynq.c)
7 * Copyright (C) 2009 - 2014 Xilinx, Inc.
8 *
9 * SPDX-License-Identifier: GPL-2.0+
10 */
11
12#include <common.h>
13#include <asm/gpio.h>
14#include <asm/io.h>
15#include <asm/errno.h>
16
17/**
18 * zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank
19 * for a given pin in the GPIO device
20 * @pin_num: gpio pin number within the device
21 * @bank_num: an output parameter used to return the bank number of the gpio
22 * pin
23 * @bank_pin_num: an output parameter used to return pin number within a bank
24 * for the given gpio pin
25 *
26 * Returns the bank number and pin offset within the bank.
27 */
28static inline void zynq_gpio_get_bank_pin(unsigned int pin_num,
29 unsigned int *bank_num,
30 unsigned int *bank_pin_num)
31{
32 switch (pin_num) {
33 case ZYNQ_GPIO_BANK0_PIN_MIN ... ZYNQ_GPIO_BANK0_PIN_MAX:
34 *bank_num = 0;
35 *bank_pin_num = pin_num;
36 break;
37 case ZYNQ_GPIO_BANK1_PIN_MIN ... ZYNQ_GPIO_BANK1_PIN_MAX:
38 *bank_num = 1;
39 *bank_pin_num = pin_num - ZYNQ_GPIO_BANK1_PIN_MIN;
40 break;
41 case ZYNQ_GPIO_BANK2_PIN_MIN ... ZYNQ_GPIO_BANK2_PIN_MAX:
42 *bank_num = 2;
43 *bank_pin_num = pin_num - ZYNQ_GPIO_BANK2_PIN_MIN;
44 break;
45 case ZYNQ_GPIO_BANK3_PIN_MIN ... ZYNQ_GPIO_BANK3_PIN_MAX:
46 *bank_num = 3;
47 *bank_pin_num = pin_num - ZYNQ_GPIO_BANK3_PIN_MIN;
48 break;
49 default:
50 printf("invalid GPIO pin number: %u\n", pin_num);
51 *bank_num = 0;
52 *bank_pin_num = 0;
53 break;
54 }
55}
56
57int gpio_is_valid(unsigned gpio)
58{
59 return (gpio >= 0) && (gpio < ZYNQ_GPIO_NR_GPIOS);
60}
61
62static int check_gpio(unsigned gpio)
63{
64 if (!gpio_is_valid(gpio)) {
65 printf("ERROR : check_gpio: invalid GPIO %d\n", gpio);
66 return -1;
67 }
68 return 0;
69}
70
71/**
72 * gpio_get_value - Get the state of the specified pin of GPIO device
73 * @gpio: gpio pin number within the device
74 *
75 * This function reads the state of the specified pin of the GPIO device.
76 *
77 * Return: 0 if the pin is low, 1 if pin is high.
78 */
79int gpio_get_value(unsigned gpio)
80{
81 u32 data;
82 unsigned int bank_num, bank_pin_num;
83
84 if (check_gpio(gpio) < 0)
85 return -1;
86
87 zynq_gpio_get_bank_pin(gpio, &bank_num, &bank_pin_num);
88
89 data = readl(ZYNQ_GPIO_BASE_ADDRESS +
90 ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
91
92 return (data >> bank_pin_num) & 1;
93}
94
95/**
96 * gpio_set_value - Modify the value of the pin with specified value
97 * @gpio: gpio pin number within the device
98 * @value: value used to modify the value of the specified pin
99 *
100 * This function calculates the register offset (i.e to lower 16 bits or
101 * upper 16 bits) based on the given pin number and sets the value of a
102 * gpio pin to the specified value. The value is either 0 or non-zero.
103 */
104int gpio_set_value(unsigned gpio, int value)
105{
106 unsigned int reg_offset, bank_num, bank_pin_num;
107
108 if (check_gpio(gpio) < 0)
109 return -1;
110
111 zynq_gpio_get_bank_pin(gpio, &bank_num, &bank_pin_num);
112
113 if (bank_pin_num >= ZYNQ_GPIO_MID_PIN_NUM) {
114 /* only 16 data bits in bit maskable reg */
115 bank_pin_num -= ZYNQ_GPIO_MID_PIN_NUM;
116 reg_offset = ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num);
117 } else {
118 reg_offset = ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num);
119 }
120
121 /*
122 * get the 32 bit value to be written to the mask/data register where
123 * the upper 16 bits is the mask and lower 16 bits is the data
124 */
125 value = !!value;
126 value = ~(1 << (bank_pin_num + ZYNQ_GPIO_MID_PIN_NUM)) &
127 ((value << bank_pin_num) | ZYNQ_GPIO_UPPER_MASK);
128
129 writel(value, ZYNQ_GPIO_BASE_ADDRESS + reg_offset);
130
131 return 0;
132}
133
134/**
135 * gpio_direction_input - Set the direction of the specified GPIO pin as input
136 * @gpio: gpio pin number within the device
137 *
138 * This function uses the read-modify-write sequence to set the direction of
139 * the gpio pin as input.
140 *
141 * Return: -1 if invalid gpio specified, 0 if successul
142 */
143int gpio_direction_input(unsigned gpio)
144{
145 u32 reg;
146 unsigned int bank_num, bank_pin_num;
147
148 if (check_gpio(gpio) < 0)
149 return -1;
150
151 zynq_gpio_get_bank_pin(gpio, &bank_num, &bank_pin_num);
152
153 /* bank 0 pins 7 and 8 are special and cannot be used as inputs */
154 if (bank_num == 0 && (bank_pin_num == 7 || bank_pin_num == 8))
155 return -1;
156
157 /* clear the bit in direction mode reg to set the pin as input */
158 reg = readl(ZYNQ_GPIO_BASE_ADDRESS + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
159 reg &= ~BIT(bank_pin_num);
160 writel(reg, ZYNQ_GPIO_BASE_ADDRESS + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
161
162 return 0;
163}
164
165/**
166 * gpio_direction_output - Set the direction of the specified GPIO pin as output
167 * @gpio: gpio pin number within the device
168 * @value: value to be written to specified pin
169 *
170 * This function sets the direction of specified GPIO pin as output, configures
171 * the Output Enable register for the pin and uses zynq_gpio_set to set
172 * the value of the pin to the value specified.
173 *
174 * Return: 0 always
175 */
176int gpio_direction_output(unsigned gpio, int value)
177{
178 u32 reg;
179 unsigned int bank_num, bank_pin_num;
180
181 if (check_gpio(gpio) < 0)
182 return -1;
183
184 zynq_gpio_get_bank_pin(gpio, &bank_num, &bank_pin_num);
185
186 /* set the GPIO pin as output */
187 reg = readl(ZYNQ_GPIO_BASE_ADDRESS + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
188 reg |= BIT(bank_pin_num);
189 writel(reg, ZYNQ_GPIO_BASE_ADDRESS + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
190
191 /* configure the output enable reg for the pin */
192 reg = readl(ZYNQ_GPIO_BASE_ADDRESS + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
193 reg |= BIT(bank_pin_num);
194 writel(reg, ZYNQ_GPIO_BASE_ADDRESS + ZYNQ_GPIO_OUTEN_OFFSET(bank_num));
195
196 /* set the state of the pin */
197 gpio_set_value(gpio, value);
198 return 0;
199}
200
201/**
202 * Request a gpio before using it.
203 *
204 * NOTE: Argument 'label' is unused.
205 */
206int gpio_request(unsigned gpio, const char *label)
207{
208 if (check_gpio(gpio) < 0)
209 return -1;
210
211 return 0;
212}
213
214/**
215 * Reset and free the gpio after using it.
216 */
217int gpio_free(unsigned gpio)
218{
219 return 0;
220}