@@ -70,35 +70,12 @@ struct tegra_gpio {
void __iomem *base;
};
-static const struct tegra_gpio_port *
-tegra186_gpio_get_port(struct tegra_gpio *gpio, unsigned int *pin)
-{
- unsigned int start = 0, i;
-
- for (i = 0; i < gpio->soc->num_ports; i++) {
- const struct tegra_gpio_port *port = &gpio->soc->ports[i];
-
- if (*pin >= start && *pin < start + port->pins) {
- *pin -= start;
- return port;
- }
-
- start += port->pins;
- }
-
- return NULL;
-}
-
static void __iomem *tegra186_gpio_get_base(struct tegra_gpio *gpio,
unsigned int pin)
{
- const struct tegra_gpio_port *port;
-
- port = tegra186_gpio_get_port(gpio, &pin);
- if (!port)
- return NULL;
+ const struct tegra_gpio_port *port = &gpio->soc->ports[pin / 8];
- return gpio->base + port->offset + pin * 0x20;
+ return gpio->base + port->offset + (pin % 8) * 0x20;
}
static int tegra186_gpio_get_direction(struct gpio_chip *chip,
@@ -208,68 +185,6 @@ static void tegra186_gpio_set(struct gpio_chip *chip, unsigned int offset,
writel(value, base + TEGRA186_GPIO_OUTPUT_VALUE);
}
-static int tegra186_gpio_of_xlate(struct gpio_chip *chip,
- const struct of_phandle_args *spec,
- u32 *flags)
-{
- struct tegra_gpio *gpio = gpiochip_get_data(chip);
- unsigned int port, pin, i, offset = 0;
-
- if (WARN_ON(chip->of_gpio_n_cells < 2))
- return -EINVAL;
-
- if (WARN_ON(spec->args_count < chip->of_gpio_n_cells))
- return -EINVAL;
-
- port = spec->args[0] / 8;
- pin = spec->args[0] % 8;
-
- if (port >= gpio->soc->num_ports) {
- dev_err(chip->parent, "invalid port number: %u\n", port);
- return -EINVAL;
- }
-
- for (i = 0; i < port; i++)
- offset += gpio->soc->ports[i].pins;
-
- if (flags)
- *flags = spec->args[1];
-
- return offset + pin;
-}
-
-static int tegra186_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
-{
- struct tegra_gpio *gpio = gpiochip_get_data(chip);
- struct irq_domain *domain = chip->irq.domain;
-
- if (!gpiochip_irqchip_irq_valid(chip, offset))
- return -ENXIO;
-
- if (irq_domain_is_hierarchy(domain)) {
- struct irq_fwspec spec;
- unsigned int i;
-
- for (i = 0; i < gpio->soc->num_ports; i++) {
- if (offset < gpio->soc->ports[i].pins)
- break;
-
- offset -= gpio->soc->ports[i].pins;
- }
-
- offset += i * 8;
-
- spec.fwnode = domain->fwnode;
- spec.param_count = 2;
- spec.param[0] = offset;
- spec.param[1] = 0;
-
- return irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, &spec);
- }
-
- return irq_create_mapping(domain, offset);
-}
-
static void tegra186_irq_ack(struct irq_data *data)
{
struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
@@ -372,7 +287,7 @@ static void tegra186_gpio_irq(struct irq_desc *desc)
struct irq_domain *domain = gpio->gpio.irq.domain;
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned int parent = irq_desc_get_irq(desc);
- unsigned int i, offset = 0;
+ unsigned int i;
chained_irq_enter(chip, desc);
@@ -384,20 +299,17 @@ static void tegra186_gpio_irq(struct irq_desc *desc)
/* skip ports that are not associated with this controller */
if (parent != gpio->irq[port->irq])
- goto skip;
+ continue;
value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1));
for_each_set_bit(pin, &value, port->pins) {
- irq = irq_find_mapping(domain, offset + pin);
+ irq = irq_find_mapping(domain, i * 8 + pin);
if (WARN_ON(irq == 0))
continue;
generic_handle_irq(irq);
}
-
-skip:
- offset += port->pins;
}
chained_irq_exit(chip, desc);
@@ -409,7 +321,7 @@ static int tegra186_gpio_irq_domain_translate(struct irq_domain *domain,
unsigned int *type)
{
struct tegra_gpio *gpio = gpiochip_get_data(domain->host_data);
- unsigned int port, pin, i, offset = 0;
+ unsigned int port, pin;
if (WARN_ON(gpio->gpio.of_gpio_n_cells < 2))
return -EINVAL;
@@ -423,11 +335,8 @@ static int tegra186_gpio_irq_domain_translate(struct irq_domain *domain,
if (port >= gpio->soc->num_ports)
return -EINVAL;
- for (i = 0; i < port; i++)
- offset += gpio->soc->ports[i].pins;
-
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
- *hwirq = offset + pin;
+ *hwirq = port * 8 + pin;
return 0;
}
@@ -466,6 +375,43 @@ static const struct irq_domain_ops tegra186_gpio_irq_domain_ops = {
.unmap = gpiochip_irq_unmap,
};
+static void tegra186_gpio_set_valid_mask(struct tegra_gpio *gpio,
+ unsigned long *mask)
+{
+ unsigned int i;
+
+ bitmap_zero(mask, gpio->gpio.ngpio);
+
+ for (i = 0; i < gpio->soc->num_ports; i++) {
+ const struct tegra_gpio_port *port = &gpio->soc->ports[i];
+
+ bitmap_set(mask, i * 8, port->pins);
+ }
+}
+
+static int tegra186_gpio_init_valid_mask(struct gpio_chip *chip)
+{
+ struct tegra_gpio *gpio = gpiochip_get_data(chip);
+
+ tegra186_gpio_set_valid_mask(gpio, chip->valid_mask);
+
+ return 0;
+}
+
+static unsigned long *tegra186_gpio_setup_valid_mask(struct tegra_gpio *gpio)
+{
+ unsigned long *mask;
+
+ mask = devm_kcalloc(gpio->gpio.parent, BITS_TO_LONGS(gpio->gpio.ngpio),
+ sizeof(*mask), GFP_KERNEL);
+ if (!mask)
+ return ERR_PTR(-ENOMEM);
+
+ tegra186_gpio_set_valid_mask(gpio, mask);
+
+ return mask;
+}
+
static const struct of_device_id tegra186_pmc_of_match[] = {
{ .compatible = "nvidia,tegra186-pmc" },
{ .compatible = "nvidia,tegra194-pmc" },
@@ -474,11 +420,11 @@ static const struct of_device_id tegra186_pmc_of_match[] = {
static int tegra186_gpio_probe(struct platform_device *pdev)
{
- unsigned int i, j, offset;
struct gpio_irq_chip *irq;
struct tegra_gpio *gpio;
struct device_node *np;
struct resource *res;
+ unsigned int i, j;
char **names;
int err;
@@ -521,17 +467,15 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
gpio->gpio.get = tegra186_gpio_get,
gpio->gpio.set = tegra186_gpio_set;
+ gpio->gpio.ngpio = gpio->soc->num_ports * 8;
gpio->gpio.base = -1;
- for (i = 0; i < gpio->soc->num_ports; i++)
- gpio->gpio.ngpio += gpio->soc->ports[i].pins;
-
names = devm_kcalloc(gpio->gpio.parent, gpio->gpio.ngpio,
sizeof(*names), GFP_KERNEL);
if (!names)
return -ENOMEM;
- for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) {
+ for (i = 0; i < gpio->soc->num_ports; i++) {
const struct tegra_gpio_port *port = &gpio->soc->ports[i];
char *name;
@@ -541,18 +485,17 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
if (!name)
return -ENOMEM;
- names[offset + j] = name;
+ names[i * 8 + j] = name;
}
-
- offset += port->pins;
}
gpio->gpio.names = (const char * const *)names;
gpio->gpio.of_node = pdev->dev.of_node;
gpio->gpio.of_gpio_n_cells = 2;
- gpio->gpio.of_xlate = tegra186_gpio_of_xlate;
- gpio->gpio.to_irq = tegra186_gpio_to_irq;
+
+ gpio->gpio.init_valid_mask = tegra186_gpio_init_valid_mask;
+ gpio->gpio.need_valid_mask = true;
gpio->intc.name = pdev->dev.of_node->name;
gpio->intc.irq_ack = tegra186_irq_ack;
@@ -580,18 +523,22 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
return -EPROBE_DEFER;
}
+ irq->valid_mask = tegra186_gpio_setup_valid_mask(gpio);
+ if (IS_ERR(irq->valid_mask))
+ return PTR_ERR(irq->valid_mask);
+
+ irq->need_valid_mask = true;
+
irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
sizeof(*irq->map), GFP_KERNEL);
if (!irq->map)
return -ENOMEM;
- for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) {
+ for (i = 0; i < gpio->soc->num_ports; i++) {
const struct tegra_gpio_port *port = &gpio->soc->ports[i];
for (j = 0; j < port->pins; j++)
- irq->map[offset + j] = irq->parents[port->irq];
-
- offset += port->pins;
+ irq->map[i * 8 + j] = irq->parents[port->irq];
}
platform_set_drvdata(pdev, gpio);