Loading drivers/pinctrl/qcom/pinctrl-msm.c +234 −45 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ struct msm_pinctrl { const struct msm_pinctrl_soc_data *soc; void __iomem *regs; void __iomem *pdc_regs; #ifdef CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE /* For holding per tile virtual address */ void __iomem *per_tile_regs[4]; Loading Loading @@ -975,6 +976,158 @@ static const struct irq_domain_ops msm_gpio_domain_ops = { .free = irq_domain_free_irqs_top, }; static struct irq_chip msm_dirconn_irq_chip; static void msm_gpio_dirconn_handler(struct irq_desc *desc) { struct irq_data *irqd = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); generic_handle_irq(irqd->irq); chained_irq_exit(chip, desc); } static void setup_pdc_gpio(struct irq_domain *domain, unsigned int parent_irq, unsigned int gpio) { int irq; if (gpio != 0) { irq = irq_create_mapping(domain, gpio); irq_set_parent(irq, parent_irq); irq_set_chip(irq, &msm_dirconn_irq_chip); irq_set_handler_data(parent_irq, irq_get_irq_data(irq)); } __irq_set_handler(parent_irq, msm_gpio_dirconn_handler, false, NULL); } static void request_dc_interrupt(struct irq_domain *domain, struct irq_domain *parent, irq_hw_number_t hwirq, unsigned int gpio) { struct irq_fwspec fwspec; unsigned int parent_irq; fwspec.fwnode = parent->fwnode; fwspec.param[0] = 0; /* SPI */ fwspec.param[1] = hwirq; fwspec.param[2] = IRQ_TYPE_NONE; fwspec.param_count = 3; parent_irq = irq_create_fwspec_mapping(&fwspec); setup_pdc_gpio(domain, parent_irq, gpio); } /** * gpio_muxed_to_pdc: Mux the GPIO to a PDC IRQ * * @pdc_domain: the PDC's domain * @d: the GPIO's IRQ data * * Find a free PDC port for the GPIO and map the GPIO's mux information to the * PDC registers; so the GPIO can be used a wakeup source. */ static void gpio_muxed_to_pdc(struct irq_domain *pdc_domain, struct irq_data *d) { int i, j; unsigned int mux; struct irq_desc *desc = irq_data_to_desc(d); struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq); struct gpio_chip *gc = irq_data_get_irq_chip_data(d); unsigned int gpio = d->hwirq; struct msm_pinctrl *pctrl; unsigned int irq; if (!gc || !parent_data) return; pctrl = gpiochip_get_data(gc); for (i = 0; i < pctrl->soc->n_gpio_mux_in; i++) { if (gpio != pctrl->soc->gpio_mux_in[i].gpio) continue; mux = pctrl->soc->gpio_mux_in[i].mux; for (j = 0; j < pctrl->soc->n_pdc_mux_out; j++) { struct msm_pdc_mux_output *pdc_out = &pctrl->soc->pdc_mux_out[j]; if (pdc_out->mux == mux) break; if (pdc_out->mux) continue; pdc_out->mux = gpio; irq = irq_find_mapping(pdc_domain, pdc_out->hwirq + 32); /* setup the IRQ parent for the GPIO */ setup_pdc_gpio(pctrl->chip.irqdomain, irq, gpio); /* program pdc select grp register */ writel_relaxed((mux & 0x3F), pctrl->pdc_regs + (0x14 * j)); break; } /* We have no more PDC port available */ WARN_ON(j == pctrl->soc->n_pdc_mux_out); } } static bool is_gpio_tlmm_dc(struct irq_data *d, u32 type) { const struct msm_pingroup *g; unsigned long flags; struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl; bool ret = false; unsigned int polarity = 0, offset, val; int i; void __iomem *base; if (!gc) return false; pctrl = gpiochip_get_data(gc); for (i = 0; i < pctrl->soc->n_dir_conns; i++) { struct msm_dir_conn *dir_conn = (struct msm_dir_conn *) &pctrl->soc->dir_conn[i]; if (dir_conn->gpio == d->hwirq && dir_conn->tlmm_dc) { ret = true; offset = pctrl->soc->dir_conn_irq_base - dir_conn->hwirq; break; } } if (!ret) return ret; if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)) return ret; /* * Since the default polarity is set to 0, change it to 1 for * Rising edge and active high interrupt type such that the line * is not inverted. */ polarity = 1; raw_spin_lock_irqsave(&pctrl->lock, flags); g = &pctrl->soc->groups[d->hwirq]; base = reassign_pctrl_reg(pctrl->soc, d->hwirq); val = readl_relaxed(base + g->dir_conn_reg + (offset * 4)); val |= polarity << 8; writel_relaxed(val, base + g->dir_conn_reg + (offset * 4)); raw_spin_unlock_irqrestore(&pctrl->lock, flags); return ret; } static bool is_gpio_dual_edge(struct irq_data *d, irq_hw_number_t *dir_conn_irq) { struct irq_desc *desc = irq_data_to_desc(d); Loading @@ -995,6 +1148,17 @@ static bool is_gpio_dual_edge(struct irq_data *d, irq_hw_number_t *dir_conn_irq) return true; } } for (i = 0; i < pctrl->soc->n_pdc_mux_out; i++) { struct msm_pdc_mux_output *dir_conn = &pctrl->soc->pdc_mux_out[i]; if (dir_conn->mux == d->hwirq && (dir_conn->hwirq + 32) != parent_data->hwirq) { *dir_conn_irq = dir_conn->hwirq + 32; return true; } } return false; } Loading @@ -1012,9 +1176,13 @@ static void msm_dirconn_irq_mask(struct irq_data *d) irq_get_irq_data(irq_find_mapping(parent_data->domain, dir_conn_irq)); if (dir_conn_data && dir_conn_data->chip->irq_mask) if (!dir_conn_data) return; if (dir_conn_data->chip->irq_mask) dir_conn_data->chip->irq_mask(dir_conn_data); } if (parent_data->chip->irq_mask) parent_data->chip->irq_mask(parent_data); } Loading Loading @@ -1065,7 +1233,10 @@ static void msm_dirconn_irq_unmask(struct irq_data *d) irq_get_irq_data(irq_find_mapping(parent_data->domain, dir_conn_irq)); if (dir_conn_data && dir_conn_data->chip->irq_unmask) if (!dir_conn_data) return; if (dir_conn_data->chip->irq_unmask) dir_conn_data->chip->irq_unmask(dir_conn_data); } if (parent_data->chip->irq_unmask) Loading Loading @@ -1264,12 +1435,12 @@ static int msm_dirconn_irq_set_type(struct irq_data *d, unsigned int type) if (!parent_data) return 0; if (type == IRQ_TYPE_EDGE_BOTH) { if (type == IRQ_TYPE_EDGE_BOTH) add_dirconn_tlmm(d, irq); } else { if (is_gpio_dual_edge(d, &irq)) else if (is_gpio_dual_edge(d, &irq)) remove_dirconn_tlmm(d, irq); } else if (is_gpio_tlmm_dc(d, type)) type = IRQ_TYPE_EDGE_RISING; if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) irq_set_handler_locked(d, handle_level_irq); Loading Loading @@ -1333,57 +1504,72 @@ static void msm_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } static void msm_gpio_dirconn_handler(struct irq_desc *desc) { struct irq_data *irqd = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); generic_handle_irq(irqd->irq); chained_irq_exit(chip, desc); } static void msm_gpio_setup_dir_connects(struct msm_pinctrl *pctrl) { struct device_node *parent_node; struct irq_domain *parent_domain; struct irq_fwspec fwspec; struct irq_domain *pdc_domain; unsigned int i; parent_node = of_irq_find_parent(pctrl->dev->of_node); if (!parent_node) return; parent_domain = irq_find_host(parent_node); if (!parent_domain) pdc_domain = irq_find_host(parent_node); if (!pdc_domain) return; fwspec.fwnode = parent_domain->fwnode; for (i = 0; i < pctrl->soc->n_dir_conns; i++) { const struct msm_dir_conn *dirconn = &pctrl->soc->dir_conn[i]; unsigned int parent_irq; int irq; struct irq_data *d; fwspec.param[0] = 0; /* SPI */ fwspec.param[1] = dirconn->hwirq; fwspec.param[2] = IRQ_TYPE_NONE; fwspec.param_count = 3; parent_irq = irq_create_fwspec_mapping(&fwspec); request_dc_interrupt(pctrl->chip.irqdomain, pdc_domain, dirconn->hwirq, dirconn->gpio); if (dirconn->gpio != 0) { irq = irq_create_mapping(pctrl->chip.irqdomain, dirconn->gpio); if (!dirconn->gpio) continue; irq_set_parent(irq, parent_irq); irq_set_chip(irq, &msm_dirconn_irq_chip); __irq_set_handler(parent_irq, msm_gpio_dirconn_handler, false, NULL); irq_set_handler_data(parent_irq, irq_get_irq_data(irq)); } else { __irq_set_handler(parent_irq, msm_gpio_dirconn_handler, false, NULL); if (!dirconn->tlmm_dc) continue; /* * If the gpio is routed through TLMM direct connect interrupts, * program the TLMM registers for this setup. */ d = irq_get_irq_data(irq_find_mapping(pctrl->chip.irqdomain, dirconn->gpio)); if (!d) continue; msm_dirconn_cfg_reg(d, pctrl->soc->dir_conn_irq_base - (u32)dirconn->hwirq); } for (i = 0; i < pctrl->soc->n_pdc_mux_out; i++) { struct msm_pdc_mux_output *pdc_out = &pctrl->soc->pdc_mux_out[i]; request_dc_interrupt(pctrl->chip.irqdomain, pdc_domain, pdc_out->hwirq, 0); } /* * Statically choose the GPIOs for mapping to PDC. Dynamic mux mapping * is very difficult. */ for (i = 0; i < pctrl->soc->n_gpio_mux_in; i++) { unsigned int irq; struct irq_data *d; struct msm_gpio_mux_input *gpio_in = &pctrl->soc->gpio_mux_in[i]; if (!gpio_in->init) continue; irq = irq_find_mapping(pctrl->chip.irqdomain, gpio_in->gpio); d = irq_get_irq_data(irq); if (!d) continue; gpio_muxed_to_pdc(pdc_domain, d); } } Loading Loading @@ -1554,6 +1740,9 @@ int msm_pinctrl_probe(struct platform_device *pdev, } #endif res = platform_get_resource(pdev, IORESOURCE_MEM, 1); pctrl->pdc_regs = devm_ioremap_resource(&pdev->dev, res); msm_pinctrl_setup_pm_reset(pctrl); pctrl->irq = platform_get_irq(pdev, 0); Loading drivers/pinctrl/qcom/pinctrl-msm.h +37 −2 Original line number Diff line number Diff line /* * Copyright (c) 2013, Sony Mobile Communications AB. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -104,16 +105,40 @@ struct msm_pingroup { unsigned intr_detection_bit:5; unsigned intr_detection_width:5; unsigned dir_conn_en_bit:8; } }; /** * struct msm_gpio_mux_input - Map GPIO to Mux pin * @mux:: The mux pin to which the GPIO is connected to * @gpio: GPIO pin number * @init: Setup PDC connection at probe */ struct msm_gpio_mux_input { unsigned int mux; unsigned int gpio; bool init; }; /** * struct msm_pdc_mux_output - GPIO mux pin to PDC port * @mux: GPIO mux pin number * @hwirq: The PDC port (hwirq) that GPIO is connected to */ struct msm_pdc_mux_output { unsigned int mux; irq_hw_number_t hwirq; }; /** * struct msm_dir_conn - Direct GPIO connect configuration * @gpio: GPIO pin number * @hwirq: The GIC interrupt that the pin is connected to */; * @tlmm_dc: indicates if the GPIO is routed to GIC directly */ struct msm_dir_conn { unsigned int gpio; irq_hw_number_t hwirq; bool tlmm_dc; }; /** Loading @@ -129,6 +154,11 @@ struct msm_dir_conn { * @dir_conn: An array describing all the pins directly connected to GIC. * @ndirconns: The number of pins directly connected to GIC * @dir_conn_irq_base: Direct connect interrupt base register for kpss. * @gpio_mux_in: Map of GPIO pin to the hwirq. * @n_gpioc_mux_in: The number of entries in @pdc_mux_in. * @pdc_mux_out: Map of GPIO mux to PDC port. * @n_pdc_mux_out: The number of entries in @pdc_mux_out. * @n_pdc_offset: The offset for the PDC mux pins */ struct msm_pinctrl_soc_data { const struct pinctrl_pin_desc *pins; Loading @@ -142,6 +172,11 @@ struct msm_pinctrl_soc_data { const struct msm_dir_conn *dir_conn; unsigned int n_dir_conns; unsigned int dir_conn_irq_base; struct msm_pdc_mux_output *pdc_mux_out; unsigned int n_pdc_mux_out; struct msm_gpio_mux_input *gpio_mux_in; unsigned int n_gpio_mux_in; unsigned int n_pdc_mux_offset; #ifdef CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE const u32 *tile_start; const u32 *tile_offsets; Loading Loading
drivers/pinctrl/qcom/pinctrl-msm.c +234 −45 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ struct msm_pinctrl { const struct msm_pinctrl_soc_data *soc; void __iomem *regs; void __iomem *pdc_regs; #ifdef CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE /* For holding per tile virtual address */ void __iomem *per_tile_regs[4]; Loading Loading @@ -975,6 +976,158 @@ static const struct irq_domain_ops msm_gpio_domain_ops = { .free = irq_domain_free_irqs_top, }; static struct irq_chip msm_dirconn_irq_chip; static void msm_gpio_dirconn_handler(struct irq_desc *desc) { struct irq_data *irqd = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); generic_handle_irq(irqd->irq); chained_irq_exit(chip, desc); } static void setup_pdc_gpio(struct irq_domain *domain, unsigned int parent_irq, unsigned int gpio) { int irq; if (gpio != 0) { irq = irq_create_mapping(domain, gpio); irq_set_parent(irq, parent_irq); irq_set_chip(irq, &msm_dirconn_irq_chip); irq_set_handler_data(parent_irq, irq_get_irq_data(irq)); } __irq_set_handler(parent_irq, msm_gpio_dirconn_handler, false, NULL); } static void request_dc_interrupt(struct irq_domain *domain, struct irq_domain *parent, irq_hw_number_t hwirq, unsigned int gpio) { struct irq_fwspec fwspec; unsigned int parent_irq; fwspec.fwnode = parent->fwnode; fwspec.param[0] = 0; /* SPI */ fwspec.param[1] = hwirq; fwspec.param[2] = IRQ_TYPE_NONE; fwspec.param_count = 3; parent_irq = irq_create_fwspec_mapping(&fwspec); setup_pdc_gpio(domain, parent_irq, gpio); } /** * gpio_muxed_to_pdc: Mux the GPIO to a PDC IRQ * * @pdc_domain: the PDC's domain * @d: the GPIO's IRQ data * * Find a free PDC port for the GPIO and map the GPIO's mux information to the * PDC registers; so the GPIO can be used a wakeup source. */ static void gpio_muxed_to_pdc(struct irq_domain *pdc_domain, struct irq_data *d) { int i, j; unsigned int mux; struct irq_desc *desc = irq_data_to_desc(d); struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq); struct gpio_chip *gc = irq_data_get_irq_chip_data(d); unsigned int gpio = d->hwirq; struct msm_pinctrl *pctrl; unsigned int irq; if (!gc || !parent_data) return; pctrl = gpiochip_get_data(gc); for (i = 0; i < pctrl->soc->n_gpio_mux_in; i++) { if (gpio != pctrl->soc->gpio_mux_in[i].gpio) continue; mux = pctrl->soc->gpio_mux_in[i].mux; for (j = 0; j < pctrl->soc->n_pdc_mux_out; j++) { struct msm_pdc_mux_output *pdc_out = &pctrl->soc->pdc_mux_out[j]; if (pdc_out->mux == mux) break; if (pdc_out->mux) continue; pdc_out->mux = gpio; irq = irq_find_mapping(pdc_domain, pdc_out->hwirq + 32); /* setup the IRQ parent for the GPIO */ setup_pdc_gpio(pctrl->chip.irqdomain, irq, gpio); /* program pdc select grp register */ writel_relaxed((mux & 0x3F), pctrl->pdc_regs + (0x14 * j)); break; } /* We have no more PDC port available */ WARN_ON(j == pctrl->soc->n_pdc_mux_out); } } static bool is_gpio_tlmm_dc(struct irq_data *d, u32 type) { const struct msm_pingroup *g; unsigned long flags; struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl; bool ret = false; unsigned int polarity = 0, offset, val; int i; void __iomem *base; if (!gc) return false; pctrl = gpiochip_get_data(gc); for (i = 0; i < pctrl->soc->n_dir_conns; i++) { struct msm_dir_conn *dir_conn = (struct msm_dir_conn *) &pctrl->soc->dir_conn[i]; if (dir_conn->gpio == d->hwirq && dir_conn->tlmm_dc) { ret = true; offset = pctrl->soc->dir_conn_irq_base - dir_conn->hwirq; break; } } if (!ret) return ret; if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)) return ret; /* * Since the default polarity is set to 0, change it to 1 for * Rising edge and active high interrupt type such that the line * is not inverted. */ polarity = 1; raw_spin_lock_irqsave(&pctrl->lock, flags); g = &pctrl->soc->groups[d->hwirq]; base = reassign_pctrl_reg(pctrl->soc, d->hwirq); val = readl_relaxed(base + g->dir_conn_reg + (offset * 4)); val |= polarity << 8; writel_relaxed(val, base + g->dir_conn_reg + (offset * 4)); raw_spin_unlock_irqrestore(&pctrl->lock, flags); return ret; } static bool is_gpio_dual_edge(struct irq_data *d, irq_hw_number_t *dir_conn_irq) { struct irq_desc *desc = irq_data_to_desc(d); Loading @@ -995,6 +1148,17 @@ static bool is_gpio_dual_edge(struct irq_data *d, irq_hw_number_t *dir_conn_irq) return true; } } for (i = 0; i < pctrl->soc->n_pdc_mux_out; i++) { struct msm_pdc_mux_output *dir_conn = &pctrl->soc->pdc_mux_out[i]; if (dir_conn->mux == d->hwirq && (dir_conn->hwirq + 32) != parent_data->hwirq) { *dir_conn_irq = dir_conn->hwirq + 32; return true; } } return false; } Loading @@ -1012,9 +1176,13 @@ static void msm_dirconn_irq_mask(struct irq_data *d) irq_get_irq_data(irq_find_mapping(parent_data->domain, dir_conn_irq)); if (dir_conn_data && dir_conn_data->chip->irq_mask) if (!dir_conn_data) return; if (dir_conn_data->chip->irq_mask) dir_conn_data->chip->irq_mask(dir_conn_data); } if (parent_data->chip->irq_mask) parent_data->chip->irq_mask(parent_data); } Loading Loading @@ -1065,7 +1233,10 @@ static void msm_dirconn_irq_unmask(struct irq_data *d) irq_get_irq_data(irq_find_mapping(parent_data->domain, dir_conn_irq)); if (dir_conn_data && dir_conn_data->chip->irq_unmask) if (!dir_conn_data) return; if (dir_conn_data->chip->irq_unmask) dir_conn_data->chip->irq_unmask(dir_conn_data); } if (parent_data->chip->irq_unmask) Loading Loading @@ -1264,12 +1435,12 @@ static int msm_dirconn_irq_set_type(struct irq_data *d, unsigned int type) if (!parent_data) return 0; if (type == IRQ_TYPE_EDGE_BOTH) { if (type == IRQ_TYPE_EDGE_BOTH) add_dirconn_tlmm(d, irq); } else { if (is_gpio_dual_edge(d, &irq)) else if (is_gpio_dual_edge(d, &irq)) remove_dirconn_tlmm(d, irq); } else if (is_gpio_tlmm_dc(d, type)) type = IRQ_TYPE_EDGE_RISING; if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) irq_set_handler_locked(d, handle_level_irq); Loading Loading @@ -1333,57 +1504,72 @@ static void msm_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } static void msm_gpio_dirconn_handler(struct irq_desc *desc) { struct irq_data *irqd = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); generic_handle_irq(irqd->irq); chained_irq_exit(chip, desc); } static void msm_gpio_setup_dir_connects(struct msm_pinctrl *pctrl) { struct device_node *parent_node; struct irq_domain *parent_domain; struct irq_fwspec fwspec; struct irq_domain *pdc_domain; unsigned int i; parent_node = of_irq_find_parent(pctrl->dev->of_node); if (!parent_node) return; parent_domain = irq_find_host(parent_node); if (!parent_domain) pdc_domain = irq_find_host(parent_node); if (!pdc_domain) return; fwspec.fwnode = parent_domain->fwnode; for (i = 0; i < pctrl->soc->n_dir_conns; i++) { const struct msm_dir_conn *dirconn = &pctrl->soc->dir_conn[i]; unsigned int parent_irq; int irq; struct irq_data *d; fwspec.param[0] = 0; /* SPI */ fwspec.param[1] = dirconn->hwirq; fwspec.param[2] = IRQ_TYPE_NONE; fwspec.param_count = 3; parent_irq = irq_create_fwspec_mapping(&fwspec); request_dc_interrupt(pctrl->chip.irqdomain, pdc_domain, dirconn->hwirq, dirconn->gpio); if (dirconn->gpio != 0) { irq = irq_create_mapping(pctrl->chip.irqdomain, dirconn->gpio); if (!dirconn->gpio) continue; irq_set_parent(irq, parent_irq); irq_set_chip(irq, &msm_dirconn_irq_chip); __irq_set_handler(parent_irq, msm_gpio_dirconn_handler, false, NULL); irq_set_handler_data(parent_irq, irq_get_irq_data(irq)); } else { __irq_set_handler(parent_irq, msm_gpio_dirconn_handler, false, NULL); if (!dirconn->tlmm_dc) continue; /* * If the gpio is routed through TLMM direct connect interrupts, * program the TLMM registers for this setup. */ d = irq_get_irq_data(irq_find_mapping(pctrl->chip.irqdomain, dirconn->gpio)); if (!d) continue; msm_dirconn_cfg_reg(d, pctrl->soc->dir_conn_irq_base - (u32)dirconn->hwirq); } for (i = 0; i < pctrl->soc->n_pdc_mux_out; i++) { struct msm_pdc_mux_output *pdc_out = &pctrl->soc->pdc_mux_out[i]; request_dc_interrupt(pctrl->chip.irqdomain, pdc_domain, pdc_out->hwirq, 0); } /* * Statically choose the GPIOs for mapping to PDC. Dynamic mux mapping * is very difficult. */ for (i = 0; i < pctrl->soc->n_gpio_mux_in; i++) { unsigned int irq; struct irq_data *d; struct msm_gpio_mux_input *gpio_in = &pctrl->soc->gpio_mux_in[i]; if (!gpio_in->init) continue; irq = irq_find_mapping(pctrl->chip.irqdomain, gpio_in->gpio); d = irq_get_irq_data(irq); if (!d) continue; gpio_muxed_to_pdc(pdc_domain, d); } } Loading Loading @@ -1554,6 +1740,9 @@ int msm_pinctrl_probe(struct platform_device *pdev, } #endif res = platform_get_resource(pdev, IORESOURCE_MEM, 1); pctrl->pdc_regs = devm_ioremap_resource(&pdev->dev, res); msm_pinctrl_setup_pm_reset(pctrl); pctrl->irq = platform_get_irq(pdev, 0); Loading
drivers/pinctrl/qcom/pinctrl-msm.h +37 −2 Original line number Diff line number Diff line /* * Copyright (c) 2013, Sony Mobile Communications AB. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -104,16 +105,40 @@ struct msm_pingroup { unsigned intr_detection_bit:5; unsigned intr_detection_width:5; unsigned dir_conn_en_bit:8; } }; /** * struct msm_gpio_mux_input - Map GPIO to Mux pin * @mux:: The mux pin to which the GPIO is connected to * @gpio: GPIO pin number * @init: Setup PDC connection at probe */ struct msm_gpio_mux_input { unsigned int mux; unsigned int gpio; bool init; }; /** * struct msm_pdc_mux_output - GPIO mux pin to PDC port * @mux: GPIO mux pin number * @hwirq: The PDC port (hwirq) that GPIO is connected to */ struct msm_pdc_mux_output { unsigned int mux; irq_hw_number_t hwirq; }; /** * struct msm_dir_conn - Direct GPIO connect configuration * @gpio: GPIO pin number * @hwirq: The GIC interrupt that the pin is connected to */; * @tlmm_dc: indicates if the GPIO is routed to GIC directly */ struct msm_dir_conn { unsigned int gpio; irq_hw_number_t hwirq; bool tlmm_dc; }; /** Loading @@ -129,6 +154,11 @@ struct msm_dir_conn { * @dir_conn: An array describing all the pins directly connected to GIC. * @ndirconns: The number of pins directly connected to GIC * @dir_conn_irq_base: Direct connect interrupt base register for kpss. * @gpio_mux_in: Map of GPIO pin to the hwirq. * @n_gpioc_mux_in: The number of entries in @pdc_mux_in. * @pdc_mux_out: Map of GPIO mux to PDC port. * @n_pdc_mux_out: The number of entries in @pdc_mux_out. * @n_pdc_offset: The offset for the PDC mux pins */ struct msm_pinctrl_soc_data { const struct pinctrl_pin_desc *pins; Loading @@ -142,6 +172,11 @@ struct msm_pinctrl_soc_data { const struct msm_dir_conn *dir_conn; unsigned int n_dir_conns; unsigned int dir_conn_irq_base; struct msm_pdc_mux_output *pdc_mux_out; unsigned int n_pdc_mux_out; struct msm_gpio_mux_input *gpio_mux_in; unsigned int n_gpio_mux_in; unsigned int n_pdc_mux_offset; #ifdef CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE const u32 *tile_start; const u32 *tile_offsets; Loading