214 lines
5.3 KiB
C
214 lines
5.3 KiB
C
|
/*
|
||
|
* Samsung Elec.
|
||
|
*
|
||
|
* drivers/gpio/secgpio_dvs_mt.c - Read GPIO for MT6768 of MTK
|
||
|
*
|
||
|
* Copyright (C) 2016, Samsung Electronics.
|
||
|
*
|
||
|
* 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
|
||
|
*/
|
||
|
|
||
|
#include <linux/errno.h>
|
||
|
#include <linux/sec-pinmux.h>
|
||
|
#include "gpiolib.h"
|
||
|
#include "../pinctrl/mediatek/pinctrl-paris.h"
|
||
|
|
||
|
#if defined(CONFIG_MACH_MT6853)
|
||
|
#define AP_GPIO_COUNT 203
|
||
|
#elif defined(CONFIG_MACH_MT6833)
|
||
|
#define AP_GPIO_COUNT 201
|
||
|
#elif defined(CONFIG_MACH_MT6768)
|
||
|
#define AP_GPIO_COUNT 180
|
||
|
#elif defined(CONFIG_MACH_MT6739)
|
||
|
#define AP_GPIO_COUNT 164
|
||
|
#elif defined(CONFIG_MACH_MT6765)
|
||
|
#define AP_GPIO_COUNT 179
|
||
|
#elif defined(CONFIG_MACH_MT6877)
|
||
|
#define AP_GPIO_COUNT 209
|
||
|
#endif
|
||
|
|
||
|
#define GET_RESULT_GPIO(a, b, c) \
|
||
|
((a<<4 & 0xF0) | (b<<1 & 0xE) | (c & 0x1))
|
||
|
|
||
|
static const char *pinctrl_paris_modname = "pinctrl_paris";
|
||
|
|
||
|
static unsigned char checkgpiomap_result[GDVS_PHONE_STATUS_MAX][AP_GPIO_COUNT];
|
||
|
static struct gpiomap_result gpiomap_result = {
|
||
|
.init = checkgpiomap_result[PHONE_INIT],
|
||
|
.sleep = checkgpiomap_result[PHONE_SLEEP]
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
**************************************************************
|
||
|
Pre-defined variables. (DO NOT CHANGE THIS!!)
|
||
|
static unsigned char checkgpiomap_result[GDVS_PHONE_STATUS_MAX][AP_GPIO_COUNT];
|
||
|
static struct gpiomap_result gpiomap_result = {
|
||
|
.init = checkgpiomap_result[PHONE_INIT],
|
||
|
.sleep = checkgpiomap_result[PHONE_SLEEP]
|
||
|
};
|
||
|
**************************************************************
|
||
|
*/
|
||
|
|
||
|
static int mtk_hw_get_value_wrap(struct mtk_pinctrl *hw, unsigned int gpio,
|
||
|
int field)
|
||
|
{
|
||
|
const struct mtk_pin_desc *desc;
|
||
|
int value, err;
|
||
|
|
||
|
if (gpio > hw->soc->npins)
|
||
|
return -EINVAL;
|
||
|
|
||
|
desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio];
|
||
|
|
||
|
err = mtk_hw_get_value(hw, desc, field, &value);
|
||
|
if (err)
|
||
|
return err;
|
||
|
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
#define mtk_pctrl_get_pinmux(hw, gpio) \
|
||
|
mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_MODE)
|
||
|
|
||
|
#define mtk_pctrl_get_direction(hw, gpio) \
|
||
|
mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_DIR)
|
||
|
|
||
|
#define mtk_pctrl_get_out(hw, gpio) \
|
||
|
mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_DO)
|
||
|
|
||
|
#define mtk_pctrl_get_in(hw, gpio) \
|
||
|
mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_DI)
|
||
|
|
||
|
static void mt_check_gpio_status(unsigned char phonestate)
|
||
|
{
|
||
|
struct gpio_device *gdev;
|
||
|
struct gpio_chip *chip = NULL;
|
||
|
struct mtk_pinctrl *hw;
|
||
|
const struct mtk_pin_desc *desc;
|
||
|
unsigned long flags;
|
||
|
unsigned int i;
|
||
|
|
||
|
struct gpiomux_setting val;
|
||
|
int temp_io = 0, temp_pupd = 0, temp_level = 0;
|
||
|
|
||
|
spin_lock_irqsave(&gpio_lock, flags);
|
||
|
list_for_each_entry(gdev, &gpio_devices, list) {
|
||
|
chip = gdev->chip;
|
||
|
if (strncmp(pinctrl_paris_modname, chip->label,
|
||
|
strlen(pinctrl_paris_modname)) == 0)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
hw = gpiochip_get_data(chip);
|
||
|
for (i = 0; i < AP_GPIO_COUNT ; i++) {
|
||
|
temp_io = 0;
|
||
|
temp_pupd = 0;
|
||
|
temp_level = 0;
|
||
|
|
||
|
desc = (const struct mtk_pin_desc *)&hw->soc->pins[i];
|
||
|
val.func = mtk_pctrl_get_pinmux(hw, i);
|
||
|
val.dir = mtk_pctrl_get_direction(hw, i);
|
||
|
mtk_pinconf_bias_get_combo(hw, desc, &val.pull, &val.pull_en);
|
||
|
|
||
|
/* Check Pin-Mux Configuration */
|
||
|
switch (val.func) {
|
||
|
case GPIOMUX_FUNC_GPIO:
|
||
|
switch (val.dir) {
|
||
|
case GPIOMUX_IN:
|
||
|
temp_io = GDVS_IO_IN;
|
||
|
temp_level = mtk_pctrl_get_in(hw, i);
|
||
|
break;
|
||
|
case GPIOMUX_OUT:
|
||
|
temp_io = GDVS_IO_OUT;
|
||
|
temp_level = mtk_pctrl_get_out(hw, i);
|
||
|
break;
|
||
|
default:
|
||
|
temp_io = GDVS_IO_ERR;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case GPIOMUX_FUNC_1:
|
||
|
case GPIOMUX_FUNC_2:
|
||
|
case GPIOMUX_FUNC_3:
|
||
|
case GPIOMUX_FUNC_4:
|
||
|
case GPIOMUX_FUNC_5:
|
||
|
case GPIOMUX_FUNC_6:
|
||
|
case GPIOMUX_FUNC_7:
|
||
|
temp_io = GDVS_IO_FUNC;
|
||
|
break;
|
||
|
default:
|
||
|
temp_io = GDVS_IO_ERR;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Check Pull Configuration */
|
||
|
switch (val.pull_en) {
|
||
|
case GPIOMUX_PULL_DIS:
|
||
|
case GPIOMUX_PULL_NONE:
|
||
|
temp_pupd = GDVS_PUPD_NP;
|
||
|
break;
|
||
|
case GPIOMUX_PULL_EN:
|
||
|
case GPIOMUX_PULL1:
|
||
|
case GPIOMUX_PULL2:
|
||
|
case GPIOMUX_PULL3:
|
||
|
switch (val.pull) {
|
||
|
case GPIOMUX_PULL_DOWN:
|
||
|
temp_pupd = GDVS_PUPD_PD;
|
||
|
break;
|
||
|
case GPIOMUX_PULL_UP:
|
||
|
temp_pupd = GDVS_PUPD_PU;
|
||
|
break;
|
||
|
default:
|
||
|
temp_pupd = GDVS_PUPD_ERR;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
temp_pupd = GDVS_PUPD_ERR;
|
||
|
}
|
||
|
|
||
|
checkgpiomap_result[phonestate][i] =
|
||
|
(unsigned char)GET_RESULT_GPIO(temp_io, temp_pupd, temp_level);
|
||
|
}
|
||
|
spin_unlock_irqrestore(&gpio_lock, flags);
|
||
|
}
|
||
|
|
||
|
static void check_gpio_status(unsigned char phonestate)
|
||
|
{
|
||
|
pr_info("[secgpio_dvs][%s] state : %s\n", __func__,
|
||
|
(phonestate == PHONE_INIT) ? "init" : "sleep");
|
||
|
|
||
|
mt_check_gpio_status(phonestate);
|
||
|
}
|
||
|
|
||
|
static struct gpio_dvs mt_gpio_dvs = {
|
||
|
.result = &gpiomap_result,
|
||
|
.check_gpio_status = check_gpio_status,
|
||
|
.count = AP_GPIO_COUNT,
|
||
|
};
|
||
|
|
||
|
struct platform_device secgpio_dvs_device = {
|
||
|
.name = "secgpio_dvs",
|
||
|
.id = -1,
|
||
|
/*
|
||
|
***************************************************************
|
||
|
Designate appropriate variable pointer
|
||
|
in accordance with the specification of each BB vendor.
|
||
|
***************************************************************
|
||
|
*/
|
||
|
.dev.platform_data = &mt_gpio_dvs,
|
||
|
};
|
||
|
|
||
|
static struct platform_device *secgpio_dvs_devices[] __initdata = {
|
||
|
&secgpio_dvs_device,
|
||
|
};
|
||
|
|
||
|
static int __init secgpio_dvs_device_init(void)
|
||
|
{
|
||
|
return platform_add_devices(
|
||
|
secgpio_dvs_devices, ARRAY_SIZE(secgpio_dvs_devices));
|
||
|
}
|
||
|
arch_initcall(secgpio_dvs_device_init);
|