You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
4.3 KiB
164 lines
4.3 KiB
/*
|
|
* Copyright (c) 2019, Linaro Limited
|
|
* Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <lib/mmio.h>
|
|
#include <drivers/delay_timer.h>
|
|
#include <drivers/rpi3/gpio/rpi3_gpio.h>
|
|
|
|
static uintptr_t reg_base;
|
|
|
|
static int rpi3_gpio_get_direction(int gpio);
|
|
static void rpi3_gpio_set_direction(int gpio, int direction);
|
|
static int rpi3_gpio_get_value(int gpio);
|
|
static void rpi3_gpio_set_value(int gpio, int value);
|
|
static void rpi3_gpio_set_pull(int gpio, int pull);
|
|
|
|
static const gpio_ops_t rpi3_gpio_ops = {
|
|
.get_direction = rpi3_gpio_get_direction,
|
|
.set_direction = rpi3_gpio_set_direction,
|
|
.get_value = rpi3_gpio_get_value,
|
|
.set_value = rpi3_gpio_set_value,
|
|
.set_pull = rpi3_gpio_set_pull,
|
|
};
|
|
|
|
/**
|
|
* Get selection of GPIO pinmux settings.
|
|
*
|
|
* @param gpio The pin number of GPIO. From 0 to 53.
|
|
* @return The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input,
|
|
* RPI3_GPIO_FUNC_OUTPUT: output,
|
|
* RPI3_GPIO_FUNC_ALT0: alt-0,
|
|
* RPI3_GPIO_FUNC_ALT1: alt-1,
|
|
* RPI3_GPIO_FUNC_ALT2: alt-2,
|
|
* RPI3_GPIO_FUNC_ALT3: alt-3,
|
|
* RPI3_GPIO_FUNC_ALT4: alt-4,
|
|
* RPI3_GPIO_FUNC_ALT5: alt-5
|
|
*/
|
|
int rpi3_gpio_get_select(int gpio)
|
|
{
|
|
int ret;
|
|
int regN = gpio / 10;
|
|
int shift = 3 * (gpio % 10);
|
|
uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN);
|
|
uint32_t sel = mmio_read_32(reg_sel);
|
|
|
|
ret = (sel >> shift) & 0x07;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Set selection of GPIO pinmux settings.
|
|
*
|
|
* @param gpio The pin number of GPIO. From 0 to 53.
|
|
* @param fsel The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input,
|
|
* RPI3_GPIO_FUNC_OUTPUT: output,
|
|
* RPI3_GPIO_FUNC_ALT0: alt-0,
|
|
* RPI3_GPIO_FUNC_ALT1: alt-1,
|
|
* RPI3_GPIO_FUNC_ALT2: alt-2,
|
|
* RPI3_GPIO_FUNC_ALT3: alt-3,
|
|
* RPI3_GPIO_FUNC_ALT4: alt-4,
|
|
* RPI3_GPIO_FUNC_ALT5: alt-5
|
|
*/
|
|
void rpi3_gpio_set_select(int gpio, int fsel)
|
|
{
|
|
int regN = gpio / 10;
|
|
int shift = 3 * (gpio % 10);
|
|
uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN);
|
|
uint32_t sel = mmio_read_32(reg_sel);
|
|
uint32_t mask = U(0x07) << shift;
|
|
|
|
sel = (sel & (~mask)) | ((fsel << shift) & mask);
|
|
mmio_write_32(reg_sel, sel);
|
|
}
|
|
|
|
static int rpi3_gpio_get_direction(int gpio)
|
|
{
|
|
int result = rpi3_gpio_get_select(gpio);
|
|
|
|
if (result == RPI3_GPIO_FUNC_INPUT)
|
|
return GPIO_DIR_IN;
|
|
else if (result == RPI3_GPIO_FUNC_OUTPUT)
|
|
return GPIO_DIR_OUT;
|
|
|
|
return GPIO_DIR_IN;
|
|
}
|
|
|
|
static void rpi3_gpio_set_direction(int gpio, int direction)
|
|
{
|
|
switch (direction) {
|
|
case GPIO_DIR_IN:
|
|
rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_INPUT);
|
|
break;
|
|
case GPIO_DIR_OUT:
|
|
rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_OUTPUT);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int rpi3_gpio_get_value(int gpio)
|
|
{
|
|
int regN = gpio / 32;
|
|
int shift = gpio % 32;
|
|
uintptr_t reg_lev = reg_base + RPI3_GPIO_GPLEV(regN);
|
|
uint32_t value = mmio_read_32(reg_lev);
|
|
|
|
if ((value >> shift) & 0x01)
|
|
return GPIO_LEVEL_HIGH;
|
|
return GPIO_LEVEL_LOW;
|
|
}
|
|
|
|
static void rpi3_gpio_set_value(int gpio, int value)
|
|
{
|
|
int regN = gpio / 32;
|
|
int shift = gpio % 32;
|
|
uintptr_t reg_set = reg_base + RPI3_GPIO_GPSET(regN);
|
|
uintptr_t reg_clr = reg_base + RPI3_GPIO_GPSET(regN);
|
|
|
|
switch (value) {
|
|
case GPIO_LEVEL_LOW:
|
|
mmio_write_32(reg_clr, U(1) << shift);
|
|
break;
|
|
case GPIO_LEVEL_HIGH:
|
|
mmio_write_32(reg_set, U(1) << shift);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void rpi3_gpio_set_pull(int gpio, int pull)
|
|
{
|
|
int regN = gpio / 32;
|
|
int shift = gpio % 32;
|
|
uintptr_t reg_pud = reg_base + RPI3_GPIO_GPPUD;
|
|
uintptr_t reg_clk = reg_base + RPI3_GPIO_GPPUDCLK(regN);
|
|
|
|
switch (pull) {
|
|
case GPIO_PULL_NONE:
|
|
mmio_write_32(reg_pud, 0x0);
|
|
break;
|
|
case GPIO_PULL_UP:
|
|
mmio_write_32(reg_pud, 0x2);
|
|
break;
|
|
case GPIO_PULL_DOWN:
|
|
mmio_write_32(reg_pud, 0x1);
|
|
break;
|
|
}
|
|
mdelay(150);
|
|
mmio_write_32(reg_clk, U(1) << shift);
|
|
mdelay(150);
|
|
mmio_write_32(reg_clk, 0x0);
|
|
mmio_write_32(reg_pud, 0x0);
|
|
}
|
|
|
|
void rpi3_gpio_init(void)
|
|
{
|
|
reg_base = RPI3_GPIO_BASE;
|
|
gpio_init(&rpi3_gpio_ops);
|
|
}
|