Add samsung specific changes

This commit is contained in:
2025-08-11 14:29:00 +02:00
parent c66122e619
commit 4d134a1294
2688 changed files with 1127995 additions and 11475 deletions

View File

@@ -124,4 +124,16 @@ config PINCTRL_SM8550_LPASS_LPI
(Low Power Island) found on the Qualcomm Technologies Inc SM8550
platform.
config SEC_GPIO_DVS
tristate "setting Samsung GPIO debugging and verification system"
help
To verify gpio configurations of devices, set this feature.
This feature should be enabled for user-debug mode.
config SEC_GPIO_DUMP
bool "Help to check GPIO configuration"
help
To debug gpio state, set this feature.
This feature can be enabled for all modes.
endif

View File

@@ -1,6 +1,76 @@
# SPDX-License-Identifier: GPL-2.0-only
if PINCTRL_MSM
config PINCTRL_KERA
tristate "Qualcomm Technologies, Inc. KERA pin controller driver"
depends on GPIOLIB && OF
help
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm Technologies Inc Top Level Mode Multiplexer block (TLMM)
block found on the Qualcomm Technologies Inc KERA platform.
Say Y here to compile statically, or M here to compile it as a
module. If unsure, say N.
config PINCTRL_TUNA
tristate "Qualcomm Technologies, Inc. TUNA pin controller driver"
depends on GPIOLIB && OF
help
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm Technologies Inc Top Level Mode Multiplexer block (TLMM)
block found on the Qualcomm Technologies Inc TUNA platform.
Say Y here to compile statically, or M here to compile it as a
module. If unsure, say N.
config PINCTRL_SUN
tristate "Qualcomm Technologies, Inc. SUN pin controller driver"
depends on GPIOLIB && OF
help
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm Technologies Inc Top Level Mode Multiplexer block (TLMM)
block found on the Qualcomm Technologies Inc SUN platform.
Say Y here to compile statically, or M here to compile it as a
module. If unsure, say N.
config PINCTRL_PINEAPPLE
tristate "Qualcomm Technologies, Inc. Pineapple pin controller driver"
depends on GPIOLIB && OF
help
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm Technologies Inc Top Level Mode Multiplexer block (TLMM)
block found on the Qualcomm Technologies Inc PINEAPPLE platform.
Say Y here to compile statically, or M here to compile it as a
module. If unsure, say N.
config PINCTRL_PARROT
tristate "Qualcomm Technologies Inc PARROT pin controller driver"
depends on GPIOLIB && OF
help
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm Technologies Inc Top Level Mode Multiplexer block (TLMM)
block found on the Qualcomm Technologies Inc PARROT platform.
Say Y here to compile statically, or M here to compile it as a module.
If unsure, say N.
config PINCTRL_RAVELIN
tristate "Qualcomm Technologies Inc RAVELIN pin controller driver"
depends on GPIOLIB && OF
help
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm Technologies Inc Top Level Mode Multiplexer block (TLMM)
block found on the Qualcomm Technologies Inc RAVELIN platform.
Say Y here to compile statically, or M here to compile it as a module.
If unsure, say N.
config PINCTRL_MONACO
tristate "Qualcomm Technologies, Inc MONACO pin controller driver"
depends on GPIOLIB && OF
help
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm Technologies Inc Top Level Mode Multiplexer block (TLMM)
block found on the Qualcomm Technologies Inc MONACO platform.
Say Y here to compile statically, or M here to compile it as a
module. If unsure, say N.
config PINCTRL_APQ8064
tristate "Qualcomm APQ8064 pin controller driver"
depends on ARM || COMPILE_TEST
@@ -366,4 +436,13 @@ config PINCTRL_SM8550
Qualcomm Technologies Inc TLMM block found on the Qualcomm
Technologies Inc SM8550 platform.
config PINCTRL_X1E80100
tristate "Qualcomm Technologies Inc X1E80100 pin controller driver"
depends on ARM64 || COMPILE_TEST
help
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm Technologies Inc Top Level Mode Multiplexer block (TLMM)
block found on the Qualcomm Technologies Inc X1E80100 platform.
Say Y here to compile statically, or M here to compile it as a module.
If unsure, say N.
endif

View File

@@ -1,6 +1,12 @@
# SPDX-License-Identifier: GPL-2.0
# Qualcomm pin control drivers
obj-$(CONFIG_PINCTRL_MSM) += pinctrl-msm.o
obj-$(CONFIG_PINCTRL_TUNA) += pinctrl-tuna.o
obj-$(CONFIG_PINCTRL_KERA) += pinctrl-kera.o
obj-$(CONFIG_PINCTRL_SUN) += pinctrl-sun.o
obj-$(CONFIG_PINCTRL_RAVELIN) += pinctrl-ravelin.o
obj-$(CONFIG_PINCTRL_PINEAPPLE) += pinctrl-pineapple.o
obj-$(CONFIG_PINCTRL_PARROT) += pinctrl-parrot.o
obj-$(CONFIG_PINCTRL_APQ8064) += pinctrl-apq8064.o
obj-$(CONFIG_PINCTRL_APQ8084) += pinctrl-apq8084.o
obj-$(CONFIG_PINCTRL_IPQ4019) += pinctrl-ipq4019.o
@@ -60,3 +66,8 @@ obj-$(CONFIG_PINCTRL_SM8550) += pinctrl-sm8550.o
obj-$(CONFIG_PINCTRL_SM8550_LPASS_LPI) += pinctrl-sm8550-lpass-lpi.o
obj-$(CONFIG_PINCTRL_SC8280XP_LPASS_LPI) += pinctrl-sc8280xp-lpass-lpi.o
obj-$(CONFIG_PINCTRL_LPASS_LPI) += pinctrl-lpass-lpi.o
obj-$(CONFIG_PINCTRL_X1E80100) += pinctrl-x1e80100.o
obj-$(CONFIG_PINCTRL_MONACO) += pinctrl-monaco.o
# Debug and verify gpio configurations.
obj-$(CONFIG_SEC_GPIO_DVS) += secgpio_dvs.o

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013, Sony Mobile Communications AB.
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
* Copyright (c) 2013-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/delay.h>
@@ -24,8 +25,9 @@
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/soc/qcom/irq.h>
#include <linux/bitmap.h>
#include <linux/sizes.h>
#include "../core.h"
#include "../pinconf.h"
@@ -33,9 +35,16 @@
#include "pinctrl-msm.h"
#if IS_ENABLED(CONFIG_SEC_GPIO_DVS)
#include "secgpio_dvs.h"
#endif
#define MAX_NR_GPIO 300
#define MAX_NR_TILES 4
#define DEFAULT_REG_SIZE_4K 1
#define PS_HOLD_OFFSET 0x820
#define QUP_MASK GENMASK(5, 0)
#define SPARE_MASK GENMASK(15, 8)
/**
* struct msm_pinctrl - state for a pinctrl-msm device
@@ -82,6 +91,39 @@ struct msm_pinctrl {
u32 phys_base[MAX_NR_TILES];
};
static struct msm_pinctrl *msm_pinctrl_data;
static bool pinctrl_msm_log_mask;
#define EGPIO_PRESENT 11
#define EGPIO_ENABLE 12
#define I2C_PULL 13
#define MSM_APPS_OWNER 1
#define MSM_REMOTE_OWNER 0
/* custom pinconf parameters for msm pinictrl*/
#define MSM_PIN_CONFIG_APPS (PIN_CONFIG_END + 1)
#define MSM_PIN_CONFIG_REMOTE (PIN_CONFIG_END + 2)
#define MSM_PIN_CONFIG_I2C_PULL (PIN_CONFIG_END + 3)
static const struct pinconf_generic_params msm_gpio_bindings[] = {
{"qcom,apps", MSM_PIN_CONFIG_APPS, 0},
{"qcom,remote", MSM_PIN_CONFIG_REMOTE, 0},
{"qcom,i2c_pull", MSM_PIN_CONFIG_I2C_PULL, 0},
};
static const char * const pulls_keeper[] = {
"no pull",
"pull down",
"keeper",
"pull up"
};
static const char * const pulls_no_keeper[] = {
"no pull",
"pull down",
"pull up",
};
#define MSM_ACCESSOR(name) \
static u32 msm_readl_##name(struct msm_pinctrl *pctrl, \
const struct msm_pingroup *g) \
@@ -326,6 +368,15 @@ static int msm_config_reg(struct msm_pinctrl *pctrl,
*bit = g->oe_bit;
*mask = 1;
break;
case MSM_PIN_CONFIG_APPS:
case MSM_PIN_CONFIG_REMOTE:
*bit = EGPIO_ENABLE;
*mask = 1;
break;
case MSM_PIN_CONFIG_I2C_PULL:
*bit = I2C_PULL;
*mask = 1;
break;
default:
return -ENOTSUPP;
}
@@ -418,6 +469,23 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev,
if (!arg)
return -EINVAL;
break;
case MSM_PIN_CONFIG_APPS:
/* Pin do not support egpio or remote owner */
if (!(val & BIT(EGPIO_PRESENT)) || !arg)
return -EINVAL;
arg = 1;
break;
case MSM_PIN_CONFIG_REMOTE:
/* Pin do not support epgio or APPS owner */
if (!(val & BIT(EGPIO_PRESENT)) || arg)
return -EINVAL;
arg = 1;
break;
case MSM_PIN_CONFIG_I2C_PULL:
arg = 1;
break;
default:
return -ENOTSUPP;
}
@@ -439,6 +507,7 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
unsigned mask;
unsigned arg;
unsigned bit;
u32 owner_bit, owner_update = 0;
int ret;
u32 val;
int i;
@@ -527,6 +596,17 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
*/
arg = 0;
break;
case MSM_PIN_CONFIG_APPS:
owner_update = 1;
owner_bit = MSM_APPS_OWNER;
break;
case MSM_PIN_CONFIG_REMOTE:
owner_update = 1;
owner_bit = MSM_REMOTE_OWNER;
break;
case MSM_PIN_CONFIG_I2C_PULL:
arg = 1;
break;
case PIN_CONFIG_OUTPUT_ENABLE:
arg = !!arg;
break;
@@ -541,6 +621,9 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
dev_err(pctrl->dev, "config %x: %x is invalid\n", param, arg);
return -EINVAL;
}
/* Update the owner bits as final config update */
if (param == MSM_PIN_CONFIG_APPS || param == MSM_PIN_CONFIG_REMOTE)
continue;
raw_spin_lock_irqsave(&pctrl->lock, flags);
val = msm_readl_ctl(pctrl, g);
@@ -550,6 +633,22 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
}
if (owner_update) {
ret = msm_config_reg(pctrl, g,
MSM_PIN_CONFIG_APPS, &mask, &bit);
if (ret < 0)
return ret;
raw_spin_lock_irqsave(&pctrl->lock, flags);
val = msm_readl_ctl(pctrl, g);
if (val & BIT(EGPIO_PRESENT)) {
val &= ~(mask << bit);
val |= owner_bit << bit;
msm_writel_ctl(val, pctrl, g);
}
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
}
return 0;
}
@@ -653,6 +752,229 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
}
static void msm_gpio_pin_status_get(struct msm_pinctrl *pctrl, const struct msm_pingroup *g,
unsigned int offset, int *is_out, unsigned int *func,
int *drive, int *pull, int *egpio_enable, int *val)
{
u32 ctl_reg, io_reg;
ctl_reg = msm_readl_ctl(pctrl, g);
io_reg = msm_readl_io(pctrl, g);
*is_out = !!(ctl_reg & BIT(g->oe_bit));
*func = (ctl_reg >> g->mux_bit) & 7;
*drive = (ctl_reg >> g->drv_bit) & 7;
*pull = (ctl_reg >> g->pull_bit) & 3;
*egpio_enable = 0;
if (pctrl->soc->egpio_func && ctl_reg & BIT(g->egpio_present))
*egpio_enable = !(ctl_reg & BIT(g->egpio_enable));
if (*is_out)
*val = !!(io_reg & BIT(g->out_bit));
else
*val = !!(io_reg & BIT(g->in_bit));
}
#if IS_ENABLED(CONFIG_SEC_GPIO_DVS) || IS_ENABLED(CONFIG_SEC_GPIO_DUMP)
#define AP_GPIO_MAX 215
#define IN_OUT_MASK 0xF0
#define PUPD_MASK 0xE
#define DATA_MASK 0x1
#define GET_RESULT_GPIO(a, b, c) \
((a<<4 & IN_OUT_MASK) | (b<<1 & PUPD_MASK) | (c & DATA_MASK))
struct gpiomux_setting {
int func;
int drv;
int pull;
int is_out;
int val;
};
static void msm_gp_get_all(struct gpio_chip *chip, u32 pin_no, struct gpiomux_setting *set)
{
const struct msm_pingroup *g;
struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
u32 ctl_reg, io_reg;
int drive;
g = &pctrl->soc->groups[pin_no];
ctl_reg = msm_readl_ctl(pctrl, g);
io_reg = msm_readl_io(pctrl, g);
set->is_out = !!(ctl_reg & BIT(g->oe_bit));
set->func = (ctl_reg >> g->mux_bit) & 7;
drive = (ctl_reg >> g->drv_bit) & 7;
set->drv = msm_regval_to_drive(drive);
set->pull = (ctl_reg >> g->pull_bit) & 3;
if (set->is_out)
set->val = !!(io_reg & BIT(g->out_bit));
else
set->val = !!(io_reg & BIT(g->in_bit));
}
#endif
#if IS_ENABLED(CONFIG_SEC_GPIO_DVS)
/****************************************************************/
/* Pre-defined variables. (DO NOT CHANGE THIS!!) */
static unsigned char checkgpiomap_result[GDVS_PHONE_STATUS_MAX][AP_GPIO_MAX];
static struct gpiomap_result gpiomap_result = {
.init = checkgpiomap_result[PHONE_INIT],
.sleep = checkgpiomap_result[PHONE_SLEEP]
};
static void msm_check_gpio_status(unsigned char phonestate)
{
struct gpio_chip *gp;
struct gpiomux_setting set;
int i;
u8 temp_io = 0, temp_pdpu = 0, temp_lh = 0;
if (!msm_pinctrl_data) {
pr_err("pinctrl data is not available\n");
return;
}
gp = &msm_pinctrl_data->chip;
pr_info("[dvs_%s] state : %s\n", __func__,
(phonestate == PHONE_INIT) ? "init" : "sleep");
for (i = 0; i < AP_GPIO_MAX; i++) {
/* If it is not valid gpio or secure, Shows IN/PD/L */
if (!gpiochip_line_is_valid(gp, i)) {
checkgpiomap_result[phonestate][i] =
GET_RESULT_GPIO(0x1, 0x1, 0x0);
continue;
}
msm_gp_get_all(gp, i, &set);
if (set.func == 0) {
if (set.is_out)
temp_io = 0x02; /* GPIO_OUT */
else
temp_io = 0x01; /* GPIO_IN */
} else
temp_io = 0x0; /* FUNC */
switch (set.pull) {
case MSM_NO_PULL:
temp_pdpu = 0x00;
break;
case MSM_PULL_DOWN:
temp_pdpu = 0x01;
break;
/*
* gpiodvs is only for samsung,
* so pull definition could be different from original value.
* gpiodvs definition: PU(0x2), KEEPER(0x3)
*/
case MSM_PULL_UP:
temp_pdpu = 0x02;
break;
case MSM_KEEPER:
temp_pdpu = 0x03;
break;
default:
temp_pdpu = 0x07;
break;
}
temp_lh = set.val;
checkgpiomap_result[phonestate][i] =
GET_RESULT_GPIO(temp_io, temp_pdpu, temp_lh);
}
pr_info("[dvs_%s]-\n", __func__);
}
static struct gpio_dvs_t msm_gpio_dvs = {
.result = &gpiomap_result,
.check_gpio_status = msm_check_gpio_status,
.count = AP_GPIO_MAX,
.check_sleep = false,
};
const struct secgpio_dvs_data msm_gpio_dvs_data = {
.gpio_dvs = &msm_gpio_dvs,
};
EXPORT_SYMBOL_GPL(msm_gpio_dvs_data);
#endif /* CONFIG_SEC_GPIO_DVS */
#if IS_ENABLED(CONFIG_SEC_GPIO_DUMP)
static const char * const gpiomux_func_str[] = {
"GPIO",
"Func_1",
"Func_2",
"Func_3",
"Func_4",
"Func_5",
"Func_6",
"Func_7",
"Func_8",
"Func_9",
"Func_a",
"Func_b",
"Func_c",
"Func_d",
"Func_e",
"Func_f",
};
static const char * const gpiomux_pull_str[] = {
"PULL_NONE",
"PULL_DOWN",
"PULL_KEEPER",
"PULL_UP",
};
static const char * const gpiomux_dir_str[] = {
"IN",
"OUT",
};
static const char * const gpiomux_val_str[] = {
"LOW",
"HIGH",
};
void sec_ap_gpio_debug_print(void)
{
struct gpio_chip *gp;
struct gpiomux_setting set = {0,};
int i;
if (!msm_pinctrl_data) {
pr_err("pinctrl data is not available\n");
return;
}
gp = &msm_pinctrl_data->chip;
for (i = 0; i < AP_GPIO_MAX; i++) {
if (!gpiochip_line_is_valid(gp, i))
continue;
msm_gp_get_all(gp, i, &set);
pr_info("GPIO[%u] %10s %10s %13s DRV_%dmA %10s\n",
i,
gpiomux_func_str[set.func],
gpiomux_dir_str[set.is_out],
gpiomux_pull_str[set.pull],
set.drv,
gpiomux_val_str[set.val]);
}
}
EXPORT_SYMBOL(sec_ap_gpio_debug_print);
#endif /* CONFIG_SEC_GPIO_DUMP */
#ifdef CONFIG_DEBUG_FS
static void msm_gpio_dbg_show_one(struct seq_file *s,
@@ -669,40 +991,13 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
int pull;
int val;
int egpio_enable;
u32 ctl_reg, io_reg;
static const char * const pulls_keeper[] = {
"no pull",
"pull down",
"keeper",
"pull up"
};
static const char * const pulls_no_keeper[] = {
"no pull",
"pull down",
"pull up",
};
if (!gpiochip_line_is_valid(chip, offset))
return;
g = &pctrl->soc->groups[offset];
ctl_reg = msm_readl_ctl(pctrl, g);
io_reg = msm_readl_io(pctrl, g);
is_out = !!(ctl_reg & BIT(g->oe_bit));
func = (ctl_reg >> g->mux_bit) & 7;
drive = (ctl_reg >> g->drv_bit) & 7;
pull = (ctl_reg >> g->pull_bit) & 3;
egpio_enable = 0;
if (pctrl->soc->egpio_func && ctl_reg & BIT(g->egpio_present))
egpio_enable = !(ctl_reg & BIT(g->egpio_enable));
if (is_out)
val = !!(io_reg & BIT(g->out_bit));
else
val = !!(io_reg & BIT(g->in_bit));
msm_gpio_pin_status_get(pctrl, g, offset, &is_out, &func,
&drive, &pull, &egpio_enable, &val);
if (egpio_enable) {
seq_printf(s, " %-8s: egpio\n", g->grp.name);
@@ -732,6 +1027,39 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
#define msm_gpio_dbg_show NULL
#endif
static void msm_gpio_log_pin_status(struct gpio_chip *chip, unsigned int offset)
{
const struct msm_pingroup *g;
struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
unsigned int func;
int is_out;
int drive;
int pull;
int val;
int egpio_enable;
if (!gpiochip_line_is_valid(chip, offset))
return;
g = &pctrl->soc->groups[offset];
msm_gpio_pin_status_get(pctrl, g, offset, &is_out, &func,
&drive, &pull, &egpio_enable, &val);
printk_deferred("%s: %s, %s, func%d, %dmA, %s\n",
g->grp.name, is_out ? "out" : "in",
val ? "high" : "low", func,
msm_regval_to_drive(drive),
pctrl->soc->pull_no_keeper ? pulls_no_keeper[pull] : pulls_keeper[pull]);
}
static void msm_gpios_status(struct gpio_chip *chip)
{
unsigned int i;
for (i = 0; i < chip->ngpio; i++)
msm_gpio_log_pin_status(chip, i);
}
static int msm_gpio_init_valid_mask(struct gpio_chip *gc,
unsigned long *valid_mask,
unsigned int ngpios)
@@ -740,6 +1068,8 @@ static int msm_gpio_init_valid_mask(struct gpio_chip *gc,
int ret;
unsigned int len, i;
const int *reserved = pctrl->soc->reserved_gpios;
struct property *prop;
const __be32 *p;
u16 *tmp;
/* Remove driver-provided reserved GPIOs from valid_mask */
@@ -755,6 +1085,17 @@ static int msm_gpio_init_valid_mask(struct gpio_chip *gc,
return 0;
}
if (of_property_count_u32_elems(pctrl->dev->of_node, "qcom,gpios-reserved") > 0) {
bitmap_fill(valid_mask, ngpios);
of_property_for_each_u32(pctrl->dev->of_node, "qcom,gpios-reserved", prop, p, i) {
if (i >= ngpios) {
dev_err(pctrl->dev, "invalid list of reserved GPIOs\n");
return -EINVAL;
}
clear_bit(i, valid_mask);
}
}
/* The number of GPIOs in the ACPI tables */
len = ret = device_property_count_u16(pctrl->dev, "gpios");
if (ret < 0)
@@ -1298,6 +1639,8 @@ static int msm_gpio_wakeirq(struct gpio_chip *gc,
{
struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
const struct msm_gpio_wakeirq_map *map;
const struct msm_pingroup *g;
u32 intr_cfg;
int i;
*parent = GPIO_NO_WAKE_IRQ;
@@ -1311,15 +1654,40 @@ static int msm_gpio_wakeirq(struct gpio_chip *gc,
}
}
/*
* Additionally set intr_wakeup_enable_bit for the GPIOs Routed
* to parent irqchip depending on intr_wakeup_present_bit.
*/
if (*parent != GPIO_NO_WAKE_IRQ) {
g = &pctrl->soc->groups[child];
if (!g->intr_wakeup_present_bit)
return 0;
intr_cfg = msm_readl_intr_cfg(pctrl, g);
if (intr_cfg & BIT(g->intr_wakeup_present_bit)) {
intr_cfg |= BIT(g->intr_wakeup_enable_bit);
msm_writel_intr_cfg(intr_cfg, pctrl, g);
}
}
return 0;
}
static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)
{
bool have_reserved, have_gpios;
if (pctrl->soc->reserved_gpios)
return true;
return device_property_count_u16(pctrl->dev, "gpios") > 0;
have_reserved = of_property_count_u32_elems(pctrl->dev->of_node, "qcom,gpios-reserved") > 0;
have_gpios = device_property_count_u16(pctrl->dev, "gpios") > 0;
if (have_reserved && have_gpios)
dev_warn(pctrl->dev, "qcom,gpios-reserved and gpios are both defined. Only one should be used.\n");
return have_reserved || have_gpios;
}
static const struct irq_chip msm_gpio_irq_chip = {
@@ -1478,6 +1846,203 @@ SIMPLE_DEV_PM_OPS(msm_pinctrl_dev_pm_ops, msm_pinctrl_suspend,
EXPORT_SYMBOL(msm_pinctrl_dev_pm_ops);
void debug_pintctrl_msm_enable(void)
{
pinctrl_msm_log_mask = true;
}
EXPORT_SYMBOL(debug_pintctrl_msm_enable);
void debug_pintctrl_msm_disable(void)
{
pinctrl_msm_log_mask = false;
}
EXPORT_SYMBOL(debug_pintctrl_msm_disable);
static __maybe_unused int noirq_msm_pinctrl_suspend(struct device *dev)
{
struct msm_pinctrl *pctrl = dev_get_drvdata(dev);
if (pinctrl_msm_log_mask) {
printk_deferred("%s\n", pctrl->chip.label);
msm_gpios_status(&pctrl->chip);
}
return 0;
}
const struct dev_pm_ops noirq_msm_pinctrl_dev_pm_ops = {
.suspend_noirq = noirq_msm_pinctrl_suspend,
};
EXPORT_SYMBOL(noirq_msm_pinctrl_dev_pm_ops);
/*
* msm_gpio_mpm_wake_set - API to make interrupt wakeup capable
* @dev: Device corrsponding to pinctrl
* @gpio: Gpio number to make interrupt wakeup capable
* @enable: Enable/Disable wakeup capability
*/
int msm_gpio_mpm_wake_set(unsigned int gpio, bool enable)
{
const struct msm_pingroup *g;
unsigned long flags;
u32 val, intr_cfg;
g = &msm_pinctrl_data->soc->groups[gpio];
if (g->wake_bit == -1 && !g->intr_wakeup_present_bit)
return -ENOENT;
raw_spin_lock_irqsave(&msm_pinctrl_data->lock, flags);
intr_cfg = msm_readl_intr_cfg(msm_pinctrl_data, g);
if (intr_cfg & BIT(g->intr_wakeup_present_bit)) {
if (enable)
intr_cfg |= BIT(g->intr_wakeup_enable_bit);
else
intr_cfg &= ~BIT(g->intr_wakeup_enable_bit);
msm_writel_intr_cfg(intr_cfg, msm_pinctrl_data, g);
goto exit;
}
val = readl_relaxed(msm_pinctrl_data->regs[g->tile] + g->wake_reg);
if (enable)
val |= BIT(g->wake_bit);
else
val &= ~BIT(g->wake_bit);
writel_relaxed(val, msm_pinctrl_data->regs[g->tile] + g->wake_reg);
exit:
raw_spin_unlock_irqrestore(&msm_pinctrl_data->lock, flags);
return 0;
}
EXPORT_SYMBOL(msm_gpio_mpm_wake_set);
/*
* msm_gpio_get_pin_address - API to get GPIO physical address range
* @gpio_num: global GPIO num, as returned from gpio apis - desc_to_gpio().
* @res: Out param. Resource struct with start/end addr populated.
* @ret: true if the pin is valid, false otherwise.
*/
bool msm_gpio_get_pin_address(unsigned int gpio_num, struct resource *res)
{
struct gpio_chip *chip;
const struct msm_pingroup *g;
struct resource *tile_res;
struct platform_device *pdev;
unsigned int gpio;
if (!msm_pinctrl_data) {
pr_err("pinctrl data is not available\n");
return false;
}
chip = &msm_pinctrl_data->chip;
pdev = to_platform_device(msm_pinctrl_data->dev);
gpio = gpio_num - chip->base;
if (!gpiochip_line_is_valid(chip, gpio))
return false;
if (!res)
return false;
g = &msm_pinctrl_data->soc->groups[gpio];
if (msm_pinctrl_data->soc->tiles)
tile_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
msm_pinctrl_data->soc->tiles[g->tile]);
else
tile_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!tile_res) {
dev_err(&pdev->dev, "failed to get resource\n");
return false;
}
res->start = tile_res->start + g->ctl_reg;
res->end = res->start + (g->reg_size_4k ? : DEFAULT_REG_SIZE_4K) * SZ_4K - 1;
return true;
}
EXPORT_SYMBOL(msm_gpio_get_pin_address);
int msm_qup_write(u32 mode, u32 val)
{
int i;
struct pinctrl_qup *regs = msm_pinctrl_data->soc->qup_regs;
int num_regs = msm_pinctrl_data->soc->nqup_regs;
/*Iterate over modes*/
for (i = 0; i < num_regs; i++) {
if (regs[i].mode == mode) {
writel_relaxed(val & QUP_MASK,
msm_pinctrl_data->regs[0] + regs[i].offset);
return 0;
}
}
return -ENOENT;
}
EXPORT_SYMBOL(msm_qup_write);
int msm_qup_read(unsigned int mode)
{
int i, val;
struct pinctrl_qup *regs = msm_pinctrl_data->soc->qup_regs;
int num_regs = msm_pinctrl_data->soc->nqup_regs;
/*Iterate over modes*/
for (i = 0; i < num_regs; i++) {
if (regs[i].mode == mode) {
val = readl_relaxed(msm_pinctrl_data->regs[0] +
regs[i].offset);
return val & QUP_MASK;
}
}
return -ENOENT;
}
EXPORT_SYMBOL(msm_qup_read);
int msm_spare_write(int spare_reg, u32 val)
{
u32 offset;
const struct msm_spare_tlmm *regs = msm_pinctrl_data->soc->spare_regs;
int num_regs = msm_pinctrl_data->soc->nspare_regs;
if (!regs || spare_reg >= num_regs)
return -ENOENT;
offset = regs[spare_reg].offset;
if (offset != 0) {
writel_relaxed(val & SPARE_MASK,
msm_pinctrl_data->regs[0] + offset);
return 0;
}
return -ENOENT;
}
EXPORT_SYMBOL_GPL(msm_spare_write);
int msm_spare_read(int spare_reg)
{
u32 offset, val;
const struct msm_spare_tlmm *regs = msm_pinctrl_data->soc->spare_regs;
int num_regs = msm_pinctrl_data->soc->nspare_regs;
if (!regs || spare_reg >= num_regs)
return -ENOENT;
offset = regs[spare_reg].offset;
if (offset != 0) {
val = readl_relaxed(msm_pinctrl_data->regs[0] + offset);
return val & SPARE_MASK;
}
return -ENOENT;
}
EXPORT_SYMBOL_GPL(msm_spare_read);
int msm_pinctrl_probe(struct platform_device *pdev,
const struct msm_pinctrl_soc_data *soc_data)
{
@@ -1486,7 +2051,7 @@ int msm_pinctrl_probe(struct platform_device *pdev,
int ret;
int i;
pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
msm_pinctrl_data = pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
if (!pctrl)
return -ENOMEM;
@@ -1528,6 +2093,8 @@ int msm_pinctrl_probe(struct platform_device *pdev,
pctrl->desc.name = dev_name(&pdev->dev);
pctrl->desc.pins = pctrl->soc->pins;
pctrl->desc.npins = pctrl->soc->npins;
pctrl->desc.num_custom_params = ARRAY_SIZE(msm_gpio_bindings);
pctrl->desc.custom_params = msm_gpio_bindings;
pctrl->pctrl = devm_pinctrl_register(&pdev->dev, &pctrl->desc, pctrl);
if (IS_ERR(pctrl->pctrl)) {
@@ -1539,6 +2106,8 @@ int msm_pinctrl_probe(struct platform_device *pdev,
if (ret)
return ret;
pinctrl_msm_log_mask = false;
platform_set_drvdata(pdev, pctrl);
dev_dbg(&pdev->dev, "Probed Qualcomm pinctrl driver\n");
@@ -1559,5 +2128,6 @@ int msm_pinctrl_remove(struct platform_device *pdev)
}
EXPORT_SYMBOL(msm_pinctrl_remove);
MODULE_SOFTDEP("pre: qcom-pdc");
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. TLMM driver");
MODULE_LICENSE("GPL v2");

View File

@@ -1,10 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2013, Sony Mobile Communications AB.
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef __PINCTRL_MSM_H__
#define __PINCTRL_MSM_H__
#include <linux/pinctrl/qcom-pinctrl.h>
#include <linux/pm.h>
#include <linux/types.h>
@@ -48,6 +51,7 @@ struct pinctrl_pin_desc;
* @intr_status_reg: Offset of the register holding the status bits for this group.
* @intr_target_reg: Offset of the register specifying routing of the interrupts
* from this group.
* @reg_size_4k: Size of the group register space in 4k granularity.
* @mux_bit: Offset in @ctl_reg for the pinmux function selection.
* @pull_bit: Offset in @ctl_reg for the bias configuration.
* @drv_bit: Offset in @ctl_reg for the drive strength configuration.
@@ -68,6 +72,8 @@ struct pinctrl_pin_desc;
* @intr_detection_width: Number of bits used for specifying interrupt type,
* Should be 2 for SoCs that can detect both edges in hardware,
* otherwise 1.
* @wake_reg: Offset of the WAKEUP_INT_EN register from base tile
* @wake_bit: Bit number for the corresponding gpio
*/
struct msm_pingroup {
struct pingroup grp;
@@ -80,6 +86,7 @@ struct msm_pingroup {
u32 intr_cfg_reg;
u32 intr_status_reg;
u32 intr_target_reg;
unsigned int reg_size_4k:5;
unsigned int tile:2;
@@ -101,12 +108,17 @@ struct msm_pingroup {
unsigned intr_ack_high:1;
unsigned intr_target_bit:5;
unsigned intr_wakeup_enable_bit:5;
unsigned intr_wakeup_present_bit:5;
unsigned intr_target_width:5;
unsigned intr_target_kpss_val:5;
unsigned intr_raw_status_bit:5;
unsigned intr_polarity_bit:5;
unsigned intr_detection_bit:5;
unsigned intr_detection_width:5;
u32 wake_reg;
unsigned int wake_bit;
};
/**
@@ -119,6 +131,26 @@ struct msm_gpio_wakeirq_map {
unsigned int wakeirq;
};
/*
* struct pinctrl_qup - Qup mode configuration
* @mode: Qup i3c mode
* @offset: Offset of the register
*/
struct pinctrl_qup {
u32 mode;
u32 offset;
};
/*
* struct msm_spare_tlmm - TLMM spare registers config
* @spare_reg: spare register number
* @offset: Offset of spare register
*/
struct msm_spare_tlmm {
int spare_reg;
u32 offset;
};
/**
* struct msm_pinctrl_soc_data - Qualcomm pin controller driver configuration
* @pins: An array describing all pins the pin controller affects.
@@ -158,11 +190,16 @@ struct msm_pinctrl_soc_data {
const struct msm_gpio_wakeirq_map *wakeirq_map;
unsigned int nwakeirq_map;
bool wakeirq_dual_edge_errata;
struct pinctrl_qup *qup_regs;
unsigned int nqup_regs;
unsigned int gpio_func;
unsigned int egpio_func;
const struct msm_spare_tlmm *spare_regs;
unsigned int nspare_regs;
};
extern const struct dev_pm_ops msm_pinctrl_dev_pm_ops;
extern const struct dev_pm_ops noirq_msm_pinctrl_dev_pm_ops;
int msm_pinctrl_probe(struct platform_device *pdev,
const struct msm_pinctrl_soc_data *soc_data);

View File

@@ -0,0 +1,81 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022, 2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinctrl.h>
#include "pinctrl-msm.h"
#include "pinctrl-parrot.h"
static const struct msm_pinctrl_soc_data parrot_tlmm = {
.pins = parrot_pins,
.npins = ARRAY_SIZE(parrot_pins),
.functions = parrot_functions,
.nfunctions = ARRAY_SIZE(parrot_functions),
.groups = parrot_groups,
.ngroups = ARRAY_SIZE(parrot_groups),
.ngpios = 142,
.wakeirq_map = parrot_pdc_map,
.nwakeirq_map = ARRAY_SIZE(parrot_pdc_map),
.egpio_func = 11,
};
static const struct msm_pinctrl_soc_data parrot_vm_tlmm = {
.pins = parrot_pins,
.npins = ARRAY_SIZE(parrot_pins),
.functions = parrot_functions,
.nfunctions = ARRAY_SIZE(parrot_functions),
.groups = parrot_groups,
.ngroups = ARRAY_SIZE(parrot_groups),
.ngpios = 142,
.egpio_func = 11,
};
static int parrot_tlmm_probe(struct platform_device *pdev)
{
const struct msm_pinctrl_soc_data *pinctrl_data;
pinctrl_data = of_device_get_match_data(&pdev->dev);
if (!pinctrl_data)
return -EINVAL;
return msm_pinctrl_probe(pdev, pinctrl_data);
}
static const struct of_device_id parrot_tlmm_of_match[] = {
{ .compatible = "qcom,parrot-tlmm", .data = &parrot_tlmm},
{ .compatible = "qcom,parrot-vm-tlmm", .data = &parrot_vm_tlmm},
{ },
};
static struct platform_driver parrot_tlmm_driver = {
.driver = {
.name = "parrot-pinctrl",
.of_match_table = parrot_tlmm_of_match,
},
.probe = parrot_tlmm_probe,
.remove = msm_pinctrl_remove,
};
static int __init parrot_tlmm_init(void)
{
return platform_driver_register(&parrot_tlmm_driver);
}
arch_initcall(parrot_tlmm_init);
static void __exit parrot_tlmm_exit(void)
{
platform_driver_unregister(&parrot_tlmm_driver);
}
module_exit(parrot_tlmm_exit);
MODULE_DESCRIPTION("QTI parrot TLMM driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(of, parrot_tlmm_of_match);
MODULE_SOFTDEP("pre: qcom_tlmm_vm_irqchip");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,78 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022, 2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinctrl.h>
#include "pinctrl-msm.h"
#include "pinctrl-ravelin.h"
static const struct msm_pinctrl_soc_data ravelin_tlmm = {
.pins = ravelin_pins,
.npins = ARRAY_SIZE(ravelin_pins),
.functions = ravelin_functions,
.nfunctions = ARRAY_SIZE(ravelin_functions),
.groups = ravelin_groups,
.ngroups = ARRAY_SIZE(ravelin_groups),
.ngpios = 137,
.wakeirq_map = ravelin_pdc_map,
.nwakeirq_map = ARRAY_SIZE(ravelin_pdc_map),
};
static const struct msm_pinctrl_soc_data ravelin_vm_tlmm = {
.pins = ravelin_pins,
.npins = ARRAY_SIZE(ravelin_pins),
.functions = ravelin_functions,
.nfunctions = ARRAY_SIZE(ravelin_functions),
.groups = ravelin_groups,
.ngroups = ARRAY_SIZE(ravelin_groups),
.ngpios = 137,
};
static int ravelin_tlmm_probe(struct platform_device *pdev)
{
const struct msm_pinctrl_soc_data *pinctrl_data;
pinctrl_data = of_device_get_match_data(&pdev->dev);
if (!pinctrl_data)
return -EINVAL;
return msm_pinctrl_probe(pdev, pinctrl_data);
}
static const struct of_device_id ravelin_tlmm_of_match[] = {
{ .compatible = "qcom,ravelin-tlmm", .data = &ravelin_tlmm},
{ .compatible = "qcom,ravelin-vm-tlmm", .data = &ravelin_vm_tlmm},
{ },
};
static struct platform_driver ravelin_tlmm_driver = {
.driver = {
.name = "ravelin-tlmm",
.of_match_table = ravelin_tlmm_of_match,
},
.probe = ravelin_tlmm_probe,
.remove = msm_pinctrl_remove,
};
static int __init ravelin_tlmm_init(void)
{
return platform_driver_register(&ravelin_tlmm_driver);
}
arch_initcall(ravelin_tlmm_init);
static void __exit ravelin_tlmm_exit(void)
{
platform_driver_unregister(&ravelin_tlmm_driver);
}
module_exit(ravelin_tlmm_exit);
MODULE_DESCRIPTION("QTI ravelin tlmm driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(of, ravelin_tlmm_of_match);
MODULE_SOFTDEP("pre: qcom_tlmm_vm_irqchip");

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2014, 2016-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/gpio/driver.h>
@@ -139,6 +139,7 @@ enum pmic_gpio_func_index {
* struct pmic_gpio_pad - keep current GPIO settings
* @base: Address base in SPMI device.
* @is_enabled: Set to false when GPIO should be put in high Z state.
* @is_configured: Set to true if the GPIO is configured
* @out_value: Cached pin output value
* @have_buffer: Set to true if GPIO output could be configured in push-pull,
* open-drain or open-source mode.
@@ -158,6 +159,7 @@ enum pmic_gpio_func_index {
struct pmic_gpio_pad {
u16 base;
bool is_enabled;
bool is_configured;
bool out_value;
bool have_buffer;
bool output_enabled;
@@ -329,6 +331,7 @@ static int pmic_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned function,
}
pad->function = function;
pad->is_configured = true;
if (pad->analog_pass)
val = PMIC_GPIO_MODE_ANALOG_PASS_THRU;
@@ -485,6 +488,7 @@ static int pmic_gpio_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
pad = pctldev->desc->pins[pin].drv_data;
pad->is_enabled = true;
pad->is_configured = true;
for (i = 0; i < nconfs; i++) {
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
@@ -713,6 +717,90 @@ static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev,
}
}
#if IS_ENABLED(CONFIG_SEC_GPIO_DUMP)
#define MAX_PMIC 32
static int pmic_count;
static struct gpio_chip *pmic_gpio_chip[MAX_PMIC];
static void pmic_gpio_sec_dbg_print(struct pinctrl_dev *pctldev)
{
struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev);
struct pmic_gpio_pad *pad;
int val, ret, function;
int index;
static const char *const biases[] = {
"pull-up 30uA", "pull-up 1.5uA", "pull-up 31.5uA",
"pull-up 1.5uA + 30uA boost", "pull-down 10uA", "no pull"
};
static const char *const buffer_types[] = {
"push-pull", "open-drain", "open-source"
};
static const char *const strengths[] = {
"no", "high", "medium", "low"
};
pr_info("%s: chip.label:%s\n", __func__, state->chip.label);
for (index = 0; index < state->chip.ngpio; index++) {
pad = pctldev->desc->pins[index].drv_data;
val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_EN_CTL);
if (val < 0 || !(val >> PMIC_GPIO_REG_MASTER_EN_SHIFT)) {
pr_info(" gpio%-2d: ---\n", index);
continue;
}
if (pad->input_enabled) {
ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS);
if (ret < 0)
continue;
ret &= PMIC_MPP_REG_RT_STS_VAL_MASK;
pad->out_value = ret;
}
if (!pad->lv_mv_type &&
pad->function >= PMIC_GPIO_FUNC_INDEX_FUNC3) {
function = pad->function + (PMIC_GPIO_FUNC_INDEX_DTEST1 -
PMIC_GPIO_FUNC_INDEX_FUNC3);
} else {
function = pad->function;
}
pr_info(" gpio%-2d: %-7s %-4s vin-%d %-27s %-10s %-2s %-7s atest-%d dtest-%d\n",
index,
pmic_gpio_functions[function],
pad->output_enabled ? "OUT" : "IN",
pad->power_source,
biases[pad->pullup],
buffer_types[pad->buffer_type],
pad->out_value ? "H" : "L",
strengths[pad->strength],
pad->atest,
pad->dtest_buffer);
}
pr_info("\n");
}
static void pmic_gpio_sec_dbg_show(struct gpio_chip *chip)
{
struct pmic_gpio_state *state = gpiochip_get_data(chip);
pmic_gpio_sec_dbg_print(state->ctrl);
}
void sec_pmic_gpio_debug_print(void)
{
unsigned int i;
for (i = 0; i < pmic_count; i++)
pmic_gpio_sec_dbg_show(pmic_gpio_chip[i]);
}
EXPORT_SYMBOL_GPL(sec_pmic_gpio_debug_print);
#endif /* CONFIG_SEC_GPIO_DUMP */
static const struct pinconf_ops pmic_gpio_pinconf_ops = {
.is_generic = true,
.pin_config_group_get = pmic_gpio_config_get,
@@ -808,6 +896,33 @@ static const struct gpio_chip pmic_gpio_gpio_template = {
.dbg_show = pmic_gpio_dbg_show,
};
static int __maybe_unused pmic_gpio_restore(struct device *dev)
{
struct pmic_gpio_state *state = dev_get_drvdata(dev);
struct pinctrl_dev *ctrl = state->ctrl;
struct pmic_gpio_pad *pad;
unsigned int i, npins = ctrl->desc->npins;
int ret = 0;
for (i = 0; i < npins; i++) {
pad = ctrl->desc->pins[i].drv_data;
if (pad->is_configured) {
ret = pmic_gpio_config_set(ctrl, i, NULL, 0);
if (ret < 0) {
dev_err(state->dev, "Failed to restore pin %s[%d] ret=%d\n",
ctrl->desc->pins[i].name, i, ret);
return ret;
}
}
}
return ret;
}
static const struct dev_pm_ops __maybe_unused pmic_gpio_pm_ops = {
.restore = pm_ptr(pmic_gpio_restore),
};
static int pmic_gpio_populate(struct pmic_gpio_state *state,
struct pmic_gpio_pad *pad)
{
@@ -961,6 +1076,7 @@ static int pmic_gpio_populate(struct pmic_gpio_state *state,
/* Pin could be disabled with PIN_CONFIG_BIAS_HIGH_IMPEDANCE */
pad->is_enabled = true;
pad->is_configured = false;
return 0;
}
@@ -1129,6 +1245,11 @@ static int pmic_gpio_probe(struct platform_device *pdev)
state->chip.of_gpio_n_cells = 2;
state->chip.can_sleep = false;
#if IS_ENABLED(CONFIG_SEC_GPIO_DUMP)
pr_info("%s: [%d]chip.label:%s\n", __func__, pmic_count, state->chip.label);
pmic_gpio_chip[pmic_count++] = &(state->chip);
#endif
state->ctrl = devm_pinctrl_register(dev, pctrldesc, state);
if (IS_ERR(state->ctrl))
return PTR_ERR(state->ctrl);
@@ -1203,6 +1324,7 @@ static const struct of_device_id pmic_gpio_of_match[] = {
{ .compatible = "qcom,pm6150-gpio", .data = (void *) 10 },
{ .compatible = "qcom,pm6150l-gpio", .data = (void *) 12 },
{ .compatible = "qcom,pm6350-gpio", .data = (void *) 9 },
{ .compatible = "qcom,pm6450-gpio", .data = (void *) 9 },
{ .compatible = "qcom,pm7250b-gpio", .data = (void *) 12 },
{ .compatible = "qcom,pm7325-gpio", .data = (void *) 10 },
{ .compatible = "qcom,pm7550ba-gpio", .data = (void *) 8},
@@ -1235,10 +1357,13 @@ static const struct of_device_id pmic_gpio_of_match[] = {
{ .compatible = "qcom,pm8994-gpio", .data = (void *) 22 },
{ .compatible = "qcom,pm8998-gpio", .data = (void *) 26 },
{ .compatible = "qcom,pma8084-gpio", .data = (void *) 22 },
{ .compatible = "qcom,pmd802x-gpio", .data = (void *) 4 },
{ .compatible = "qcom,pmi632-gpio", .data = (void *) 8 },
{ .compatible = "qcom,pmi8950-gpio", .data = (void *) 2 },
{ .compatible = "qcom,pmi8994-gpio", .data = (void *) 10 },
{ .compatible = "qcom,pmi8998-gpio", .data = (void *) 14 },
{ .compatible = "qcom,pmih010x-gpio", .data = (void *) 18 },
{ .compatible = "qcom,pmiv0108-gpio", .data = (void *) 10 },
{ .compatible = "qcom,pmk8350-gpio", .data = (void *) 4 },
{ .compatible = "qcom,pmk8550-gpio", .data = (void *) 6 },
{ .compatible = "qcom,pmm8155au-gpio", .data = (void *) 10 },
@@ -1254,6 +1379,8 @@ static const struct of_device_id pmic_gpio_of_match[] = {
{ .compatible = "qcom,pmx55-gpio", .data = (void *) 11 },
{ .compatible = "qcom,pmx65-gpio", .data = (void *) 16 },
{ .compatible = "qcom,pmx75-gpio", .data = (void *) 16 },
{ .compatible = "qcom,pmxr2230-gpio", .data = (void *) 12 },
{ .compatible = "qcom,pm5100-gpio", .data = (void *) 16 },
{ },
};
@@ -1263,6 +1390,7 @@ static struct platform_driver pmic_gpio_driver = {
.driver = {
.name = "qcom-spmi-gpio",
.of_match_table = pmic_gpio_of_match,
.pm = pm_ptr(&pmic_gpio_pm_ops),
},
.probe = pmic_gpio_probe,
.remove = pmic_gpio_remove,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,331 @@
/*
* Samsung Mobile VE Group.
*
* drivers/gpio/secgpio_dvs.c
*
* Drivers for samsung gpio debugging & verification.
*
* Copyright (C) 2013, 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/module.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/timer.h>
#include <linux/power_supply.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/slab.h>
#include "secgpio_dvs.h"
#include <trace/events/power.h>
/*sys fs*/
struct class *secgpio_dvs_class;
EXPORT_SYMBOL(secgpio_dvs_class);
struct device *secgpio_dotest;
EXPORT_SYMBOL(secgpio_dotest);
/* extern GPIOMAP_RESULT GpioMap_result; */
static struct gpio_dvs_t *gdvs_info;
static ssize_t checked_secgpio_file_read(
struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t checked_sleep_secgpio_file_read(
struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t checked_secgpio_init_read_details(
struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t checked_secgpio_sleep_read_details(
struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t secgpio_checked_sleepgpio_read(
struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t checked_secgpio_init_call(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len);
static DEVICE_ATTR(gpioinit_check, 0664,
checked_secgpio_file_read, NULL);
static DEVICE_ATTR(gpiosleep_check, 0664,
checked_sleep_secgpio_file_read, NULL);
static DEVICE_ATTR(check_init_detail, 0664,
checked_secgpio_init_read_details, NULL);
static DEVICE_ATTR(check_sleep_detail, 0664,
checked_secgpio_sleep_read_details, NULL);
static DEVICE_ATTR(checked_sleepGPIO, 0664,
secgpio_checked_sleepgpio_read, NULL);
static DEVICE_ATTR(gpioinit_call, 0664,
NULL, checked_secgpio_init_call);
static struct attribute *secgpio_dvs_attributes[] = {
&dev_attr_gpioinit_check.attr,
&dev_attr_gpiosleep_check.attr,
&dev_attr_check_init_detail.attr,
&dev_attr_check_sleep_detail.attr,
&dev_attr_checked_sleepGPIO.attr,
&dev_attr_gpioinit_call.attr,
NULL,
};
static struct attribute_group secgpio_dvs_attr_group = {
.attrs = secgpio_dvs_attributes,
};
static ssize_t checked_secgpio_file_read(
struct device *dev, struct device_attribute *attr, char *buf)
{
int i = 0;
char temp_buf[20];
struct gpio_dvs_t *gdvs = dev_get_drvdata(dev);
for (i = 0; i < gdvs->count; i++) {
memset(temp_buf, 0, sizeof(char)*20);
snprintf(temp_buf, 20, "%x ", gdvs->result->init[i]);
strlcat(buf, temp_buf, PAGE_SIZE);
}
return strlen(buf);
}
static ssize_t checked_sleep_secgpio_file_read(
struct device *dev, struct device_attribute *attr, char *buf)
{
int i = 0;
char temp_buf[20];
struct gpio_dvs_t *gdvs = dev_get_drvdata(dev);
for (i = 0; i < gdvs->count; i++) {
memset(temp_buf, 0, sizeof(char)*20);
snprintf(temp_buf, 20, "%x ", gdvs->result->sleep[i]);
strlcat(buf, temp_buf, PAGE_SIZE);
}
return strlen(buf);
}
static ssize_t checked_secgpio_init_read_details(
struct device *dev, struct device_attribute *attr, char *buf)
{
int i = 0;
char temp_buf[20];
struct gpio_dvs_t *gdvs = dev_get_drvdata(dev);
for (i = 0; i < gdvs->count; i++) {
memset(temp_buf, 0, sizeof(char)*20);
snprintf(temp_buf, 20, "GI[%d] - %x\n ",
i, gdvs->result->init[i]);
strlcat(buf, temp_buf, PAGE_SIZE);
}
return strlen(buf);
}
static ssize_t checked_secgpio_sleep_read_details(
struct device *dev, struct device_attribute *attr, char *buf)
{
int i = 0;
char temp_buf[20];
struct gpio_dvs_t *gdvs = dev_get_drvdata(dev);
for (i = 0; i < gdvs->count; i++) {
memset(temp_buf, 0, sizeof(char)*20);
snprintf(temp_buf, 20, "GS[%d] - %x\n ",
i, gdvs->result->sleep[i]);
strlcat(buf, temp_buf, PAGE_SIZE);
}
return strlen(buf);
}
static ssize_t secgpio_checked_sleepgpio_read(
struct device *dev, struct device_attribute *attr, char *buf)
{
struct gpio_dvs_t *gdvs = dev_get_drvdata(dev);
if (gdvs->check_sleep)
return snprintf(buf, PAGE_SIZE, "1");
else
return snprintf(buf, PAGE_SIZE, "0");
}
static ssize_t checked_secgpio_init_call(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
/* Check init gpio status */
gpio_dvs_check_initgpio();
return len;
}
void gpio_dvs_check_initgpio(void)
{
if (gdvs_info && gdvs_info->check_gpio_status)
gdvs_info->check_gpio_status(PHONE_INIT);
}
EXPORT_SYMBOL(gpio_dvs_check_initgpio);
void gpio_dvs_check_sleepgpio(void)
{
if (unlikely(gdvs_info && !gdvs_info->check_sleep)) {
gdvs_info->check_gpio_status(PHONE_SLEEP);
gdvs_info->check_sleep = true;
}
}
#ifdef CONFIG_OF
static const struct of_device_id secgpio_dvs_dt_match[] = {
{ .compatible = "samsung,secgpio-dvs",
.data = (void *)&msm_gpio_dvs_data },
{ },
};
MODULE_DEVICE_TABLE(of, secgpio_dvs_dt_match);
static struct secgpio_dvs_data *secgpio_dvs_get_soc_data(
struct platform_device *pdev)
{
const struct of_device_id *match;
struct device_node *node = pdev->dev.of_node;
struct secgpio_dvs_data *data;
match = of_match_node(secgpio_dvs_dt_match, node);
if (!match) {
dev_err(&pdev->dev, "failed to get SoC node\n");
return NULL;
}
data = (struct secgpio_dvs_data *)match->data;
if (!data) {
dev_err(&pdev->dev, "failed to get SoC data\n");
return NULL;
}
return data;
}
#else
static struct gpio_dvs_t *secgpio_dvs_get_soc_data(struct platform_device *pdev)
{
return dev_get_platdata(&pdev->dev);
}
#endif
static int secgpio_dvs_probe(struct platform_device *pdev)
{
int ret = 0;
struct class *secgpio_dvs_class;
struct device *secgpio_dotest;
struct secgpio_dvs_data *data = secgpio_dvs_get_soc_data(pdev);
struct gpio_dvs_t *gdvs;
pr_info("[secgpio_dvs] %s has been created!!!\n", __func__);
if (!data)
return -ENODEV;
gdvs = data->gpio_dvs;
secgpio_dvs_class = class_create("secgpio_check");
if (IS_ERR(secgpio_dvs_class)) {
ret = PTR_ERR(secgpio_dvs_class);
pr_err("Failed to create class(secgpio_check_all)");
goto fail_out;
}
secgpio_dotest = device_create(secgpio_dvs_class,
NULL, 0, NULL, "secgpio_check_all");
if (IS_ERR(secgpio_dotest)) {
ret = PTR_ERR(secgpio_dotest);
pr_err("Failed to create device(secgpio_check_all)");
goto fail1;
}
dev_set_drvdata(secgpio_dotest, gdvs);
gdvs_info = gdvs;
ret = sysfs_create_group(&secgpio_dotest->kobj,
&secgpio_dvs_attr_group);
if (ret) {
pr_err("Failed to create sysfs group");
goto fail2;
}
return ret;
fail2:
device_destroy(secgpio_dvs_class, 0);
fail1:
class_destroy(secgpio_dvs_class);
fail_out:
if (ret)
pr_err(" (err = %d)!\n", ret);
return ret;
}
static int secgpio_dvs_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver secgpio_dvs = {
.probe = secgpio_dvs_probe,
.remove = secgpio_dvs_remove,
.driver = {
.name = "secgpio_dvs",
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = of_match_ptr(secgpio_dvs_dt_match),
#endif
},
};
static void gpio_debug_suspend_trace_probe(void *unused,
const char *action, int val, bool start)
{
if (start && val > 0 && !strcmp("machine_suspend", action)) {
gpio_dvs_check_sleepgpio();
}
}
static int __init secgpio_dvs_init(void)
{
int ret;
ret = platform_driver_register(&secgpio_dvs);
pr_info("[secgpio_dvs] %s has been initialized!!!, ret=%d\n", __func__, ret);
/* Register callback for cheking sleep gpio status */
ret = register_trace_suspend_resume(
gpio_debug_suspend_trace_probe, NULL);
if (ret) {
pr_err("%s: Failed to register suspend trace callback, ret=%d\n",
__func__, ret);
return ret;
}
return ret;
}
static void __exit secgpio_dvs_exit(void)
{
unregister_trace_suspend_resume(
gpio_debug_suspend_trace_probe, NULL);
platform_driver_unregister(&secgpio_dvs);
}
module_init(secgpio_dvs_init);
module_exit(secgpio_dvs_exit);
MODULE_DESCRIPTION("Samsung GPIO debugging and verification");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,50 @@
/*
* secgpio_dvs.h -- Samsung GPIO debugging and verification system
*/
#ifndef __SECGPIO_DVS_H
#define __SECGPIO_DVS_H
#include <linux/types.h>
enum gdvs_phone_status {
PHONE_INIT = 0,
PHONE_SLEEP,
GDVS_PHONE_STATUS_MAX
};
enum gdvs_io_value {
GDVS_IO_FUNC = 0x00,
GDVS_IO_IN,
GDVS_IO_OUT,
};
enum gdvs_pupd_value {
GDVS_PUPD_NP = 0x00,
GDVS_PUPD_PD,
GDVS_PUPD_PU,
GDVS_PUPD_KEEPER,
GDVS_PUPD_ERR = 0x3F
};
struct gpiomap_result {
unsigned char *init;
unsigned char *sleep;
};
struct gpio_dvs_t {
struct gpiomap_result *result;
unsigned int count;
bool check_sleep;
void (*check_gpio_status)(unsigned char phonestate);
};
struct secgpio_dvs_data {
struct gpio_dvs_t *gpio_dvs;
};
void gpio_dvs_check_initgpio(void);
void gpio_dvs_check_sleepgpio(void);
extern const struct secgpio_dvs_data msm_gpio_dvs_data;
#endif /* __SECGPIO_DVS_H */