| /* |
| * Copyright (C) 2018 Synaptics Incorporated. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| * |
| * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND |
| * SYNAPTICS EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, |
| * INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE, AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY |
| * INTELLECTUAL PROPERTY RIGHTS. IN NO EVENT SHALL SYNAPTICS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE, OR |
| * CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION WITH THE USE |
| * OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED AND |
| * BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS |
| * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF |
| * COMPETENT JURISDICTION DOES NOT PERMIT THE DISCLAIMER OF DIRECT |
| * DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' TOTAL CUMULATIVE LIABILITY |
| * TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. DOLLARS. |
| */ |
| |
| #define _GPIO_C_ |
| /* |
| * Programming sample: |
| * 1. spi_master_init_iomapper(IOMAPPER_SPI_MASTER), init IOmapper |
| * 2. GPIO_PinmuxInit(port), setting both Galois and IOmapper pinmux |
| * 3.1 GPIO_IOmapperSetInOut(port, in), setting GPIO pin as in / out. |
| * 3.2 GPIO_PortSetInOut(port, in), setting GPIO pin as in /out. |
| * 4. GPIO_PortWrite, GPIOPortRead |
| * |
| * NOTE: GPIO_PinmuxInit shouldn't setup GPIO[13:10], it's SPI#0 for |
| * programming IOmapper. Galois GPIO in / out setting is done in |
| * GPIO_PortWrite / GPIOPortRead, just for campatible forward with Berlin. |
| * |
| * NOTE: for Berlin, #1.spi_master_init_iomapper and #3.1 is descarded. |
| */ |
| |
| #include <stdlib.h> |
| #include <stdint.h> |
| #include "io.h" |
| |
| #include "apb_perif_base.h" |
| #include "apb_gpio.h" |
| #include "global.h" |
| #include "gpio.h" |
| |
| struct gpio_port_inst { |
| uint32_t base; |
| uint32_t reg_dr; |
| uint32_t reg_ddr; |
| uint32_t reg_ctl; |
| uint32_t reg_ext; |
| }; |
| |
| /**************************************************** |
| * FUNCTION: find out SOC GPIO instance data according |
| to GPIO port number |
| * PARAMS: portnum - SoC GPIO port # (0 ~ 41) |
| * *inst - GPIO instance data |
| * *offset - offset in GPIO instance |
| * RETURN: 0 - succeed |
| * -1 - fail |
| ***************************************************/ |
| static int SOC_GPIO_GetPortInst(int portnum, struct gpio_port_inst *inst, uint32_t *offset) |
| { |
| if(inst == NULL) |
| return -1; |
| |
| if(offset == NULL) |
| return -1; |
| |
| if(portnum < 0) { |
| return -1; |
| } else if(portnum < 32){ |
| inst->base = APB_GPIO0_BASE; |
| *offset = portnum; |
| } |
| else if(portnum < 64){ |
| inst->base = APB_GPIO1_BASE; |
| *offset = portnum - 32; |
| } |
| else { |
| return -1; |
| } |
| |
| inst->reg_dr = inst->base + APB_GPIO_SWPORTA_DR; |
| inst->reg_ddr = inst->base + APB_GPIO_SWPORTA_DDR; |
| inst->reg_ctl = inst->base + APB_GPIO_PORTA_CTL; |
| inst->reg_ext = inst->base + APB_GPIO_EXT_PORTA; |
| |
| return 0; |
| } |
| |
| |
| /**************************************************** |
| * FUNCTION: toggle GPIO port between high and low |
| * PARAMS: portnum - GPIO port # (0 ~ 41) |
| * value - 1: high; 0: low |
| * RETURN: 0 - succeed |
| * -1 - fail |
| ***************************************************/ |
| int GPIO_PortWrite(int portnum, int value) |
| { |
| struct gpio_port_inst inst; |
| uint32_t offset, ddr, dr; |
| |
| if(SOC_GPIO_GetPortInst(portnum, &inst, &offset)) |
| return -1; |
| |
| /* set port value */ |
| dr = readl(inst.reg_dr); |
| if (value){ |
| dr |= (1<<offset); |
| } else { |
| dr &= ~(1<<offset); |
| } |
| writel(dr, inst.reg_dr); |
| |
| /* set port to output mode */ |
| ddr = readl(inst.reg_ddr); |
| ddr |= (1<<offset); |
| writel(ddr, inst.reg_ddr); |
| |
| return 0; |
| } |
| |
| /**************************************************** |
| * FUNCTION: read GPIO port status |
| * PARAMS: portnum - GPIO port # (0 ~ 41) |
| * *value - pointer to port status |
| * RETURN: 0 - succeed |
| * -1 - fail |
| ***************************************************/ |
| int GPIO_PortRead(int portnum, int *value) |
| { |
| struct gpio_port_inst inst; |
| uint32_t offset, ddr, ext; |
| |
| if(SOC_GPIO_GetPortInst(portnum, &inst, &offset)) |
| return -1; |
| |
| /* set port to input mode */ |
| ddr = readl(inst.reg_ddr); |
| ddr &= ~(1<<offset); |
| writel(ddr, inst.reg_ddr); |
| |
| /* get port value */ |
| ext = readl(inst.reg_ext); |
| if (ext & (1<<offset)) |
| *value = 1; |
| else |
| *value = 0; |
| |
| return 0; |
| } |
| |
| /**************************************************** |
| * FUNCTION: Set Galois GPIO pin as in or out |
| * PARAMS: portnum - GPIO port # (0 ~ 31) |
| * in - 1: IN, 0: OUT |
| * RETURN: 0 - succeed |
| * -1 - fail |
| ***************************************************/ |
| int GPIO_PortSetInOut(int portnum, int in) |
| { |
| struct gpio_port_inst inst; |
| uint32_t offset, ddr, ctl; |
| |
| if(SOC_GPIO_GetPortInst(portnum, &inst, &offset)) |
| return -1; |
| |
| /* software mode */ |
| ctl = readl(inst.reg_ctl); |
| ctl &= ~(1 << offset); |
| writel(ctl, inst.reg_ctl); |
| |
| /* set port to output mode */ |
| ddr = readl(inst.reg_ddr); |
| if (in) |
| ddr &= ~(1 << offset); |
| else |
| ddr |= (1 << offset); |
| writel(ddr, inst.reg_ddr); |
| |
| return 0; |
| } |