|
|
|
@@ -70,6 +70,12 @@
|
|
|
|
|
#define PADCFG0_PMODE_SHIFT 10
|
|
|
|
|
#define PADCFG0_PMODE_MASK GENMASK(13, 10)
|
|
|
|
|
#define PADCFG0_PMODE_GPIO 0
|
|
|
|
|
#define PADCFG0_GPIODIS_SHIFT 8
|
|
|
|
|
#define PADCFG0_GPIODIS_MASK GENMASK(9, 8)
|
|
|
|
|
#define PADCFG0_GPIODIS_NONE 0
|
|
|
|
|
#define PADCFG0_GPIODIS_OUTPUT 1
|
|
|
|
|
#define PADCFG0_GPIODIS_INPUT 2
|
|
|
|
|
#define PADCFG0_GPIODIS_FULL 3
|
|
|
|
|
#define PADCFG0_GPIORXDIS BIT(9)
|
|
|
|
|
#define PADCFG0_GPIOTXDIS BIT(8)
|
|
|
|
|
#define PADCFG0_GPIORXSTATE BIT(1)
|
|
|
|
@@ -108,13 +114,30 @@ struct intel_community_context {
|
|
|
|
|
#define pin_to_padno(c, p) ((p) - (c)->pin_base)
|
|
|
|
|
#define padgroup_offset(g, p) ((p) - (g)->base)
|
|
|
|
|
|
|
|
|
|
struct intel_community *intel_get_community(struct intel_pinctrl *pctrl, unsigned int pin)
|
|
|
|
|
{
|
|
|
|
|
struct intel_community *community;
|
|
|
|
|
int i;
|
|
|
|
|
#define for_each_intel_pin_community(pctrl, community) \
|
|
|
|
|
for (unsigned int __ci = 0; \
|
|
|
|
|
__ci < pctrl->ncommunities && (community = &pctrl->communities[__ci]); \
|
|
|
|
|
__ci++) \
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < pctrl->ncommunities; i++) {
|
|
|
|
|
community = &pctrl->communities[i];
|
|
|
|
|
#define for_each_intel_community_pad_group(community, grp) \
|
|
|
|
|
for (unsigned int __gi = 0; \
|
|
|
|
|
__gi < community->ngpps && (grp = &community->gpps[__gi]); \
|
|
|
|
|
__gi++) \
|
|
|
|
|
|
|
|
|
|
#define for_each_intel_pad_group(pctrl, community, grp) \
|
|
|
|
|
for_each_intel_pin_community(pctrl, community) \
|
|
|
|
|
for_each_intel_community_pad_group(community, grp)
|
|
|
|
|
|
|
|
|
|
#define for_each_intel_gpio_group(pctrl, community, grp) \
|
|
|
|
|
for_each_intel_pad_group(pctrl, community, grp) \
|
|
|
|
|
if (grp->gpio_base == INTEL_GPIO_BASE_NOMAP) {} else
|
|
|
|
|
|
|
|
|
|
const struct intel_community *intel_get_community(const struct intel_pinctrl *pctrl,
|
|
|
|
|
unsigned int pin)
|
|
|
|
|
{
|
|
|
|
|
const struct intel_community *community;
|
|
|
|
|
|
|
|
|
|
for_each_intel_pin_community(pctrl, community) {
|
|
|
|
|
if (pin >= community->pin_base &&
|
|
|
|
|
pin < community->pin_base + community->npins)
|
|
|
|
|
return community;
|
|
|
|
@@ -129,11 +152,9 @@ static const struct intel_padgroup *
|
|
|
|
|
intel_community_get_padgroup(const struct intel_community *community,
|
|
|
|
|
unsigned int pin)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < community->ngpps; i++) {
|
|
|
|
|
const struct intel_padgroup *padgrp = &community->gpps[i];
|
|
|
|
|
const struct intel_padgroup *padgrp;
|
|
|
|
|
|
|
|
|
|
for_each_intel_community_pad_group(community, padgrp) {
|
|
|
|
|
if (pin >= padgrp->base && pin < padgrp->base + padgrp->size)
|
|
|
|
|
return padgrp;
|
|
|
|
|
}
|
|
|
|
@@ -161,7 +182,7 @@ static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl,
|
|
|
|
|
return community->pad_regs + reg + padno * nregs * 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned int pin)
|
|
|
|
|
static bool intel_pad_owned_by_host(const struct intel_pinctrl *pctrl, unsigned int pin)
|
|
|
|
|
{
|
|
|
|
|
const struct intel_community *community;
|
|
|
|
|
const struct intel_padgroup *padgrp;
|
|
|
|
@@ -186,7 +207,7 @@ static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned int pi
|
|
|
|
|
return !(readl(padown) & PADOWN_MASK(gpp_offset));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned int pin)
|
|
|
|
|
static bool intel_pad_acpi_mode(const struct intel_pinctrl *pctrl, unsigned int pin)
|
|
|
|
|
{
|
|
|
|
|
const struct intel_community *community;
|
|
|
|
|
const struct intel_padgroup *padgrp;
|
|
|
|
@@ -212,7 +233,6 @@ static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned int pin)
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* enum - Locking variants of the pad configuration
|
|
|
|
|
*
|
|
|
|
|
* @PAD_UNLOCKED: pad is fully controlled by the configuration registers
|
|
|
|
|
* @PAD_LOCKED: pad configuration registers, except TX state, are locked
|
|
|
|
|
* @PAD_LOCKED_TX: pad configuration TX state is locked
|
|
|
|
@@ -229,9 +249,9 @@ enum {
|
|
|
|
|
PAD_LOCKED_FULL = PAD_LOCKED | PAD_LOCKED_TX,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin)
|
|
|
|
|
static int intel_pad_locked(const struct intel_pinctrl *pctrl, unsigned int pin)
|
|
|
|
|
{
|
|
|
|
|
struct intel_community *community;
|
|
|
|
|
const struct intel_community *community;
|
|
|
|
|
const struct intel_padgroup *padgrp;
|
|
|
|
|
unsigned int offset, gpp_offset;
|
|
|
|
|
u32 value;
|
|
|
|
@@ -267,19 +287,19 @@ static int intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool intel_pad_is_unlocked(struct intel_pinctrl *pctrl, unsigned int pin)
|
|
|
|
|
static bool intel_pad_is_unlocked(const struct intel_pinctrl *pctrl, unsigned int pin)
|
|
|
|
|
{
|
|
|
|
|
return (intel_pad_locked(pctrl, pin) & PAD_LOCKED) == PAD_UNLOCKED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool intel_pad_usable(struct intel_pinctrl *pctrl, unsigned int pin)
|
|
|
|
|
static bool intel_pad_usable(const struct intel_pinctrl *pctrl, unsigned int pin)
|
|
|
|
|
{
|
|
|
|
|
return intel_pad_owned_by_host(pctrl, pin) && intel_pad_is_unlocked(pctrl, pin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int intel_get_groups_count(struct pinctrl_dev *pctldev)
|
|
|
|
|
{
|
|
|
|
|
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
const struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
|
|
|
|
|
return pctrl->soc->ngroups;
|
|
|
|
|
}
|
|
|
|
@@ -287,7 +307,7 @@ EXPORT_SYMBOL_NS_GPL(intel_get_groups_count, PINCTRL_INTEL);
|
|
|
|
|
|
|
|
|
|
const char *intel_get_group_name(struct pinctrl_dev *pctldev, unsigned int group)
|
|
|
|
|
{
|
|
|
|
|
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
const struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
|
|
|
|
|
return pctrl->soc->groups[group].grp.name;
|
|
|
|
|
}
|
|
|
|
@@ -296,7 +316,7 @@ EXPORT_SYMBOL_NS_GPL(intel_get_group_name, PINCTRL_INTEL);
|
|
|
|
|
int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
|
|
|
|
|
const unsigned int **pins, unsigned int *npins)
|
|
|
|
|
{
|
|
|
|
|
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
const struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
|
|
|
|
|
*pins = pctrl->soc->groups[group].grp.pins;
|
|
|
|
|
*npins = pctrl->soc->groups[group].grp.npins;
|
|
|
|
@@ -364,7 +384,7 @@ static const struct pinctrl_ops intel_pinctrl_ops = {
|
|
|
|
|
|
|
|
|
|
int intel_get_functions_count(struct pinctrl_dev *pctldev)
|
|
|
|
|
{
|
|
|
|
|
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
const struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
|
|
|
|
|
return pctrl->soc->nfunctions;
|
|
|
|
|
}
|
|
|
|
@@ -372,7 +392,7 @@ EXPORT_SYMBOL_NS_GPL(intel_get_functions_count, PINCTRL_INTEL);
|
|
|
|
|
|
|
|
|
|
const char *intel_get_function_name(struct pinctrl_dev *pctldev, unsigned int function)
|
|
|
|
|
{
|
|
|
|
|
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
const struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
|
|
|
|
|
return pctrl->soc->functions[function].func.name;
|
|
|
|
|
}
|
|
|
|
@@ -381,7 +401,7 @@ EXPORT_SYMBOL_NS_GPL(intel_get_function_name, PINCTRL_INTEL);
|
|
|
|
|
int intel_get_function_groups(struct pinctrl_dev *pctldev, unsigned int function,
|
|
|
|
|
const char * const **groups, unsigned int * const ngroups)
|
|
|
|
|
{
|
|
|
|
|
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
const struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
|
|
|
|
|
*groups = pctrl->soc->functions[function].func.groups;
|
|
|
|
|
*ngroups = pctrl->soc->functions[function].func.ngroups;
|
|
|
|
@@ -429,19 +449,49 @@ static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input)
|
|
|
|
|
{
|
|
|
|
|
u32 value;
|
|
|
|
|
/**
|
|
|
|
|
* enum - Possible pad physical connections
|
|
|
|
|
* @PAD_CONNECT_NONE: pad is fully disconnected
|
|
|
|
|
* @PAD_CONNECT_INPUT: pad is in input only mode
|
|
|
|
|
* @PAD_CONNECT_OUTPUT: pad is in output only mode
|
|
|
|
|
* @PAD_CONNECT_FULL: pad is fully connected
|
|
|
|
|
*/
|
|
|
|
|
enum {
|
|
|
|
|
PAD_CONNECT_NONE = 0,
|
|
|
|
|
PAD_CONNECT_INPUT = 1,
|
|
|
|
|
PAD_CONNECT_OUTPUT = 2,
|
|
|
|
|
PAD_CONNECT_FULL = PAD_CONNECT_INPUT | PAD_CONNECT_OUTPUT,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
value = readl(padcfg0);
|
|
|
|
|
if (input) {
|
|
|
|
|
static int __intel_gpio_get_direction(u32 value)
|
|
|
|
|
{
|
|
|
|
|
switch ((value & PADCFG0_GPIODIS_MASK) >> PADCFG0_GPIODIS_SHIFT) {
|
|
|
|
|
case PADCFG0_GPIODIS_FULL:
|
|
|
|
|
return PAD_CONNECT_NONE;
|
|
|
|
|
case PADCFG0_GPIODIS_OUTPUT:
|
|
|
|
|
return PAD_CONNECT_INPUT;
|
|
|
|
|
case PADCFG0_GPIODIS_INPUT:
|
|
|
|
|
return PAD_CONNECT_OUTPUT;
|
|
|
|
|
case PADCFG0_GPIODIS_NONE:
|
|
|
|
|
return PAD_CONNECT_FULL;
|
|
|
|
|
default:
|
|
|
|
|
return -ENOTSUPP;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static u32 __intel_gpio_set_direction(u32 value, bool input, bool output)
|
|
|
|
|
{
|
|
|
|
|
if (input)
|
|
|
|
|
value &= ~PADCFG0_GPIORXDIS;
|
|
|
|
|
value |= PADCFG0_GPIOTXDIS;
|
|
|
|
|
} else {
|
|
|
|
|
value &= ~PADCFG0_GPIOTXDIS;
|
|
|
|
|
else
|
|
|
|
|
value |= PADCFG0_GPIORXDIS;
|
|
|
|
|
}
|
|
|
|
|
writel(value, padcfg0);
|
|
|
|
|
|
|
|
|
|
if (output)
|
|
|
|
|
value &= ~PADCFG0_GPIOTXDIS;
|
|
|
|
|
else
|
|
|
|
|
value |= PADCFG0_GPIOTXDIS;
|
|
|
|
|
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int __intel_gpio_get_gpio_mode(u32 value)
|
|
|
|
@@ -465,8 +515,7 @@ static void intel_gpio_set_gpio_mode(void __iomem *padcfg0)
|
|
|
|
|
value |= PADCFG0_PMODE_GPIO;
|
|
|
|
|
|
|
|
|
|
/* Disable TX buffer and enable RX (this will be input) */
|
|
|
|
|
value &= ~PADCFG0_GPIORXDIS;
|
|
|
|
|
value |= PADCFG0_GPIOTXDIS;
|
|
|
|
|
value = __intel_gpio_set_direction(value, true, false);
|
|
|
|
|
|
|
|
|
|
/* Disable SCI/SMI/NMI generation */
|
|
|
|
|
value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI);
|
|
|
|
@@ -512,12 +561,18 @@ static int intel_gpio_set_direction(struct pinctrl_dev *pctldev,
|
|
|
|
|
{
|
|
|
|
|
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
|
void __iomem *padcfg0;
|
|
|
|
|
u32 value;
|
|
|
|
|
|
|
|
|
|
padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
|
|
|
|
|
|
|
|
|
|
guard(raw_spinlock_irqsave)(&pctrl->lock);
|
|
|
|
|
|
|
|
|
|
__intel_gpio_set_direction(padcfg0, input);
|
|
|
|
|
value = readl(padcfg0);
|
|
|
|
|
if (input)
|
|
|
|
|
value = __intel_gpio_set_direction(value, true, false);
|
|
|
|
|
else
|
|
|
|
|
value = __intel_gpio_set_direction(value, false, true);
|
|
|
|
|
writel(value, padcfg0);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@@ -612,6 +667,23 @@ static int intel_config_get_pull(struct intel_pinctrl *pctrl, unsigned int pin,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int intel_config_get_high_impedance(struct intel_pinctrl *pctrl, unsigned int pin,
|
|
|
|
|
enum pin_config_param param, u32 *arg)
|
|
|
|
|
{
|
|
|
|
|
void __iomem *padcfg0;
|
|
|
|
|
u32 value;
|
|
|
|
|
|
|
|
|
|
padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
|
|
|
|
|
|
|
|
|
|
scoped_guard(raw_spinlock_irqsave, &pctrl->lock)
|
|
|
|
|
value = readl(padcfg0);
|
|
|
|
|
|
|
|
|
|
if (__intel_gpio_get_direction(value) != PAD_CONNECT_NONE)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int intel_config_get_debounce(struct intel_pinctrl *pctrl, unsigned int pin,
|
|
|
|
|
enum pin_config_param param, u32 *arg)
|
|
|
|
|
{
|
|
|
|
@@ -655,6 +727,12 @@ static int intel_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
|
|
|
|
|
return ret;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
|
|
|
|
|
ret = intel_config_get_high_impedance(pctrl, pin, param, &arg);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PIN_CONFIG_INPUT_DEBOUNCE:
|
|
|
|
|
ret = intel_config_get_debounce(pctrl, pin, param, &arg);
|
|
|
|
|
if (ret)
|
|
|
|
@@ -753,11 +831,34 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_gpio_set_high_impedance(struct intel_pinctrl *pctrl, unsigned int pin)
|
|
|
|
|
{
|
|
|
|
|
void __iomem *padcfg0;
|
|
|
|
|
u32 value;
|
|
|
|
|
|
|
|
|
|
padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
|
|
|
|
|
|
|
|
|
|
guard(raw_spinlock_irqsave)(&pctrl->lock);
|
|
|
|
|
|
|
|
|
|
value = readl(padcfg0);
|
|
|
|
|
value = __intel_gpio_set_direction(value, false, false);
|
|
|
|
|
writel(value, padcfg0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int intel_config_set_debounce(struct intel_pinctrl *pctrl,
|
|
|
|
|
unsigned int pin, unsigned int debounce)
|
|
|
|
|
{
|
|
|
|
|
void __iomem *padcfg0, *padcfg2;
|
|
|
|
|
u32 value0, value2;
|
|
|
|
|
unsigned long v;
|
|
|
|
|
|
|
|
|
|
if (debounce) {
|
|
|
|
|
v = order_base_2(debounce * NSEC_PER_USEC / DEBOUNCE_PERIOD_NSEC);
|
|
|
|
|
if (v < 3 || v > 15)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
} else {
|
|
|
|
|
v = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
padcfg2 = intel_get_padcfg(pctrl, pin, PADCFG2);
|
|
|
|
|
if (!padcfg2)
|
|
|
|
@@ -770,21 +871,15 @@ static int intel_config_set_debounce(struct intel_pinctrl *pctrl,
|
|
|
|
|
value0 = readl(padcfg0);
|
|
|
|
|
value2 = readl(padcfg2);
|
|
|
|
|
|
|
|
|
|
/* Disable glitch filter and debouncer */
|
|
|
|
|
value0 &= ~PADCFG0_PREGFRXSEL;
|
|
|
|
|
value2 &= ~(PADCFG2_DEBEN | PADCFG2_DEBOUNCE_MASK);
|
|
|
|
|
|
|
|
|
|
if (debounce) {
|
|
|
|
|
unsigned long v;
|
|
|
|
|
|
|
|
|
|
v = order_base_2(debounce * NSEC_PER_USEC / DEBOUNCE_PERIOD_NSEC);
|
|
|
|
|
if (v < 3 || v > 15)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
value2 = (value2 & ~PADCFG2_DEBOUNCE_MASK) | (v << PADCFG2_DEBOUNCE_SHIFT);
|
|
|
|
|
if (v) {
|
|
|
|
|
/* Enable glitch filter and debouncer */
|
|
|
|
|
value0 |= PADCFG0_PREGFRXSEL;
|
|
|
|
|
value2 |= v << PADCFG2_DEBOUNCE_SHIFT;
|
|
|
|
|
value2 |= PADCFG2_DEBEN;
|
|
|
|
|
} else {
|
|
|
|
|
/* Disable glitch filter and debouncer */
|
|
|
|
|
value0 &= ~PADCFG0_PREGFRXSEL;
|
|
|
|
|
value2 &= ~PADCFG2_DEBEN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
writel(value0, padcfg0);
|
|
|
|
@@ -812,6 +907,10 @@ static int intel_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
|
|
|
|
|
return ret;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
|
|
|
|
|
intel_gpio_set_high_impedance(pctrl, pin);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PIN_CONFIG_INPUT_DEBOUNCE:
|
|
|
|
|
ret = intel_config_set_debounce(pctrl, pin,
|
|
|
|
|
pinconf_to_config_argument(configs[i]));
|
|
|
|
@@ -854,34 +953,21 @@ static const struct pinctrl_desc intel_pinctrl_desc = {
|
|
|
|
|
* Return: a pin number and pointers to the community and pad group, which
|
|
|
|
|
* the pin belongs to, or negative error code if translation can't be done.
|
|
|
|
|
*/
|
|
|
|
|
static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned int offset,
|
|
|
|
|
static int intel_gpio_to_pin(const struct intel_pinctrl *pctrl, unsigned int offset,
|
|
|
|
|
const struct intel_community **community,
|
|
|
|
|
const struct intel_padgroup **padgrp)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
const struct intel_community *comm;
|
|
|
|
|
const struct intel_padgroup *grp;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < pctrl->ncommunities; i++) {
|
|
|
|
|
const struct intel_community *comm = &pctrl->communities[i];
|
|
|
|
|
int j;
|
|
|
|
|
for_each_intel_gpio_group(pctrl, comm, grp) {
|
|
|
|
|
if (offset >= grp->gpio_base && offset < grp->gpio_base + grp->size) {
|
|
|
|
|
if (community)
|
|
|
|
|
*community = comm;
|
|
|
|
|
if (padgrp)
|
|
|
|
|
*padgrp = grp;
|
|
|
|
|
|
|
|
|
|
for (j = 0; j < comm->ngpps; j++) {
|
|
|
|
|
const struct intel_padgroup *pgrp = &comm->gpps[j];
|
|
|
|
|
|
|
|
|
|
if (pgrp->gpio_base == INTEL_GPIO_BASE_NOMAP)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (offset >= pgrp->gpio_base &&
|
|
|
|
|
offset < pgrp->gpio_base + pgrp->size) {
|
|
|
|
|
int pin;
|
|
|
|
|
|
|
|
|
|
pin = pgrp->base + offset - pgrp->gpio_base;
|
|
|
|
|
if (community)
|
|
|
|
|
*community = comm;
|
|
|
|
|
if (padgrp)
|
|
|
|
|
*padgrp = pgrp;
|
|
|
|
|
|
|
|
|
|
return pin;
|
|
|
|
|
}
|
|
|
|
|
return grp->base + offset - grp->gpio_base;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -897,7 +983,7 @@ static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned int offset,
|
|
|
|
|
*
|
|
|
|
|
* Return: a GPIO offset, or negative error code if translation can't be done.
|
|
|
|
|
*/
|
|
|
|
|
static int intel_pin_to_gpio(struct intel_pinctrl *pctrl, int pin)
|
|
|
|
|
static int intel_pin_to_gpio(const struct intel_pinctrl *pctrl, int pin)
|
|
|
|
|
{
|
|
|
|
|
const struct intel_community *community;
|
|
|
|
|
const struct intel_padgroup *padgrp;
|
|
|
|
@@ -929,7 +1015,7 @@ static int intel_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
padcfg0 = readl(reg);
|
|
|
|
|
if (!(padcfg0 & PADCFG0_GPIOTXDIS))
|
|
|
|
|
if (__intel_gpio_get_direction(padcfg0) & PAD_CONNECT_OUTPUT)
|
|
|
|
|
return !!(padcfg0 & PADCFG0_GPIOTXSTATE);
|
|
|
|
|
|
|
|
|
|
return !!(padcfg0 & PADCFG0_GPIORXSTATE);
|
|
|
|
@@ -982,10 +1068,10 @@ static int intel_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
|
|
|
|
|
if (padcfg0 & PADCFG0_PMODE_MASK)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
if (padcfg0 & PADCFG0_GPIOTXDIS)
|
|
|
|
|
return GPIO_LINE_DIRECTION_IN;
|
|
|
|
|
if (__intel_gpio_get_direction(padcfg0) & PAD_CONNECT_OUTPUT)
|
|
|
|
|
return GPIO_LINE_DIRECTION_OUT;
|
|
|
|
|
|
|
|
|
|
return GPIO_LINE_DIRECTION_OUT;
|
|
|
|
|
return GPIO_LINE_DIRECTION_IN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
|
|
|
|
@@ -1171,15 +1257,16 @@ static const struct irq_chip intel_gpio_irq_chip = {
|
|
|
|
|
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl,
|
|
|
|
|
const struct intel_community *community)
|
|
|
|
|
static irqreturn_t intel_gpio_irq(int irq, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct gpio_chip *gc = &pctrl->chip;
|
|
|
|
|
unsigned int gpp;
|
|
|
|
|
const struct intel_community *community;
|
|
|
|
|
const struct intel_padgroup *padgrp;
|
|
|
|
|
struct intel_pinctrl *pctrl = data;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
for (gpp = 0; gpp < community->ngpps; gpp++) {
|
|
|
|
|
const struct intel_padgroup *padgrp = &community->gpps[gpp];
|
|
|
|
|
/* Need to check all communities for pending interrupts */
|
|
|
|
|
for_each_intel_pad_group(pctrl, community, padgrp) {
|
|
|
|
|
struct gpio_chip *gc = &pctrl->chip;
|
|
|
|
|
unsigned long pending, enabled;
|
|
|
|
|
unsigned int gpp, gpp_offset;
|
|
|
|
|
void __iomem *reg, *is;
|
|
|
|
@@ -1203,36 +1290,17 @@ static int intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl,
|
|
|
|
|
ret += pending ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static irqreturn_t intel_gpio_irq(int irq, void *data)
|
|
|
|
|
{
|
|
|
|
|
const struct intel_community *community;
|
|
|
|
|
struct intel_pinctrl *pctrl = data;
|
|
|
|
|
unsigned int i;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
/* Need to check all communities for pending interrupts */
|
|
|
|
|
for (i = 0; i < pctrl->ncommunities; i++) {
|
|
|
|
|
community = &pctrl->communities[i];
|
|
|
|
|
ret += intel_gpio_community_irq_handler(pctrl, community);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return IRQ_RETVAL(ret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_gpio_irq_init(struct intel_pinctrl *pctrl)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
const struct intel_community *community;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < pctrl->ncommunities; i++) {
|
|
|
|
|
const struct intel_community *community;
|
|
|
|
|
for_each_intel_pin_community(pctrl, community) {
|
|
|
|
|
void __iomem *reg, *is;
|
|
|
|
|
unsigned int gpp;
|
|
|
|
|
|
|
|
|
|
community = &pctrl->communities[i];
|
|
|
|
|
|
|
|
|
|
for (gpp = 0; gpp < community->ngpps; gpp++) {
|
|
|
|
|
reg = community->regs + community->ie_offset + gpp * 4;
|
|
|
|
|
is = community->regs + community->is_offset + gpp * 4;
|
|
|
|
@@ -1257,36 +1325,17 @@ static int intel_gpio_irq_init_hw(struct gpio_chip *gc)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int intel_gpio_add_community_ranges(struct intel_pinctrl *pctrl,
|
|
|
|
|
const struct intel_community *community)
|
|
|
|
|
{
|
|
|
|
|
int ret = 0, i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < community->ngpps; i++) {
|
|
|
|
|
const struct intel_padgroup *gpp = &community->gpps[i];
|
|
|
|
|
|
|
|
|
|
if (gpp->gpio_base == INTEL_GPIO_BASE_NOMAP)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev),
|
|
|
|
|
gpp->gpio_base, gpp->base,
|
|
|
|
|
gpp->size);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int intel_gpio_add_pin_ranges(struct gpio_chip *gc)
|
|
|
|
|
{
|
|
|
|
|
struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
|
|
|
|
|
int ret, i;
|
|
|
|
|
const struct intel_community *community;
|
|
|
|
|
const struct intel_padgroup *grp;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < pctrl->ncommunities; i++) {
|
|
|
|
|
struct intel_community *community = &pctrl->communities[i];
|
|
|
|
|
|
|
|
|
|
ret = intel_gpio_add_community_ranges(pctrl, community);
|
|
|
|
|
for_each_intel_gpio_group(pctrl, community, grp) {
|
|
|
|
|
ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev),
|
|
|
|
|
grp->gpio_base, grp->base,
|
|
|
|
|
grp->size);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(pctrl->dev, "failed to add GPIO pin range\n");
|
|
|
|
|
return ret;
|
|
|
|
@@ -1299,20 +1348,12 @@ static int intel_gpio_add_pin_ranges(struct gpio_chip *gc)
|
|
|
|
|
static unsigned int intel_gpio_ngpio(const struct intel_pinctrl *pctrl)
|
|
|
|
|
{
|
|
|
|
|
const struct intel_community *community;
|
|
|
|
|
const struct intel_padgroup *grp;
|
|
|
|
|
unsigned int ngpio = 0;
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < pctrl->ncommunities; i++) {
|
|
|
|
|
community = &pctrl->communities[i];
|
|
|
|
|
for (j = 0; j < community->ngpps; j++) {
|
|
|
|
|
const struct intel_padgroup *gpp = &community->gpps[j];
|
|
|
|
|
|
|
|
|
|
if (gpp->gpio_base == INTEL_GPIO_BASE_NOMAP)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (gpp->gpio_base + gpp->size > ngpio)
|
|
|
|
|
ngpio = gpp->gpio_base + gpp->size;
|
|
|
|
|
}
|
|
|
|
|
for_each_intel_gpio_group(pctrl, community, grp) {
|
|
|
|
|
if (grp->gpio_base + grp->size > ngpio)
|
|
|
|
|
ngpio = grp->gpio_base + grp->size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ngpio;
|
|
|
|
@@ -1682,7 +1723,8 @@ EXPORT_SYMBOL_NS_GPL(intel_pinctrl_get_soc_data, PINCTRL_INTEL);
|
|
|
|
|
|
|
|
|
|
static bool __intel_gpio_is_direct_irq(u32 value)
|
|
|
|
|
{
|
|
|
|
|
return (value & PADCFG0_GPIROUTIOXAPIC) && (value & PADCFG0_GPIOTXDIS) &&
|
|
|
|
|
return (value & PADCFG0_GPIROUTIOXAPIC) &&
|
|
|
|
|
(__intel_gpio_get_direction(value) == PAD_CONNECT_INPUT) &&
|
|
|
|
|
(__intel_gpio_get_gpio_mode(value) == PADCFG0_PMODE_GPIO);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|