| /* |
| * |
| * Macros for external SMP-safe access to the PMC MSP71xx reference |
| * board GPIO pins |
| * |
| * Copyright 2010 PMC-Sierra, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by the |
| * Free Software Foundation; either version 2 of the License, or (at your |
| * option) any later version. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN |
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 675 Mass Ave, Cambridge, MA 02139, USA. |
| */ |
| |
| #ifndef __MSP_GPIO_MACROS_H__ |
| #define __MSP_GPIO_MACROS_H__ |
| |
| #include <msp_regops.h> |
| #include <msp_regs.h> |
| |
| #ifdef CONFIG_PMC_MSP7120_GW |
| #define MSP_NUM_GPIOS 20 |
| #else |
| #define MSP_NUM_GPIOS 28 |
| #endif |
| |
| /* -- GPIO Enumerations -- */ |
| enum msp_gpio_data { |
| MSP_GPIO_LO = 0, |
| MSP_GPIO_HI = 1, |
| MSP_GPIO_NONE, /* Special - Means pin is out of range */ |
| MSP_GPIO_TOGGLE, /* Special - Sets pin to opposite */ |
| }; |
| |
| enum msp_gpio_mode { |
| MSP_GPIO_INPUT = 0x0, |
| /* MSP_GPIO_ INTERRUPT = 0x1, Not supported yet */ |
| MSP_GPIO_UART_INPUT = 0x2, /* Only GPIO 4 or 5 */ |
| MSP_GPIO_OUTPUT = 0x8, |
| MSP_GPIO_UART_OUTPUT = 0x9, /* Only GPIO 2 or 3 */ |
| MSP_GPIO_PERIF_TIMERA = 0x9, /* Only GPIO 0 or 1 */ |
| MSP_GPIO_PERIF_TIMERB = 0xa, /* Only GPIO 0 or 1 */ |
| MSP_GPIO_UNKNOWN = 0xb, /* No such GPIO or mode */ |
| }; |
| |
| /* -- Static Tables -- */ |
| |
| /* Maps pins to data register */ |
| static volatile u32 * const MSP_GPIO_DATA_REGISTER[] = { |
| /* GPIO 0 and 1 on the first register */ |
| GPIO_DATA1_REG, GPIO_DATA1_REG, |
| /* GPIO 2, 3, 4, and 5 on the second register */ |
| GPIO_DATA2_REG, GPIO_DATA2_REG, GPIO_DATA2_REG, GPIO_DATA2_REG, |
| /* GPIO 6, 7, 8, and 9 on the third register */ |
| GPIO_DATA3_REG, GPIO_DATA3_REG, GPIO_DATA3_REG, GPIO_DATA3_REG, |
| /* GPIO 10, 11, 12, 13, 14, and 15 on the fourth register */ |
| GPIO_DATA4_REG, GPIO_DATA4_REG, GPIO_DATA4_REG, GPIO_DATA4_REG, |
| GPIO_DATA4_REG, GPIO_DATA4_REG, |
| /* GPIO 16 - 23 on the first strange EXTENDED register */ |
| EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, |
| EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, |
| EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, |
| /* GPIO 24 - 27 on the second strange EXTENDED register */ |
| EXTENDED_GPIO2_REG, EXTENDED_GPIO2_REG, EXTENDED_GPIO2_REG, |
| EXTENDED_GPIO2_REG, |
| }; |
| |
| /* Maps pins to mode register */ |
| static volatile u32 * const MSP_GPIO_MODE_REGISTER[] = { |
| /* GPIO 0 and 1 on the first register */ |
| GPIO_CFG1_REG, GPIO_CFG1_REG, |
| /* GPIO 2, 3, 4, and 5 on the second register */ |
| GPIO_CFG2_REG, GPIO_CFG2_REG, GPIO_CFG2_REG, GPIO_CFG2_REG, |
| /* GPIO 6, 7, 8, and 9 on the third register */ |
| GPIO_CFG3_REG, GPIO_CFG3_REG, GPIO_CFG3_REG, GPIO_CFG3_REG, |
| /* GPIO 10, 11, 12, 13, 14, and 15 on the fourth register */ |
| GPIO_CFG4_REG, GPIO_CFG4_REG, GPIO_CFG4_REG, GPIO_CFG4_REG, |
| GPIO_CFG4_REG, GPIO_CFG4_REG, |
| /* GPIO 16 - 23 on the first strange EXTENDED register */ |
| EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, |
| EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, |
| EXTENDED_GPIO1_REG, EXTENDED_GPIO1_REG, |
| /* GPIO 24 - 27 on the second strange EXTENDED register */ |
| EXTENDED_GPIO2_REG, EXTENDED_GPIO2_REG, EXTENDED_GPIO2_REG, |
| EXTENDED_GPIO2_REG, |
| }; |
| |
| /* Maps 'basic' pins to relative offset from 0 per register */ |
| static int MSP_GPIO_OFFSET[] = { |
| /* GPIO 0 and 1 on the first register */ |
| 0, 0, |
| /* GPIO 2, 3, 4, and 5 on the second register */ |
| 2, 2, 2, 2, |
| /* GPIO 6, 7, 8, and 9 on the third register */ |
| 6, 6, 6, 6, |
| /* GPIO 10, 11, 12, 13, 14, and 15 on the fourth register */ |
| 10, 10, 10, 10, 10, 10, |
| }; |
| |
| /* Maps MODE to allowed pin mask */ |
| static unsigned int MSP_GPIO_MODE_ALLOWED[] = { |
| 0xffffffff, /* Mode 0 - INPUT */ |
| 0x00000, /* Mode 1 - INTERRUPT */ |
| 0x00030, /* Mode 2 - UART_INPUT (GPIO 4, 5)*/ |
| 0, 0, 0, 0, 0, /* Modes 3, 4, 5, 6, and 7 are reserved */ |
| 0xffffffff, /* Mode 8 - OUTPUT */ |
| 0x0000f, /* Mode 9 - UART_OUTPUT/ |
| PERF_TIMERA (GPIO 0, 1, 2, 3) */ |
| 0x00003, /* Mode a - PERF_TIMERB (GPIO 0, 1) */ |
| 0x00000, /* Mode b - Not really a mode! */ |
| }; |
| |
| /* -- Bit masks -- */ |
| |
| /* This gives you the 'register relative offset gpio' number */ |
| #define OFFSET_GPIO_NUMBER(gpio) (gpio - MSP_GPIO_OFFSET[gpio]) |
| |
| /* These take the 'register relative offset gpio' number */ |
| #define BASIC_DATA_REG_MASK(ogpio) (1 << ogpio) |
| #define BASIC_MODE_REG_VALUE(mode, ogpio) \ |
| (mode << BASIC_MODE_REG_SHIFT(ogpio)) |
| #define BASIC_MODE_REG_MASK(ogpio) \ |
| BASIC_MODE_REG_VALUE(0xf, ogpio) |
| #define BASIC_MODE_REG_SHIFT(ogpio) (ogpio * 4) |
| #define BASIC_MODE_REG_FROM_REG(data, ogpio) \ |
| ((data & BASIC_MODE_REG_MASK(ogpio)) >> BASIC_MODE_REG_SHIFT(ogpio)) |
| |
| /* These take the actual GPIO number (0 through 15) */ |
| #define BASIC_DATA_MASK(gpio) \ |
| BASIC_DATA_REG_MASK(OFFSET_GPIO_NUMBER(gpio)) |
| #define BASIC_MODE_MASK(gpio) \ |
| BASIC_MODE_REG_MASK(OFFSET_GPIO_NUMBER(gpio)) |
| #define BASIC_MODE(mode, gpio) \ |
| BASIC_MODE_REG_VALUE(mode, OFFSET_GPIO_NUMBER(gpio)) |
| #define BASIC_MODE_SHIFT(gpio) \ |
| BASIC_MODE_REG_SHIFT(OFFSET_GPIO_NUMBER(gpio)) |
| #define BASIC_MODE_FROM_REG(data, gpio) \ |
| BASIC_MODE_REG_FROM_REG(data, OFFSET_GPIO_NUMBER(gpio)) |
| |
| /* |
| * Each extended GPIO register is 32 bits long and is responsible for up to |
| * eight GPIOs. The least significant 16 bits contain the set and clear bit |
| * pair for each of the GPIOs. The most significant 16 bits contain the |
| * disable and enable bit pair for each of the GPIOs. For example, the |
| * extended GPIO reg for GPIOs 16-23 is as follows: |
| * |
| * 31: GPIO23_DISABLE |
| * ... |
| * 19: GPIO17_DISABLE |
| * 18: GPIO17_ENABLE |
| * 17: GPIO16_DISABLE |
| * 16: GPIO16_ENABLE |
| * ... |
| * 3: GPIO17_SET |
| * 2: GPIO17_CLEAR |
| * 1: GPIO16_SET |
| * 0: GPIO16_CLEAR |
| */ |
| |
| /* This gives the 'register relative offset gpio' number */ |
| #define EXTENDED_OFFSET_GPIO(gpio) (gpio < 24 ? gpio - 16 : gpio - 24) |
| |
| /* These take the 'register relative offset gpio' number */ |
| #define EXTENDED_REG_DISABLE(ogpio) (0x2 << ((ogpio * 2) + 16)) |
| #define EXTENDED_REG_ENABLE(ogpio) (0x1 << ((ogpio * 2) + 16)) |
| #define EXTENDED_REG_SET(ogpio) (0x2 << (ogpio * 2)) |
| #define EXTENDED_REG_CLR(ogpio) (0x1 << (ogpio * 2)) |
| |
| /* These take the actual GPIO number (16 through 27) */ |
| #define EXTENDED_DISABLE(gpio) \ |
| EXTENDED_REG_DISABLE(EXTENDED_OFFSET_GPIO(gpio)) |
| #define EXTENDED_ENABLE(gpio) \ |
| EXTENDED_REG_ENABLE(EXTENDED_OFFSET_GPIO(gpio)) |
| #define EXTENDED_SET(gpio) \ |
| EXTENDED_REG_SET(EXTENDED_OFFSET_GPIO(gpio)) |
| #define EXTENDED_CLR(gpio) \ |
| EXTENDED_REG_CLR(EXTENDED_OFFSET_GPIO(gpio)) |
| |
| #define EXTENDED_FULL_MASK (0xffffffff) |
| |
| /* -- API inline-functions -- */ |
| |
| /* |
| * Gets the current value of the specified pin |
| */ |
| static inline enum msp_gpio_data msp_gpio_pin_get(unsigned int gpio) |
| { |
| u32 pinhi_mask = 0, pinhi_mask2 = 0; |
| |
| if (gpio >= MSP_NUM_GPIOS) |
| return MSP_GPIO_NONE; |
| |
| if (gpio < 16) { |
| pinhi_mask = BASIC_DATA_MASK(gpio); |
| } else { |
| /* |
| * Two cases are possible with the EXTENDED register: |
| * - In output mode (ENABLED flag set), check the CLR bit |
| * - In input mode (ENABLED flag not set), check the SET bit |
| */ |
| pinhi_mask = EXTENDED_ENABLE(gpio) | EXTENDED_CLR(gpio); |
| pinhi_mask2 = EXTENDED_SET(gpio); |
| } |
| if (((*MSP_GPIO_DATA_REGISTER[gpio] & pinhi_mask) == pinhi_mask) || |
| (*MSP_GPIO_DATA_REGISTER[gpio] & pinhi_mask2)) |
| return MSP_GPIO_HI; |
| else |
| return MSP_GPIO_LO; |
| } |
| |
| /* Sets the specified pin to the specified value */ |
| static inline void msp_gpio_pin_set(enum msp_gpio_data data, unsigned int gpio) |
| { |
| if (gpio >= MSP_NUM_GPIOS) |
| return; |
| |
| if (gpio < 16) { |
| if (data == MSP_GPIO_TOGGLE) |
| toggle_reg32(MSP_GPIO_DATA_REGISTER[gpio], |
| BASIC_DATA_MASK(gpio)); |
| else if (data == MSP_GPIO_HI) |
| set_reg32(MSP_GPIO_DATA_REGISTER[gpio], |
| BASIC_DATA_MASK(gpio)); |
| else |
| clear_reg32(MSP_GPIO_DATA_REGISTER[gpio], |
| BASIC_DATA_MASK(gpio)); |
| } else { |
| if (data == MSP_GPIO_TOGGLE) { |
| /* Special ugly case: |
| * We have to read the CLR bit. |
| * If set, we write the CLR bit. |
| * If not, we write the SET bit. |
| */ |
| u32 tmpdata; |
| |
| custom_read_reg32(MSP_GPIO_DATA_REGISTER[gpio], |
| tmpdata); |
| if (tmpdata & EXTENDED_CLR(gpio)) |
| tmpdata = EXTENDED_CLR(gpio); |
| else |
| tmpdata = EXTENDED_SET(gpio); |
| custom_write_reg32(MSP_GPIO_DATA_REGISTER[gpio], |
| tmpdata); |
| } else { |
| u32 newdata; |
| |
| if (data == MSP_GPIO_HI) |
| newdata = EXTENDED_SET(gpio); |
| else |
| newdata = EXTENDED_CLR(gpio); |
| set_value_reg32(MSP_GPIO_DATA_REGISTER[gpio], |
| EXTENDED_FULL_MASK, newdata); |
| } |
| } |
| } |
| |
| /* Sets the specified pin to the specified value */ |
| static inline void msp_gpio_pin_hi(unsigned int gpio) |
| { |
| msp_gpio_pin_set(MSP_GPIO_HI, gpio); |
| } |
| |
| /* Sets the specified pin to the specified value */ |
| static inline void msp_gpio_pin_lo(unsigned int gpio) |
| { |
| msp_gpio_pin_set(MSP_GPIO_LO, gpio); |
| } |
| |
| /* Sets the specified pin to the opposite value */ |
| static inline void msp_gpio_pin_toggle(unsigned int gpio) |
| { |
| msp_gpio_pin_set(MSP_GPIO_TOGGLE, gpio); |
| } |
| |
| /* Gets the mode of the specified pin */ |
| static inline enum msp_gpio_mode msp_gpio_pin_get_mode(unsigned int gpio) |
| { |
| enum msp_gpio_mode retval = MSP_GPIO_UNKNOWN; |
| uint32_t data; |
| |
| if (gpio >= MSP_NUM_GPIOS) |
| return retval; |
| |
| data = *MSP_GPIO_MODE_REGISTER[gpio]; |
| |
| if (gpio < 16) { |
| retval = BASIC_MODE_FROM_REG(data, gpio); |
| } else { |
| /* Extended pins can only be either INPUT or OUTPUT */ |
| if (data & EXTENDED_ENABLE(gpio)) |
| retval = MSP_GPIO_OUTPUT; |
| else |
| retval = MSP_GPIO_INPUT; |
| } |
| |
| return retval; |
| } |
| |
| /* |
| * Sets the specified mode on the requested pin |
| * Returns 0 on success, or -1 if that mode is not allowed on this pin |
| */ |
| static inline int msp_gpio_pin_mode(enum msp_gpio_mode mode, unsigned int gpio) |
| { |
| u32 modemask, newmode; |
| |
| if ((1 << gpio) & ~MSP_GPIO_MODE_ALLOWED[mode]) |
| return -1; |
| |
| if (gpio >= MSP_NUM_GPIOS) |
| return -1; |
| |
| if (gpio < 16) { |
| modemask = BASIC_MODE_MASK(gpio); |
| newmode = BASIC_MODE(mode, gpio); |
| } else { |
| modemask = EXTENDED_FULL_MASK; |
| if (mode == MSP_GPIO_INPUT) |
| newmode = EXTENDED_DISABLE(gpio); |
| else |
| newmode = EXTENDED_ENABLE(gpio); |
| } |
| /* Do the set atomically */ |
| set_value_reg32(MSP_GPIO_MODE_REGISTER[gpio], modemask, newmode); |
| |
| return 0; |
| } |
| |
| #endif /* __MSP_GPIO_MACROS_H__ */ |