forked from luck/tmp_suning_uos_patched
Merge branch 'ib-qcom-ssbi' into devel
This commit is contained in:
commit
3dda927fdb
|
@ -93,9 +93,8 @@ cm3605 {
|
|||
vdd-supply = <&pm8058_l14>; // 2.85V
|
||||
aset-gpios = <&pm8058_gpio 35 GPIO_ACTIVE_LOW>;
|
||||
capella,aset-resistance-ohms = <100000>;
|
||||
/* GPIO34 has interrupt 225 on the PM8058 */
|
||||
/* 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 */
|
||||
io-channels = <&xoadc 0x00 0x05>;
|
||||
io-channel-names = "aout";
|
||||
|
@ -515,9 +514,8 @@ i2c@19c80000 {
|
|||
ak8975@c {
|
||||
compatible = "asahi-kasei,ak8975";
|
||||
reg = <0x0c>;
|
||||
/* FIXME: GPIO33 has interrupt 224 on the PM8058 */
|
||||
interrupt-parent = <&pm8058>;
|
||||
interrupts = <224 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-parent = <&pm8058_gpio>;
|
||||
interrupts = <33 IRQ_TYPE_EDGE_RISING>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&dragon_ak8975_gpios>;
|
||||
vid-supply = <&pm8058_lvs0>; // 1.8V
|
||||
|
@ -526,9 +524,8 @@ ak8975@c {
|
|||
bmp085@77 {
|
||||
compatible = "bosch,bmp085";
|
||||
reg = <0x77>;
|
||||
/* FIXME: GPIO16 has interrupt 207 on the PM8058 */
|
||||
interrupt-parent = <&pm8058>;
|
||||
interrupts = <207 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-parent = <&pm8058_gpio>;
|
||||
interrupts = <16 IRQ_TYPE_EDGE_RISING>;
|
||||
reset-gpios = <&tlmm 86 GPIO_ACTIVE_LOW>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&dragon_bmp085_gpios>;
|
||||
|
@ -539,12 +536,11 @@ mpu3050@68 {
|
|||
compatible = "invensense,mpu3050";
|
||||
reg = <0x68>;
|
||||
/*
|
||||
* GPIO17 has interrupt 208 on the
|
||||
* PM8058, it is pulled high by a 10k
|
||||
* GPIO17 is pulled high by a 10k
|
||||
* resistor to VLOGIC so needs to be
|
||||
* 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-0 = <&dragon_mpu3050_gpios>;
|
||||
vlogic-supply = <&pm8058_lvs0>; // 1.8V
|
||||
|
@ -589,11 +585,10 @@ ethernet-ebi2@2,0 {
|
|||
compatible = "smsc,lan9221", "smsc,lan9115";
|
||||
reg = <2 0x0 0x100>;
|
||||
/*
|
||||
* GPIO7 has interrupt 198 on the PM8058
|
||||
* The second interrupt is the PME interrupt
|
||||
* 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>;
|
||||
reset-gpios = <&tlmm 30 GPIO_ACTIVE_LOW>;
|
||||
vdd33a-supply = <&dragon_veth>;
|
||||
|
|
|
@ -705,50 +705,8 @@ pm8921_gpio: gpio@150 {
|
|||
compatible = "qcom,pm8921-gpio",
|
||||
"qcom,ssbi-gpio";
|
||||
reg = <0x150>;
|
||||
interrupts = <192 IRQ_TYPE_NONE>,
|
||||
<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>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
|
|
|
@ -323,13 +323,8 @@ rtc@11d {
|
|||
|
||||
pmicgpio: gpio@150 {
|
||||
compatible = "qcom,pm8018-gpio", "qcom,ssbi-gpio";
|
||||
interrupt-parent = <&pmicintc>;
|
||||
interrupts = <24 IRQ_TYPE_NONE>,
|
||||
<25 IRQ_TYPE_NONE>,
|
||||
<26 IRQ_TYPE_NONE>,
|
||||
<27 IRQ_TYPE_NONE>,
|
||||
<28 IRQ_TYPE_NONE>,
|
||||
<29 IRQ_TYPE_NONE>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
|
|
@ -285,51 +285,8 @@ pm8058_gpio: gpio@150 {
|
|||
compatible = "qcom,pm8058-gpio",
|
||||
"qcom,ssbi-gpio";
|
||||
reg = <0x150>;
|
||||
interrupt-parent = <&pm8058>;
|
||||
interrupts = <192 IRQ_TYPE_NONE>,
|
||||
<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>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
|
|
|
@ -928,7 +928,7 @@ config UCB1400_CORE
|
|||
config MFD_PM8XXX
|
||||
tristate "Qualcomm PM8xxx PMIC chips driver"
|
||||
depends on (ARM || HEXAGON || COMPILE_TEST)
|
||||
select IRQ_DOMAIN
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
select MFD_CORE
|
||||
select REGMAP
|
||||
help
|
||||
|
|
|
@ -70,22 +70,23 @@
|
|||
#define PM8XXX_NR_IRQS 256
|
||||
#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 regmap *regmap;
|
||||
spinlock_t pm_irq_lock;
|
||||
struct irq_domain *irqdomain;
|
||||
unsigned int num_irqs;
|
||||
unsigned int num_blocks;
|
||||
unsigned int num_masters;
|
||||
const struct pm_irq_data *pm_irq_data;
|
||||
/* MUST BE AT THE END OF THIS STRUCT */
|
||||
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,
|
||||
unsigned int *ip)
|
||||
{
|
||||
|
@ -375,21 +376,38 @@ static struct irq_chip pm8xxx_irq_chip = {
|
|||
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
|
||||
};
|
||||
|
||||
static int pm8xxx_irq_domain_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
static void pm8xxx_irq_domain_map(struct pm_irq_chip *chip,
|
||||
struct irq_domain *domain, unsigned int irq,
|
||||
irq_hw_number_t hwirq, unsigned int type)
|
||||
{
|
||||
struct pm_irq_chip *chip = d->host_data;
|
||||
|
||||
irq_set_chip_and_handler(irq, &pm8xxx_irq_chip, handle_level_irq);
|
||||
irq_set_chip_data(irq, chip);
|
||||
irq_domain_set_info(domain, irq, hwirq, chip->pm_irq_data->irq_chip,
|
||||
chip, handle_level_irq, NULL, NULL);
|
||||
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;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops pm8xxx_irq_domain_ops = {
|
||||
.xlate = irq_domain_xlate_twocell,
|
||||
.map = pm8xxx_irq_domain_map,
|
||||
.alloc = pm8xxx_irq_domain_alloc,
|
||||
.free = irq_domain_free_irqs_common,
|
||||
.translate = irq_domain_translate_twocell,
|
||||
};
|
||||
|
||||
static void pm8821_irq_mask_ack(struct irq_data *d)
|
||||
|
@ -473,23 +491,6 @@ static struct irq_chip pm8821_irq_chip = {
|
|||
.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 = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
|
@ -501,13 +502,13 @@ static const struct regmap_config ssbi_regmap_config = {
|
|||
|
||||
static const struct pm_irq_data pm8xxx_data = {
|
||||
.num_irqs = PM8XXX_NR_IRQS,
|
||||
.irq_domain_ops = &pm8xxx_irq_domain_ops,
|
||||
.irq_chip = &pm8xxx_irq_chip,
|
||||
.irq_handler = pm8xxx_irq_handler,
|
||||
};
|
||||
|
||||
static const struct pm_irq_data pm8821_data = {
|
||||
.num_irqs = PM8821_NR_IRQS,
|
||||
.irq_domain_ops = &pm8821_irq_domain_ops,
|
||||
.irq_chip = &pm8821_irq_chip,
|
||||
.irq_handler = pm8821_irq_handler,
|
||||
};
|
||||
|
||||
|
@ -571,14 +572,14 @@ static int pm8xxx_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, chip);
|
||||
chip->regmap = regmap;
|
||||
chip->num_irqs = data->num_irqs;
|
||||
chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
|
||||
chip->num_blocks = DIV_ROUND_UP(data->num_irqs, 8);
|
||||
chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
|
||||
chip->pm_irq_data = data;
|
||||
spin_lock_init(&chip->pm_irq_lock);
|
||||
|
||||
chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node,
|
||||
data->num_irqs,
|
||||
data->irq_domain_ops,
|
||||
&pm8xxx_irq_domain_ops,
|
||||
chip);
|
||||
if (!chip->irqdomain)
|
||||
return -ENODEV;
|
||||
|
|
|
@ -150,6 +150,7 @@ config PINCTRL_QCOM_SSBI_PMIC
|
|||
select PINMUX
|
||||
select PINCONF
|
||||
select GENERIC_PINCONF
|
||||
select IRQ_DOMAIN_HIERARCHY
|
||||
help
|
||||
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
|
||||
Qualcomm GPIO and MPP blocks found in the Qualcomm PMIC's chips,
|
||||
|
|
|
@ -55,6 +55,8 @@
|
|||
|
||||
#define PM8XXX_MAX_GPIOS 44
|
||||
|
||||
#define PM8XXX_GPIO_PHYSICAL_OFFSET 1
|
||||
|
||||
/* custom pinconf parameters */
|
||||
#define PM8XXX_QCOM_DRIVE_STRENGH (PIN_CONFIG_END + 1)
|
||||
#define PM8XXX_QCOM_PULL_UP_STRENGTH (PIN_CONFIG_END + 2)
|
||||
|
@ -99,6 +101,9 @@ struct pm8xxx_gpio {
|
|||
|
||||
struct pinctrl_desc desc;
|
||||
unsigned npins;
|
||||
|
||||
struct fwnode_handle *fwnode;
|
||||
struct irq_domain *domain;
|
||||
};
|
||||
|
||||
static const struct pinconf_generic_params pm8xxx_gpio_bindings[] = {
|
||||
|
@ -499,11 +504,12 @@ static int pm8xxx_gpio_get(struct gpio_chip *chip, unsigned offset)
|
|||
|
||||
if (pin->mode == PM8XXX_GPIO_MODE_OUTPUT) {
|
||||
ret = pin->output_value;
|
||||
} else {
|
||||
} else if (pin->irq >= 0) {
|
||||
ret = irq_get_irqchip_state(pin->irq, IRQCHIP_STATE_LINE_LEVEL, &state);
|
||||
if (!ret)
|
||||
ret = !!state;
|
||||
}
|
||||
} else
|
||||
ret = -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -533,7 +539,7 @@ static int pm8xxx_gpio_of_xlate(struct gpio_chip *chip,
|
|||
if (flags)
|
||||
*flags = gpio_desc->args[1];
|
||||
|
||||
return gpio_desc->args[0] - 1;
|
||||
return gpio_desc->args[0] - PM8XXX_GPIO_PHYSICAL_OFFSET;
|
||||
}
|
||||
|
||||
|
||||
|
@ -541,8 +547,31 @@ 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;
|
||||
|
||||
return pin->irq;
|
||||
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_pin_data *pin = pctrl->desc.pins[offset].drv_data;
|
||||
|
||||
pin->irq = -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
@ -571,7 +600,7 @@ static void pm8xxx_gpio_dbg_show_one(struct seq_file *s,
|
|||
"no", "high", "medium", "low"
|
||||
};
|
||||
|
||||
seq_printf(s, " gpio%-2d:", offset + 1);
|
||||
seq_printf(s, " gpio%-2d:", offset + PM8XXX_GPIO_PHYSICAL_OFFSET);
|
||||
if (pin->disable) {
|
||||
seq_puts(s, " ---");
|
||||
} else {
|
||||
|
@ -603,6 +632,7 @@ static void pm8xxx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
|||
#endif
|
||||
|
||||
static const struct gpio_chip pm8xxx_gpio_template = {
|
||||
.free = pm8xxx_gpio_free,
|
||||
.direction_input = pm8xxx_gpio_direction_input,
|
||||
.direction_output = pm8xxx_gpio_direction_output,
|
||||
.get = pm8xxx_gpio_get,
|
||||
|
@ -664,13 +694,75 @@ static int pm8xxx_pin_populate(struct pm8xxx_gpio *pctrl,
|
|||
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[] = {
|
||||
{ .compatible = "qcom,pm8018-gpio" },
|
||||
{ .compatible = "qcom,pm8038-gpio" },
|
||||
{ .compatible = "qcom,pm8058-gpio" },
|
||||
{ .compatible = "qcom,pm8917-gpio" },
|
||||
{ .compatible = "qcom,pm8921-gpio" },
|
||||
{ .compatible = "qcom,ssbi-gpio" },
|
||||
{ .compatible = "qcom,pm8018-gpio", .data = (void *) 6 },
|
||||
{ .compatible = "qcom,pm8038-gpio", .data = (void *) 12 },
|
||||
{ .compatible = "qcom,pm8058-gpio", .data = (void *) 44 },
|
||||
{ .compatible = "qcom,pm8917-gpio", .data = (void *) 38 },
|
||||
{ .compatible = "qcom,pm8921-gpio", .data = (void *) 44 },
|
||||
{ },
|
||||
};
|
||||
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)
|
||||
{
|
||||
struct pm8xxx_pin_data *pin_data;
|
||||
struct irq_domain *parent_domain;
|
||||
struct device_node *parent_node;
|
||||
struct pinctrl_pin_desc *pins;
|
||||
struct pm8xxx_gpio *pctrl;
|
||||
int ret;
|
||||
int i, npins;
|
||||
int ret, i;
|
||||
|
||||
pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
|
||||
if (!pctrl)
|
||||
return -ENOMEM;
|
||||
|
||||
pctrl->dev = &pdev->dev;
|
||||
npins = platform_irq_count(pdev);
|
||||
if (!npins)
|
||||
return -EINVAL;
|
||||
if (npins < 0)
|
||||
return npins;
|
||||
pctrl->npins = npins;
|
||||
pctrl->npins = (uintptr_t) device_get_match_data(&pdev->dev);
|
||||
|
||||
pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!pctrl->regmap) {
|
||||
|
@ -720,12 +808,7 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
for (i = 0; i < pctrl->desc.npins; i++) {
|
||||
pin_data[i].reg = SSBI_REG_ADDR_GPIO(i);
|
||||
pin_data[i].irq = platform_get_irq(pdev, i);
|
||||
if (pin_data[i].irq < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"missing interrupts for pin %d\n", i);
|
||||
return pin_data[i].irq;
|
||||
}
|
||||
pin_data[i].irq = -1;
|
||||
|
||||
ret = pm8xxx_pin_populate(pctrl, &pin_data[i]);
|
||||
if (ret)
|
||||
|
@ -756,10 +839,29 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
|
|||
pctrl->chip.of_gpio_n_cells = 2;
|
||||
pctrl->chip.label = dev_name(pctrl->dev);
|
||||
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);
|
||||
if (ret) {
|
||||
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)
|
|||
|
||||
unregister_gpiochip:
|
||||
gpiochip_remove(&pctrl->chip);
|
||||
err_chip_add_data:
|
||||
irq_domain_remove(pctrl->domain);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -798,6 +902,7 @@ static int pm8xxx_gpio_remove(struct platform_device *pdev)
|
|||
struct pm8xxx_gpio *pctrl = platform_get_drvdata(pdev);
|
||||
|
||||
gpiochip_remove(&pctrl->chip);
|
||||
irq_domain_remove(pctrl->domain);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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 int irq_chip_retrigger_hierarchy(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_eoi_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,
|
|||
const u32 *intspec, unsigned int intsize,
|
||||
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 */
|
||||
int irq_reserve_ipi(struct irq_domain *domain, 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)
|
|||
}
|
||||
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
|
||||
* @data: Pointer to interrupt specific data
|
||||
|
|
|
@ -729,16 +729,17 @@ static int irq_domain_translate(struct irq_domain *d,
|
|||
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)
|
||||
{
|
||||
int i;
|
||||
|
||||
fwspec->fwnode = irq_data->np ? &irq_data->np->fwnode : NULL;
|
||||
fwspec->param_count = irq_data->args_count;
|
||||
fwspec->fwnode = np ? &np->fwnode : NULL;
|
||||
fwspec->param_count = count;
|
||||
|
||||
for (i = 0; i < irq_data->args_count; i++)
|
||||
fwspec->param[i] = irq_data->args[i];
|
||||
for (i = 0; i < count; i++)
|
||||
fwspec->param[i] = args[i];
|
||||
}
|
||||
|
||||
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)
|
|||
{
|
||||
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);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_create_of_mapping);
|
||||
|
@ -928,11 +931,10 @@ int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr,
|
|||
const u32 *intspec, unsigned int intsize,
|
||||
irq_hw_number_t *out_hwirq, unsigned int *out_type)
|
||||
{
|
||||
if (WARN_ON(intsize < 2))
|
||||
return -EINVAL;
|
||||
*out_hwirq = intspec[0];
|
||||
*out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
|
||||
return 0;
|
||||
struct irq_fwspec fwspec;
|
||||
|
||||
of_phandle_args_to_fwspec(ctrlr, intspec, intsize, &fwspec);
|
||||
return irq_domain_translate_twocell(d, &fwspec, out_hwirq, out_type);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_xlate_twocell);
|
||||
|
||||
|
@ -968,6 +970,27 @@ const struct irq_domain_ops 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 node, const struct irq_affinity_desc *affinity)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user