Commit 3dda927f authored by Linus Walleij's avatar Linus Walleij

Merge branch 'ib-qcom-ssbi' into devel

parents 9aac1e33 79890c2e
...@@ -93,9 +93,8 @@ cm3605 { ...@@ -93,9 +93,8 @@ cm3605 {
vdd-supply = <&pm8058_l14>; // 2.85V vdd-supply = <&pm8058_l14>; // 2.85V
aset-gpios = <&pm8058_gpio 35 GPIO_ACTIVE_LOW>; aset-gpios = <&pm8058_gpio 35 GPIO_ACTIVE_LOW>;
capella,aset-resistance-ohms = <100000>; capella,aset-resistance-ohms = <100000>;
/* GPIO34 has interrupt 225 on the PM8058 */
/* Trig on both edges - getting close or far away */ /* Trig on both edges - getting close or far away */
interrupts-extended = <&pm8058 225 IRQ_TYPE_EDGE_BOTH>; interrupts-extended = <&pm8058_gpio 34 IRQ_TYPE_EDGE_BOTH>;
/* MPP05 analog input to the XOADC */ /* MPP05 analog input to the XOADC */
io-channels = <&xoadc 0x00 0x05>; io-channels = <&xoadc 0x00 0x05>;
io-channel-names = "aout"; io-channel-names = "aout";
...@@ -515,9 +514,8 @@ i2c@19c80000 { ...@@ -515,9 +514,8 @@ i2c@19c80000 {
ak8975@c { ak8975@c {
compatible = "asahi-kasei,ak8975"; compatible = "asahi-kasei,ak8975";
reg = <0x0c>; reg = <0x0c>;
/* FIXME: GPIO33 has interrupt 224 on the PM8058 */ interrupt-parent = <&pm8058_gpio>;
interrupt-parent = <&pm8058>; interrupts = <33 IRQ_TYPE_EDGE_RISING>;
interrupts = <224 IRQ_TYPE_EDGE_RISING>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&dragon_ak8975_gpios>; pinctrl-0 = <&dragon_ak8975_gpios>;
vid-supply = <&pm8058_lvs0>; // 1.8V vid-supply = <&pm8058_lvs0>; // 1.8V
...@@ -526,9 +524,8 @@ ak8975@c { ...@@ -526,9 +524,8 @@ ak8975@c {
bmp085@77 { bmp085@77 {
compatible = "bosch,bmp085"; compatible = "bosch,bmp085";
reg = <0x77>; reg = <0x77>;
/* FIXME: GPIO16 has interrupt 207 on the PM8058 */ interrupt-parent = <&pm8058_gpio>;
interrupt-parent = <&pm8058>; interrupts = <16 IRQ_TYPE_EDGE_RISING>;
interrupts = <207 IRQ_TYPE_EDGE_RISING>;
reset-gpios = <&tlmm 86 GPIO_ACTIVE_LOW>; reset-gpios = <&tlmm 86 GPIO_ACTIVE_LOW>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&dragon_bmp085_gpios>; pinctrl-0 = <&dragon_bmp085_gpios>;
...@@ -539,12 +536,11 @@ mpu3050@68 { ...@@ -539,12 +536,11 @@ mpu3050@68 {
compatible = "invensense,mpu3050"; compatible = "invensense,mpu3050";
reg = <0x68>; reg = <0x68>;
/* /*
* GPIO17 has interrupt 208 on the * GPIO17 is pulled high by a 10k
* PM8058, it is pulled high by a 10k
* resistor to VLOGIC so needs to be * resistor to VLOGIC so needs to be
* active low/falling edge. * active low/falling edge.
*/ */
interrupts-extended = <&pm8058 208 IRQ_TYPE_EDGE_FALLING>; interrupts-extended = <&pm8058_gpio 17 IRQ_TYPE_EDGE_FALLING>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&dragon_mpu3050_gpios>; pinctrl-0 = <&dragon_mpu3050_gpios>;
vlogic-supply = <&pm8058_lvs0>; // 1.8V vlogic-supply = <&pm8058_lvs0>; // 1.8V
...@@ -589,11 +585,10 @@ ethernet-ebi2@2,0 { ...@@ -589,11 +585,10 @@ ethernet-ebi2@2,0 {
compatible = "smsc,lan9221", "smsc,lan9115"; compatible = "smsc,lan9221", "smsc,lan9115";
reg = <2 0x0 0x100>; reg = <2 0x0 0x100>;
/* /*
* GPIO7 has interrupt 198 on the PM8058
* The second interrupt is the PME interrupt * The second interrupt is the PME interrupt
* for network wakeup, connected to the TLMM. * for network wakeup, connected to the TLMM.
*/ */
interrupts-extended = <&pm8058 198 IRQ_TYPE_EDGE_FALLING>, interrupts-extended = <&pm8058_gpio 7 IRQ_TYPE_EDGE_FALLING>,
<&tlmm 29 IRQ_TYPE_EDGE_RISING>; <&tlmm 29 IRQ_TYPE_EDGE_RISING>;
reset-gpios = <&tlmm 30 GPIO_ACTIVE_LOW>; reset-gpios = <&tlmm 30 GPIO_ACTIVE_LOW>;
vdd33a-supply = <&dragon_veth>; vdd33a-supply = <&dragon_veth>;
......
...@@ -705,50 +705,8 @@ pm8921_gpio: gpio@150 { ...@@ -705,50 +705,8 @@ pm8921_gpio: gpio@150 {
compatible = "qcom,pm8921-gpio", compatible = "qcom,pm8921-gpio",
"qcom,ssbi-gpio"; "qcom,ssbi-gpio";
reg = <0x150>; reg = <0x150>;
interrupts = <192 IRQ_TYPE_NONE>, interrupt-controller;
<193 IRQ_TYPE_NONE>, #interrupt-cells = <2>;
<194 IRQ_TYPE_NONE>,
<195 IRQ_TYPE_NONE>,
<196 IRQ_TYPE_NONE>,
<197 IRQ_TYPE_NONE>,
<198 IRQ_TYPE_NONE>,
<199 IRQ_TYPE_NONE>,
<200 IRQ_TYPE_NONE>,
<201 IRQ_TYPE_NONE>,
<202 IRQ_TYPE_NONE>,
<203 IRQ_TYPE_NONE>,
<204 IRQ_TYPE_NONE>,
<205 IRQ_TYPE_NONE>,
<206 IRQ_TYPE_NONE>,
<207 IRQ_TYPE_NONE>,
<208 IRQ_TYPE_NONE>,
<209 IRQ_TYPE_NONE>,
<210 IRQ_TYPE_NONE>,
<211 IRQ_TYPE_NONE>,
<212 IRQ_TYPE_NONE>,
<213 IRQ_TYPE_NONE>,
<214 IRQ_TYPE_NONE>,
<215 IRQ_TYPE_NONE>,
<216 IRQ_TYPE_NONE>,
<217 IRQ_TYPE_NONE>,
<218 IRQ_TYPE_NONE>,
<219 IRQ_TYPE_NONE>,
<220 IRQ_TYPE_NONE>,
<221 IRQ_TYPE_NONE>,
<222 IRQ_TYPE_NONE>,
<223 IRQ_TYPE_NONE>,
<224 IRQ_TYPE_NONE>,
<225 IRQ_TYPE_NONE>,
<226 IRQ_TYPE_NONE>,
<227 IRQ_TYPE_NONE>,
<228 IRQ_TYPE_NONE>,
<229 IRQ_TYPE_NONE>,
<230 IRQ_TYPE_NONE>,
<231 IRQ_TYPE_NONE>,
<232 IRQ_TYPE_NONE>,
<233 IRQ_TYPE_NONE>,
<234 IRQ_TYPE_NONE>,
<235 IRQ_TYPE_NONE>;
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
......
...@@ -323,13 +323,8 @@ rtc@11d { ...@@ -323,13 +323,8 @@ rtc@11d {
pmicgpio: gpio@150 { pmicgpio: gpio@150 {
compatible = "qcom,pm8018-gpio", "qcom,ssbi-gpio"; compatible = "qcom,pm8018-gpio", "qcom,ssbi-gpio";
interrupt-parent = <&pmicintc>; interrupt-controller;
interrupts = <24 IRQ_TYPE_NONE>, #interrupt-cells = <2>;
<25 IRQ_TYPE_NONE>,
<26 IRQ_TYPE_NONE>,
<27 IRQ_TYPE_NONE>,
<28 IRQ_TYPE_NONE>,
<29 IRQ_TYPE_NONE>;
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
}; };
......
...@@ -285,51 +285,8 @@ pm8058_gpio: gpio@150 { ...@@ -285,51 +285,8 @@ pm8058_gpio: gpio@150 {
compatible = "qcom,pm8058-gpio", compatible = "qcom,pm8058-gpio",
"qcom,ssbi-gpio"; "qcom,ssbi-gpio";
reg = <0x150>; reg = <0x150>;
interrupt-parent = <&pm8058>; interrupt-controller;
interrupts = <192 IRQ_TYPE_NONE>, #interrupt-cells = <2>;
<193 IRQ_TYPE_NONE>,
<194 IRQ_TYPE_NONE>,
<195 IRQ_TYPE_NONE>,
<196 IRQ_TYPE_NONE>,
<197 IRQ_TYPE_NONE>,
<198 IRQ_TYPE_NONE>,
<199 IRQ_TYPE_NONE>,
<200 IRQ_TYPE_NONE>,
<201 IRQ_TYPE_NONE>,
<202 IRQ_TYPE_NONE>,
<203 IRQ_TYPE_NONE>,
<204 IRQ_TYPE_NONE>,
<205 IRQ_TYPE_NONE>,
<206 IRQ_TYPE_NONE>,
<207 IRQ_TYPE_NONE>,
<208 IRQ_TYPE_NONE>,
<209 IRQ_TYPE_NONE>,
<210 IRQ_TYPE_NONE>,
<211 IRQ_TYPE_NONE>,
<212 IRQ_TYPE_NONE>,
<213 IRQ_TYPE_NONE>,
<214 IRQ_TYPE_NONE>,
<215 IRQ_TYPE_NONE>,
<216 IRQ_TYPE_NONE>,
<217 IRQ_TYPE_NONE>,
<218 IRQ_TYPE_NONE>,
<219 IRQ_TYPE_NONE>,
<220 IRQ_TYPE_NONE>,
<221 IRQ_TYPE_NONE>,
<222 IRQ_TYPE_NONE>,
<223 IRQ_TYPE_NONE>,
<224 IRQ_TYPE_NONE>,
<225 IRQ_TYPE_NONE>,
<226 IRQ_TYPE_NONE>,
<227 IRQ_TYPE_NONE>,
<228 IRQ_TYPE_NONE>,
<229 IRQ_TYPE_NONE>,
<230 IRQ_TYPE_NONE>,
<231 IRQ_TYPE_NONE>,
<232 IRQ_TYPE_NONE>,
<233 IRQ_TYPE_NONE>,
<234 IRQ_TYPE_NONE>,
<235 IRQ_TYPE_NONE>;
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
......
...@@ -928,7 +928,7 @@ config UCB1400_CORE ...@@ -928,7 +928,7 @@ config UCB1400_CORE
config MFD_PM8XXX config MFD_PM8XXX
tristate "Qualcomm PM8xxx PMIC chips driver" tristate "Qualcomm PM8xxx PMIC chips driver"
depends on (ARM || HEXAGON || COMPILE_TEST) depends on (ARM || HEXAGON || COMPILE_TEST)
select IRQ_DOMAIN select IRQ_DOMAIN_HIERARCHY
select MFD_CORE select MFD_CORE
select REGMAP select REGMAP
help help
......
...@@ -70,22 +70,23 @@ ...@@ -70,22 +70,23 @@
#define PM8XXX_NR_IRQS 256 #define PM8XXX_NR_IRQS 256
#define PM8821_NR_IRQS 112 #define PM8821_NR_IRQS 112
struct pm_irq_data {
int num_irqs;
struct irq_chip *irq_chip;
void (*irq_handler)(struct irq_desc *desc);
};
struct pm_irq_chip { struct pm_irq_chip {
struct regmap *regmap; struct regmap *regmap;
spinlock_t pm_irq_lock; spinlock_t pm_irq_lock;
struct irq_domain *irqdomain; struct irq_domain *irqdomain;
unsigned int num_irqs;
unsigned int num_blocks; unsigned int num_blocks;
unsigned int num_masters; unsigned int num_masters;
const struct pm_irq_data *pm_irq_data;
/* MUST BE AT THE END OF THIS STRUCT */
u8 config[0]; u8 config[0];
}; };
struct pm_irq_data {
int num_irqs;
const struct irq_domain_ops *irq_domain_ops;
void (*irq_handler)(struct irq_desc *desc);
};
static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp, static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp,
unsigned int *ip) unsigned int *ip)
{ {
...@@ -375,21 +376,38 @@ static struct irq_chip pm8xxx_irq_chip = { ...@@ -375,21 +376,38 @@ static struct irq_chip pm8xxx_irq_chip = {
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
}; };
static int pm8xxx_irq_domain_map(struct irq_domain *d, unsigned int irq, static void pm8xxx_irq_domain_map(struct pm_irq_chip *chip,
irq_hw_number_t hwirq) struct irq_domain *domain, unsigned int irq,
irq_hw_number_t hwirq, unsigned int type)
{ {
struct pm_irq_chip *chip = d->host_data; irq_domain_set_info(domain, irq, hwirq, chip->pm_irq_data->irq_chip,
chip, handle_level_irq, NULL, NULL);
irq_set_chip_and_handler(irq, &pm8xxx_irq_chip, handle_level_irq);
irq_set_chip_data(irq, chip);
irq_set_noprobe(irq); irq_set_noprobe(irq);
}
static int pm8xxx_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *data)
{
struct pm_irq_chip *chip = domain->host_data;
struct irq_fwspec *fwspec = data;
irq_hw_number_t hwirq;
unsigned int type;
int ret, i;
ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type);
if (ret)
return ret;
for (i = 0; i < nr_irqs; i++)
pm8xxx_irq_domain_map(chip, domain, virq + i, hwirq + i, type);
return 0; return 0;
} }
static const struct irq_domain_ops pm8xxx_irq_domain_ops = { static const struct irq_domain_ops pm8xxx_irq_domain_ops = {
.xlate = irq_domain_xlate_twocell, .alloc = pm8xxx_irq_domain_alloc,
.map = pm8xxx_irq_domain_map, .free = irq_domain_free_irqs_common,
.translate = irq_domain_translate_twocell,
}; };
static void pm8821_irq_mask_ack(struct irq_data *d) static void pm8821_irq_mask_ack(struct irq_data *d)
...@@ -473,23 +491,6 @@ static struct irq_chip pm8821_irq_chip = { ...@@ -473,23 +491,6 @@ static struct irq_chip pm8821_irq_chip = {
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
}; };
static int pm8821_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hwirq)
{
struct pm_irq_chip *chip = d->host_data;
irq_set_chip_and_handler(irq, &pm8821_irq_chip, handle_level_irq);
irq_set_chip_data(irq, chip);
irq_set_noprobe(irq);
return 0;
}
static const struct irq_domain_ops pm8821_irq_domain_ops = {
.xlate = irq_domain_xlate_twocell,
.map = pm8821_irq_domain_map,
};
static const struct regmap_config ssbi_regmap_config = { static const struct regmap_config ssbi_regmap_config = {
.reg_bits = 16, .reg_bits = 16,
.val_bits = 8, .val_bits = 8,
...@@ -501,13 +502,13 @@ static const struct regmap_config ssbi_regmap_config = { ...@@ -501,13 +502,13 @@ static const struct regmap_config ssbi_regmap_config = {
static const struct pm_irq_data pm8xxx_data = { static const struct pm_irq_data pm8xxx_data = {
.num_irqs = PM8XXX_NR_IRQS, .num_irqs = PM8XXX_NR_IRQS,
.irq_domain_ops = &pm8xxx_irq_domain_ops, .irq_chip = &pm8xxx_irq_chip,
.irq_handler = pm8xxx_irq_handler, .irq_handler = pm8xxx_irq_handler,
}; };
static const struct pm_irq_data pm8821_data = { static const struct pm_irq_data pm8821_data = {
.num_irqs = PM8821_NR_IRQS, .num_irqs = PM8821_NR_IRQS,
.irq_domain_ops = &pm8821_irq_domain_ops, .irq_chip = &pm8821_irq_chip,
.irq_handler = pm8821_irq_handler, .irq_handler = pm8821_irq_handler,
}; };
...@@ -571,14 +572,14 @@ static int pm8xxx_probe(struct platform_device *pdev) ...@@ -571,14 +572,14 @@ static int pm8xxx_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, chip); platform_set_drvdata(pdev, chip);
chip->regmap = regmap; chip->regmap = regmap;
chip->num_irqs = data->num_irqs; chip->num_blocks = DIV_ROUND_UP(data->num_irqs, 8);
chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8); chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
chip->pm_irq_data = data;
spin_lock_init(&chip->pm_irq_lock); spin_lock_init(&chip->pm_irq_lock);
chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node, chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node,
data->num_irqs, data->num_irqs,
data->irq_domain_ops, &pm8xxx_irq_domain_ops,
chip); chip);
if (!chip->irqdomain) if (!chip->irqdomain)
return -ENODEV; return -ENODEV;
......
...@@ -150,6 +150,7 @@ config PINCTRL_QCOM_SSBI_PMIC ...@@ -150,6 +150,7 @@ config PINCTRL_QCOM_SSBI_PMIC
select PINMUX select PINMUX
select PINCONF select PINCONF
select GENERIC_PINCONF select GENERIC_PINCONF
select IRQ_DOMAIN_HIERARCHY
help help
This is the pinctrl, pinmux, pinconf and gpiolib driver for the This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm GPIO and MPP blocks found in the Qualcomm PMIC's chips, Qualcomm GPIO and MPP blocks found in the Qualcomm PMIC's chips,
......
...@@ -55,6 +55,8 @@ ...@@ -55,6 +55,8 @@
#define PM8XXX_MAX_GPIOS 44 #define PM8XXX_MAX_GPIOS 44
#define PM8XXX_GPIO_PHYSICAL_OFFSET 1
/* custom pinconf parameters */ /* custom pinconf parameters */
#define PM8XXX_QCOM_DRIVE_STRENGH (PIN_CONFIG_END + 1) #define PM8XXX_QCOM_DRIVE_STRENGH (PIN_CONFIG_END + 1)
#define PM8XXX_QCOM_PULL_UP_STRENGTH (PIN_CONFIG_END + 2) #define PM8XXX_QCOM_PULL_UP_STRENGTH (PIN_CONFIG_END + 2)
...@@ -99,6 +101,9 @@ struct pm8xxx_gpio { ...@@ -99,6 +101,9 @@ struct pm8xxx_gpio {
struct pinctrl_desc desc; struct pinctrl_desc desc;
unsigned npins; unsigned npins;
struct fwnode_handle *fwnode;
struct irq_domain *domain;
}; };
static const struct pinconf_generic_params pm8xxx_gpio_bindings[] = { static const struct pinconf_generic_params pm8xxx_gpio_bindings[] = {
...@@ -499,11 +504,12 @@ static int pm8xxx_gpio_get(struct gpio_chip *chip, unsigned offset) ...@@ -499,11 +504,12 @@ static int pm8xxx_gpio_get(struct gpio_chip *chip, unsigned offset)
if (pin->mode == PM8XXX_GPIO_MODE_OUTPUT) { if (pin->mode == PM8XXX_GPIO_MODE_OUTPUT) {
ret = pin->output_value; ret = pin->output_value;
} else { } else if (pin->irq >= 0) {
ret = irq_get_irqchip_state(pin->irq, IRQCHIP_STATE_LINE_LEVEL, &state); ret = irq_get_irqchip_state(pin->irq, IRQCHIP_STATE_LINE_LEVEL, &state);
if (!ret) if (!ret)
ret = !!state; ret = !!state;
} } else
ret = -EINVAL;
return ret; return ret;
} }
...@@ -533,16 +539,39 @@ static int pm8xxx_gpio_of_xlate(struct gpio_chip *chip, ...@@ -533,16 +539,39 @@ static int pm8xxx_gpio_of_xlate(struct gpio_chip *chip,
if (flags) if (flags)
*flags = gpio_desc->args[1]; *flags = gpio_desc->args[1];
return gpio_desc->args[0] - 1; return gpio_desc->args[0] - PM8XXX_GPIO_PHYSICAL_OFFSET;
} }
static int pm8xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset) static int pm8xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
struct irq_fwspec fwspec;
int ret;
fwspec.fwnode = pctrl->fwnode;
fwspec.param_count = 2;
fwspec.param[0] = offset + PM8XXX_GPIO_PHYSICAL_OFFSET;
fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
ret = irq_create_fwspec_mapping(&fwspec);
/*
* Cache the IRQ since pm8xxx_gpio_get() needs this to get determine the
* line level.
*/
pin->irq = ret;
return ret;
}
static void pm8xxx_gpio_free(struct gpio_chip *chip, unsigned int offset)
{ {
struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip); struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip);
struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;
return pin->irq; pin->irq = -1;
} }
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
...@@ -571,7 +600,7 @@ static void pm8xxx_gpio_dbg_show_one(struct seq_file *s, ...@@ -571,7 +600,7 @@ static void pm8xxx_gpio_dbg_show_one(struct seq_file *s,
"no", "high", "medium", "low" "no", "high", "medium", "low"
}; };
seq_printf(s, " gpio%-2d:", offset + 1); seq_printf(s, " gpio%-2d:", offset + PM8XXX_GPIO_PHYSICAL_OFFSET);
if (pin->disable) { if (pin->disable) {
seq_puts(s, " ---"); seq_puts(s, " ---");
} else { } else {
...@@ -603,6 +632,7 @@ static void pm8xxx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) ...@@ -603,6 +632,7 @@ static void pm8xxx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
#endif #endif
static const struct gpio_chip pm8xxx_gpio_template = { static const struct gpio_chip pm8xxx_gpio_template = {
.free = pm8xxx_gpio_free,
.direction_input = pm8xxx_gpio_direction_input, .direction_input = pm8xxx_gpio_direction_input,
.direction_output = pm8xxx_gpio_direction_output, .direction_output = pm8xxx_gpio_direction_output,
.get = pm8xxx_gpio_get, .get = pm8xxx_gpio_get,
...@@ -664,13 +694,75 @@ static int pm8xxx_pin_populate(struct pm8xxx_gpio *pctrl, ...@@ -664,13 +694,75 @@ static int pm8xxx_pin_populate(struct pm8xxx_gpio *pctrl,
return 0; return 0;
} }
static struct irq_chip pm8xxx_irq_chip = {
.name = "ssbi-gpio",
.irq_mask_ack = irq_chip_mask_ack_parent,
.irq_unmask = irq_chip_unmask_parent,
.irq_set_type = irq_chip_set_type_parent,
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
};
static int pm8xxx_domain_translate(struct irq_domain *domain,
struct irq_fwspec *fwspec,
unsigned long *hwirq,
unsigned int *type)
{
struct pm8xxx_gpio *pctrl = container_of(domain->host_data,
struct pm8xxx_gpio, chip);
if (fwspec->param_count != 2 || fwspec->param[0] < 1 ||
fwspec->param[0] > pctrl->chip.ngpio)
return -EINVAL;
*hwirq = fwspec->param[0] - PM8XXX_GPIO_PHYSICAL_OFFSET;
*type = fwspec->param[1];
return 0;
}
static int pm8xxx_domain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *data)
{
struct pm8xxx_gpio *pctrl = container_of(domain->host_data,
struct pm8xxx_gpio, chip);
struct irq_fwspec *fwspec = data;
struct irq_fwspec parent_fwspec;
irq_hw_number_t hwirq;
unsigned int type;
int ret, i;
ret = pm8xxx_domain_translate(domain, fwspec, &hwirq, &type);
if (ret)
return ret;
for (i = 0; i < nr_irqs; i++)
irq_domain_set_info(domain, virq + i, hwirq + i,
&pm8xxx_irq_chip, pctrl, handle_level_irq,
NULL, NULL);
parent_fwspec.fwnode = domain->parent->fwnode;
parent_fwspec.param_count = 2;
parent_fwspec.param[0] = hwirq + 0xc0;
parent_fwspec.param[1] = fwspec->param[1];
return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
&parent_fwspec);
}
static const struct irq_domain_ops pm8xxx_domain_ops = {
.activate = gpiochip_irq_domain_activate,
.alloc = pm8xxx_domain_alloc,
.deactivate = gpiochip_irq_domain_deactivate,
.free = irq_domain_free_irqs_common,
.translate = pm8xxx_domain_translate,
};
static const struct of_device_id pm8xxx_gpio_of_match[] = { static const struct of_device_id pm8xxx_gpio_of_match[] = {
{ .compatible = "qcom,pm8018-gpio" }, { .compatible = "qcom,pm8018-gpio", .data = (void *) 6 },
{ .compatible = "qcom,pm8038-gpio" }, { .compatible = "qcom,pm8038-gpio", .data = (void *) 12 },
{ .compatible = "qcom,pm8058-gpio" }, { .compatible = "qcom,pm8058-gpio", .data = (void *) 44 },
{ .compatible = "qcom,pm8917-gpio" }, { .compatible = "qcom,pm8917-gpio", .data = (void *) 38 },
{ .compatible = "qcom,pm8921-gpio" }, { .compatible = "qcom,pm8921-gpio", .data = (void *) 44 },
{ .compatible = "qcom,ssbi-gpio" },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, pm8xxx_gpio_of_match); MODULE_DEVICE_TABLE(of, pm8xxx_gpio_of_match);
...@@ -678,22 +770,18 @@ MODULE_DEVICE_TABLE(of, pm8xxx_gpio_of_match); ...@@ -678,22 +770,18 @@ MODULE_DEVICE_TABLE(of, pm8xxx_gpio_of_match);
static int pm8xxx_gpio_probe(struct platform_device *pdev) static int pm8xxx_gpio_probe(struct platform_device *pdev)
{ {
struct pm8xxx_pin_data *pin_data; struct pm8xxx_pin_data *pin_data;
struct irq_domain *parent_domain;
struct device_node *parent_node;
struct pinctrl_pin_desc *pins; struct pinctrl_pin_desc *pins;
struct pm8xxx_gpio *pctrl; struct pm8xxx_gpio *pctrl;
int ret; int ret, i;
int i, npins;
pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
if (!pctrl) if (!pctrl)
return -ENOMEM; return -ENOMEM;
pctrl->dev = &pdev->dev; pctrl->dev = &pdev->dev;
npins = platform_irq_count(pdev); pctrl->npins = (uintptr_t) device_get_match_data(&pdev->dev);
if (!npins)
return -EINVAL;
if (npins < 0)
return npins;
pctrl->npins = npins;
pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL); pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!pctrl->regmap) { if (!pctrl->regmap) {
...@@ -720,12 +808,7 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev) ...@@ -720,12 +808,7 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
for (i = 0; i < pctrl->desc.npins; i++) { for (i = 0; i < pctrl->desc.npins; i++) {
pin_data[i].reg = SSBI_REG_ADDR_GPIO(i); pin_data[i].reg = SSBI_REG_ADDR_GPIO(i);
pin_data[i].irq = platform_get_irq(pdev, i); pin_data[i].irq = -1;
if (pin_data[i].irq < 0) {
dev_err(&pdev->dev,
"missing interrupts for pin %d\n", i);
return pin_data[i].irq;
}
ret = pm8xxx_pin_populate(pctrl, &pin_data[i]); ret = pm8xxx_pin_populate(pctrl, &pin_data[i]);
if (ret) if (ret)
...@@ -756,10 +839,29 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev) ...@@ -756,10 +839,29 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
pctrl->chip.of_gpio_n_cells = 2; pctrl->chip.of_gpio_n_cells = 2;
pctrl->chip.label = dev_name(pctrl->dev); pctrl->chip.label = dev_name(pctrl->dev);
pctrl->chip.ngpio = pctrl->npins; pctrl->chip.ngpio = pctrl->npins;
parent_node = of_irq_find_parent(pctrl->dev->of_node);
if (!parent_node)
return -ENXIO;
parent_domain = irq_find_host(parent_node);
of_node_put(parent_node);
if (!parent_domain)
return -ENXIO;
pctrl->fwnode = of_node_to_fwnode(pctrl->dev->of_node);
pctrl->domain = irq_domain_create_hierarchy(parent_domain, 0,
pctrl->chip.ngpio,
pctrl->fwnode,
&pm8xxx_domain_ops,
&pctrl->chip);
if (!pctrl->domain)
return -ENODEV;
ret = gpiochip_add_data(&pctrl->chip, pctrl); ret = gpiochip_add_data(&pctrl->chip, pctrl);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed register gpiochip\n"); dev_err(&pdev->dev, "failed register gpiochip\n");
return ret; goto err_chip_add_data;
} }
/* /*
...@@ -789,6 +891,8 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev) ...@@ -789,6 +891,8 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
unregister_gpiochip: unregister_gpiochip:
gpiochip_remove(&pctrl->chip); gpiochip_remove(&pctrl->chip);
err_chip_add_data:
irq_domain_remove(pctrl->domain);
return ret; return ret;
} }
...@@ -798,6 +902,7 @@ static int pm8xxx_gpio_remove(struct platform_device *pdev) ...@@ -798,6 +902,7 @@ static int pm8xxx_gpio_remove(struct platform_device *pdev)
struct pm8xxx_gpio *pctrl = platform_get_drvdata(pdev); struct pm8xxx_gpio *pctrl = platform_get_drvdata(pdev);
gpiochip_remove(&pctrl->chip); gpiochip_remove(&pctrl->chip);
irq_domain_remove(pctrl->domain);
return 0; return 0;
} }
......
...@@ -605,6 +605,7 @@ extern void irq_chip_disable_parent(struct irq_data *data); ...@@ -605,6 +605,7 @@ extern void irq_chip_disable_parent(struct irq_data *data);
extern void irq_chip_ack_parent(struct irq_data *data); extern void irq_chip_ack_parent(struct irq_data *data);
extern int irq_chip_retrigger_hierarchy(struct irq_data *data); extern int irq_chip_retrigger_hierarchy(struct irq_data *data);
extern void irq_chip_mask_parent(struct irq_data *data); extern void irq_chip_mask_parent(struct irq_data *data);
extern void irq_chip_mask_ack_parent(struct irq_data *data);
extern void irq_chip_unmask_parent(struct irq_data *data); extern void irq_chip_unmask_parent(struct irq_data *data);
extern void irq_chip_eoi_parent(struct irq_data *data); extern void irq_chip_eoi_parent(struct irq_data *data);
extern int irq_chip_set_affinity_parent(struct irq_data *data, extern int irq_chip_set_affinity_parent(struct irq_data *data,
......
...@@ -419,6 +419,11 @@ int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr, ...@@ -419,6 +419,11 @@ int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr,
const u32 *intspec, unsigned int intsize, const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_type); irq_hw_number_t *out_hwirq, unsigned int *out_type);
int irq_domain_translate_twocell(struct irq_domain *d,
struct irq_fwspec *fwspec,
unsigned long *out_hwirq,
unsigned int *out_type);
/* IPI functions */ /* IPI functions */
int irq_reserve_ipi(struct irq_domain *domain, const struct cpumask *dest); int irq_reserve_ipi(struct irq_domain *domain, const struct cpumask *dest);
int irq_destroy_ipi(unsigned int irq, const struct cpumask *dest); int irq_destroy_ipi(unsigned int irq, const struct cpumask *dest);
......
...@@ -1277,6 +1277,17 @@ void irq_chip_mask_parent(struct irq_data *data) ...@@ -1277,6 +1277,17 @@ void irq_chip_mask_parent(struct irq_data *data)
} }
EXPORT_SYMBOL_GPL(irq_chip_mask_parent); EXPORT_SYMBOL_GPL(irq_chip_mask_parent);
/**
* irq_chip_mask_ack_parent - Mask and acknowledge the parent interrupt
* @data: Pointer to interrupt specific data
*/
void irq_chip_mask_ack_parent(struct irq_data *data)
{
data = data->parent_data;
data->chip->irq_mask_ack(data);
}
EXPORT_SYMBOL_GPL(irq_chip_mask_ack_parent);
/** /**
* irq_chip_unmask_parent - Unmask the parent interrupt * irq_chip_unmask_parent - Unmask the parent interrupt
* @data: Pointer to interrupt specific data * @data: Pointer to interrupt specific data
......
...@@ -729,16 +729,17 @@ static int irq_domain_translate(struct irq_domain *d, ...@@ -729,16 +729,17 @@ static int irq_domain_translate(struct irq_domain *d,
return 0; return 0;
} }
static void of_phandle_args_to_fwspec(struct of_phandle_args *irq_data, static void of_phandle_args_to_fwspec(struct device_node *np, const u32 *args,
unsigned int count,
struct irq_fwspec *fwspec) struct irq_fwspec *fwspec)
{ {
int i; int i;
fwspec->fwnode = irq_data->np ? &irq_data->np->fwnode : NULL; fwspec->fwnode = np ? &np->fwnode : NULL;
fwspec->param_count = irq_data->args_count; fwspec->param_count = count;
for (i = 0; i < irq_data->args_count; i++) for (i = 0; i < count; i++)
fwspec->param[i] = irq_data->args[i]; fwspec->param[i] = args[i];
} }
unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec) unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
...@@ -836,7 +837,9 @@ unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data) ...@@ -836,7 +837,9 @@ unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data)
{ {
struct irq_fwspec fwspec; struct irq_fwspec fwspec;
of_phandle_args_to_fwspec(irq_data, &fwspec); of_phandle_args_to_fwspec(irq_data->np, irq_data->args,
irq_data->args_count, &fwspec);
return irq_create_fwspec_mapping(&fwspec); return irq_create_fwspec_mapping(&fwspec);
} }
EXPORT_SYMBOL_GPL(irq_create_of_mapping); EXPORT_SYMBOL_GPL(irq_create_of_mapping);
...@@ -928,11 +931,10 @@ int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr, ...@@ -928,11 +931,10 @@ int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr,
const u32 *intspec, unsigned int intsize, const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_type) irq_hw_number_t *out_hwirq, unsigned int *out_type)
{ {
if (WARN_ON(intsize < 2)) struct irq_fwspec fwspec;
return -EINVAL;
*out_hwirq = intspec[0]; of_phandle_args_to_fwspec(ctrlr, intspec, intsize, &fwspec);
*out_type = intspec[1] & IRQ_TYPE_SENSE_MASK; return irq_domain_translate_twocell(d, &fwspec, out_hwirq, out_type);
return 0;
} }
EXPORT_SYMBOL_GPL(irq_domain_xlate_twocell); EXPORT_SYMBOL_GPL(irq_domain_xlate_twocell);
...@@ -968,6 +970,27 @@ const struct irq_domain_ops irq_domain_simple_ops = { ...@@ -968,6 +970,27 @@ const struct irq_domain_ops irq_domain_simple_ops = {
}; };
EXPORT_SYMBOL_GPL(irq_domain_simple_ops); EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
/**
* irq_domain_translate_twocell() - Generic translate for direct two cell
* bindings
*
* Device Tree IRQ specifier translation function which works with two cell
* bindings where the cell values map directly to the hwirq number
* and linux irq flags.
*/
int irq_domain_translate_twocell(struct irq_domain *d,
struct irq_fwspec *fwspec,
unsigned long *out_hwirq,
unsigned int *out_type)
{
if (WARN_ON(fwspec->param_count < 2))
return -EINVAL;
*out_hwirq = fwspec->param[0];
*out_type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
return 0;
}
EXPORT_SYMBOL_GPL(irq_domain_translate_twocell);
int irq_domain_alloc_descs(int virq, unsigned int cnt, irq_hw_number_t hwirq, int irq_domain_alloc_descs(int virq, unsigned int cnt, irq_hw_number_t hwirq,
int node, const struct irq_affinity_desc *affinity) int node, const struct irq_affinity_desc *affinity)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment