327 lines
7.8 KiB
C
327 lines
7.8 KiB
C
// SPDX-License-Identifier: BSD-3-Clause
|
|
/*
|
|
* Copyright (c) 2021 Rockchip Electronics Co. Ltd.
|
|
*
|
|
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
|
|
*/
|
|
|
|
#include "rk628.h"
|
|
|
|
static int rk628_calc_mux_offset(struct rk628 *rk628, int mux, int reg, int offset)
|
|
{
|
|
int val = 0, orig;
|
|
|
|
switch (reg) {
|
|
case GRF_SYSTEM_CON3:
|
|
rk628_i2c_read(rk628, reg, &orig);
|
|
if (mux)
|
|
val = BIT(offset) | orig;
|
|
else
|
|
val = ~BIT(offset) & orig;
|
|
break;
|
|
case GRF_GPIO0AB_SEL_CON:
|
|
if (offset >= 4 && offset < 8) {
|
|
offset += offset - 4;
|
|
val = 0x3 << (offset + 16) | (mux << offset);
|
|
} else if (offset > 7) {
|
|
offset += 4;
|
|
val = BIT(offset + 16) | (mux << offset);
|
|
} else {
|
|
val = BIT(offset + 16) | (mux << offset);
|
|
}
|
|
break;
|
|
case GRF_GPIO1AB_SEL_CON:
|
|
if (offset == 13)
|
|
offset++;
|
|
if (offset > 11)
|
|
val = 0x3 << (offset + 16) | (mux << offset);
|
|
else
|
|
val = BIT(offset + 16) | (mux << offset);
|
|
break;
|
|
case GRF_GPIO2AB_SEL_CON:
|
|
val = BIT(offset + 16) | (mux << offset);
|
|
break;
|
|
case GRF_GPIO2C_SEL_CON:
|
|
offset -= 16;
|
|
val = 0x3 << ((offset*2) + 16) | (mux << (offset*2));
|
|
break;
|
|
case GRF_GPIO3AB_SEL_CON:
|
|
if (offset > 11)
|
|
val = 0x3 << (offset + 16) | (mux << offset);
|
|
else
|
|
val = BIT(offset + 16) | (mux << offset);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
int rk628_misc_pinctrl_set_mux(struct rk628 *rk628, int gpio, int mux)
|
|
{
|
|
int i, iomux_base, offset, val;
|
|
|
|
mux &= 0x3;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(rk628_pin_iomux_groups); i++) {
|
|
if (rk628_pin_iomux_groups[i].pins == gpio) {
|
|
iomux_base = rk628_pin_iomux_groups[i].iomux_base;
|
|
offset = rk628_pin_iomux_groups[i].pins % BANK_OFFSET;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((i == ARRAY_SIZE(rk628_pin_iomux_groups)) || (!iomux_base)) {
|
|
pr_info("%s invalid gpio or iomux_base\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
val = rk628_calc_mux_offset(rk628, mux, iomux_base, offset);
|
|
|
|
rk628_i2c_write(rk628, iomux_base, val);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
/* generic gpio chip */
|
|
int rk628_misc_gpio_get_value(struct rk628 *rk628, int gpio)
|
|
{
|
|
int i, data_reg, offset, val;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(rk628_pin_iomux_groups); i++) {
|
|
if (rk628_pin_iomux_groups[i].pins == gpio) {
|
|
data_reg = rk628_pin_iomux_groups[i].gpio_base + GPIO_EXT_PORT;
|
|
offset = rk628_pin_iomux_groups[i].pins % BANK_OFFSET;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((i == ARRAY_SIZE(rk628_pin_iomux_groups)) || (!data_reg)) {
|
|
pr_info("%s invalid gpio or data_reg\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
rk628_i2c_read(rk628, data_reg, &val);
|
|
|
|
val >>= offset;
|
|
val &= 1;
|
|
|
|
return val;
|
|
}
|
|
|
|
int rk628_misc_gpio_set_value(struct rk628 *rk628, int gpio, int value)
|
|
{
|
|
int i, data_reg, offset, val;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(rk628_pin_iomux_groups); i++) {
|
|
if (rk628_pin_iomux_groups[i].pins == gpio) {
|
|
offset = rk628_pin_iomux_groups[i].pins % BANK_OFFSET;
|
|
if (offset >= 16) {
|
|
data_reg = rk628_pin_iomux_groups[i].gpio_base + GPIO_SWPORT_DR_H;
|
|
offset -= 16;
|
|
} else {
|
|
data_reg = rk628_pin_iomux_groups[i].gpio_base + GPIO_SWPORT_DR_L;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((i == ARRAY_SIZE(rk628_pin_iomux_groups)) || (!data_reg)) {
|
|
pr_info("%s invalid gpio or data_reg\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
if (value)
|
|
val = BIT(offset + 16) | BIT(offset);
|
|
else
|
|
val = BIT(offset + 16) | (0xffff & ~BIT(offset));
|
|
|
|
rk628_i2c_write(rk628, data_reg, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int rk628_misc_gpio_set_direction(struct rk628 *rk628, int gpio, int direction)
|
|
{
|
|
int i, dir_reg, offset, val;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(rk628_pin_iomux_groups); i++) {
|
|
if (rk628_pin_iomux_groups[i].pins == gpio) {
|
|
offset = rk628_pin_iomux_groups[i].pins % BANK_OFFSET;
|
|
if (offset >= 16) {
|
|
dir_reg = rk628_pin_iomux_groups[i].gpio_base + GPIO_SWPORT_DDR_H;
|
|
offset -= 16;
|
|
} else {
|
|
dir_reg = rk628_pin_iomux_groups[i].gpio_base + GPIO_SWPORT_DDR_L;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((i == ARRAY_SIZE(rk628_pin_iomux_groups)) || (!dir_reg)) {
|
|
pr_info("%s invalid gpio or dir_reg\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
if (!direction)
|
|
val = BIT(offset + 16) | (0xffff & ~BIT(offset));
|
|
else
|
|
val = BIT(offset + 16) | BIT(offset);
|
|
|
|
rk628_i2c_write(rk628, dir_reg, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int rk628_misc_iomux_init(struct rk628 *rk628)
|
|
{
|
|
int i, iomux_base, offset, val, mux;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(rk628_pin_iomux_groups); i++) {
|
|
mux = rk628_pin_iomux_groups[i].mux;
|
|
iomux_base = rk628_pin_iomux_groups[i].iomux_base;
|
|
offset = rk628_pin_iomux_groups[i].pins % BANK_OFFSET;
|
|
if (iomux_base) {
|
|
val = rk628_calc_mux_offset(rk628, mux, iomux_base, offset);
|
|
rk628_i2c_write(rk628, iomux_base, val);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int rk628_misc_gpio_direction_input(struct rk628 *rk628, int gpio)
|
|
{
|
|
rk628_misc_pinctrl_set_mux(rk628, gpio, GPIO_FUNC);
|
|
|
|
rk628_misc_gpio_set_direction(rk628, gpio, GPIO_DIRECTION_IN);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int rk628_misc_gpio_direction_output(struct rk628 *rk628, int gpio, int value)
|
|
{
|
|
|
|
rk628_misc_pinctrl_set_mux(rk628, gpio, GPIO_FUNC);
|
|
rk628_misc_gpio_set_value(rk628, gpio, value);
|
|
rk628_misc_gpio_set_direction(rk628, gpio, GPIO_DIRECTION_OUT);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int rk628_misc_gpio_set_pull_highz_up_down(struct rk628 *rk628, int gpio, int pull)
|
|
{
|
|
int i, bank, pull_reg = 0, offset, val = 0;
|
|
int valid_pinnum[] = { 8, 8, 24, 13 };
|
|
|
|
for (i = 0; i < ARRAY_SIZE(rk628_pin_iomux_groups); i++) {
|
|
if (rk628_pin_iomux_groups[i].pins == gpio) {
|
|
bank = rk628_pin_iomux_groups[i].bank;
|
|
pull_reg = rk628_pin_iomux_groups[i].pull_reg;
|
|
offset = rk628_pin_iomux_groups[i].pins % BANK_OFFSET;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((i == ARRAY_SIZE(rk628_pin_iomux_groups)) || (!pull_reg)) {
|
|
pr_info("rk628_gpio_pull_highz_up_down invalid gpio or pull_reg\n");
|
|
return -1;
|
|
}
|
|
|
|
switch (bank) {
|
|
case GPIO_BANK0:
|
|
if (pull == GPIO_PULL_UP)
|
|
return -1;
|
|
|
|
if (offset == 2)
|
|
return -1;
|
|
|
|
if (offset < valid_pinnum[bank])
|
|
val = 0x3 << (2 * offset + 16) | pull << (2 * offset);
|
|
break;
|
|
case GPIO_BANK1:
|
|
if (pull == GPIO_PULL_UP)
|
|
return -1;
|
|
|
|
if (offset == 2)
|
|
return -1;
|
|
|
|
if (offset < valid_pinnum[bank])
|
|
val = 0x3 << (2 * offset + 16) | pull << (2 * offset);
|
|
break;
|
|
case GPIO_BANK2:
|
|
if (pull == GPIO_PULL_UP)
|
|
pull = GPIO_PULL_DOWN;
|
|
else if (pull == GPIO_PULL_DOWN)
|
|
pull = GPIO_PULL_UP;
|
|
|
|
if (offset < valid_pinnum[bank]) {
|
|
offset = offset % 8;
|
|
val = 0x3 << (2 * offset + 16) | pull << (2 * offset);
|
|
}
|
|
break;
|
|
case GPIO_BANK3:
|
|
if (pull == GPIO_PULL_UP && (offset == 2 || offset == 11 || offset == 12))
|
|
return -1;
|
|
else if (pull == GPIO_PULL_DOWN && (offset == 9 || offset == 10))
|
|
return -1;
|
|
|
|
if (offset == 0 || offset == 1 || offset == 3 || offset == 8) {
|
|
if (pull == GPIO_PULL_UP)
|
|
pull = GPIO_PULL_DOWN;
|
|
else if (pull == GPIO_PULL_DOWN)
|
|
pull = GPIO_PULL_UP;
|
|
}
|
|
|
|
if ((offset > 7 && offset < valid_pinnum[bank]) || offset < 4) {
|
|
offset = offset % 8;
|
|
val = 0x3 << (2 * offset + 16) | pull << (2 * offset);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
rk628_i2c_write(rk628, pull_reg, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int rk628_misc_gpio_test_all(struct rk628 *rk628)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(rk628_pin_iomux_groups); i++) {
|
|
if (rk628_pin_iomux_groups[i].pins && (rk628_pin_iomux_groups[i].pins != GPIO1_A1)
|
|
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C0)
|
|
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C1)
|
|
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C2)
|
|
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C3)
|
|
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C4))
|
|
rk628_misc_gpio_direction_output(rk628, rk628_pin_iomux_groups[i].pins, 1);
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(rk628_pin_iomux_groups); i++) {
|
|
if (rk628_pin_iomux_groups[i].pins && (rk628_pin_iomux_groups[i].pins != GPIO1_A1)
|
|
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C0)
|
|
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C1)
|
|
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C2)
|
|
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C3)
|
|
&& (rk628_pin_iomux_groups[i].pins != GPIO2_C4))
|
|
rk628_misc_gpio_direction_output(rk628, rk628_pin_iomux_groups[i].pins, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|