Advertisement
Guest User

Untitled

a guest
Jan 15th, 2016
192
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.79 KB | None | 0 0
  1. /*
  2.  * This file is subject to the terms and conditions of the GNU General Public
  3.  * License.  See the file "COPYING" in the main directory of this archive
  4.  * for more details.
  5.  *
  6.  * Copyright (C) 2014 Jonas Gorski <jogo@openwrt.org>
  7.  */
  8.  
  9. #include <linux/ioport.h>
  10. #include <linux/irq.h>
  11. #include <linux/irqchip/chained_irq.h>
  12. #include <linux/irqchip/irq-bcm6345-ext.h>
  13. #include <linux/kernel.h>
  14. #include <linux/of.h>
  15. #include <linux/of_irq.h>
  16. #include <linux/of_address.h>
  17. #include <linux/slab.h>
  18. #include <linux/spinlock.h>
  19.  
  20. #include "irqchip.h"
  21.  
  22. #ifdef CONFIG_BCM63XX
  23. #include <asm/mach-bcm63xx/bcm63xx_irq.h>
  24.  
  25. #define VIRQ_BASE       IRQ_EXTERNAL_BASE
  26. #else
  27. #define VIRQ_BASE       0
  28. #endif
  29.  
  30. #define MAX_IRQS        4
  31.  
  32. #define EXTIRQ_CFG_SENSE    0
  33. #define EXTIRQ_CFG_STAT     1
  34. #define EXTIRQ_CFG_CLEAR    2
  35. #define EXTIRQ_CFG_MASK     3
  36. #define EXTIRQ_CFG_BOTHEDGE 4
  37. #define EXTIRQ_CFG_LEVELSENSE   5
  38.  
  39. struct intc_data {
  40.     struct irq_chip chip;
  41.     struct irq_domain *domain;
  42.     raw_spinlock_t lock;
  43.  
  44.     int parent_irq[MAX_IRQS];
  45.     void __iomem *reg;
  46.     int shift;
  47. };
  48.  
  49. static void bcm6345_ext_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
  50. {
  51.     struct intc_data *data = irq_desc_get_handler_data(desc);
  52.     struct irq_chip *chip = irq_desc_get_chip(desc);
  53.     unsigned int idx;
  54.  
  55.     chained_irq_enter(chip, desc);
  56.  
  57.     for (idx = 0; idx < MAX_IRQS; idx++) {
  58.         if (data->parent_irq[idx] != irq)
  59.             continue;
  60.  
  61.         generic_handle_irq(irq_find_mapping(data->domain, idx));
  62.     }
  63.  
  64.     chained_irq_exit(chip, desc);
  65. }
  66.  
  67. static void bcm6345_ext_intc_irq_ack(struct irq_data *data)
  68. {
  69.     struct intc_data *priv = data->domain->host_data;
  70.     irq_hw_number_t hwirq = irqd_to_hwirq(data);
  71.     u32 reg;
  72.  
  73.     raw_spin_lock(&priv->lock);
  74.     reg = __raw_readl(priv->reg);
  75.     reg |= hwirq << (EXTIRQ_CFG_CLEAR * priv->shift);
  76.     __raw_writel(reg, priv->reg);
  77.     raw_spin_unlock(&priv->lock);
  78. }
  79.  
  80. static void bcm6345_ext_intc_irq_mask(struct irq_data *data)
  81. {
  82.     struct intc_data *priv = data->domain->host_data;
  83.     irq_hw_number_t hwirq = irqd_to_hwirq(data);
  84.     u32 reg;
  85.  
  86.     raw_spin_lock(&priv->lock);
  87.     reg = __raw_readl(priv->reg);
  88.     reg &= ~(hwirq << (EXTIRQ_CFG_MASK * priv->shift));
  89.     __raw_writel(reg, priv->reg);
  90.     raw_spin_unlock(&priv->lock);
  91. }
  92.  
  93. static void bcm6345_ext_intc_irq_unmask(struct irq_data *data)
  94. {
  95.     struct intc_data *priv = data->domain->host_data;
  96.     irq_hw_number_t hwirq = irqd_to_hwirq(data);
  97.     u32 reg;
  98.  
  99.     raw_spin_lock(&priv->lock);
  100.     reg = __raw_readl(priv->reg);
  101.     reg |= hwirq << (EXTIRQ_CFG_MASK * priv->shift);
  102.     __raw_writel(reg, priv->reg);
  103.     raw_spin_unlock(&priv->lock);
  104. }
  105.  
  106. static int bcm6345_ext_intc_set_type(struct irq_data *data,
  107.                      unsigned int flow_type)
  108. {
  109.     struct intc_data *priv = data->domain->host_data;
  110.     irq_hw_number_t hwirq = irqd_to_hwirq(data);
  111.     bool levelsense = 0, sense = 0, bothedge = 0;
  112.     u32 reg;
  113.  
  114.     flow_type &= IRQ_TYPE_SENSE_MASK;
  115.  
  116.     if (flow_type == IRQ_TYPE_NONE)
  117.         flow_type = IRQ_TYPE_LEVEL_LOW;
  118.  
  119.     switch (flow_type) {
  120.     case IRQ_TYPE_EDGE_BOTH:
  121.         bothedge = 1;
  122.         break;
  123.  
  124.     case IRQ_TYPE_EDGE_RISING:
  125.         break;
  126.  
  127.     case IRQ_TYPE_EDGE_FALLING:
  128.         sense = 1;
  129.         break;
  130.  
  131.     case IRQ_TYPE_LEVEL_HIGH:
  132.         levelsense = 1;
  133.         sense = 1;
  134.         break;
  135.  
  136.     case IRQ_TYPE_LEVEL_LOW:
  137.         levelsense = 1;
  138.         break;
  139.  
  140.     default:
  141.         pr_err("bogus flow type combination given!\n");
  142.         return -EINVAL;
  143.     }
  144.  
  145.     raw_spin_lock(&priv->lock);
  146.     reg = __raw_readl(priv->reg);
  147.  
  148.     if (levelsense)
  149.         reg |= hwirq << (EXTIRQ_CFG_LEVELSENSE * priv->shift);
  150.     else
  151.         reg &= ~(hwirq << (EXTIRQ_CFG_LEVELSENSE * priv->shift));
  152.     if (sense)
  153.         reg |= hwirq << (EXTIRQ_CFG_SENSE * priv->shift);
  154.     else
  155.         reg &= ~(hwirq << (EXTIRQ_CFG_SENSE * priv->shift));
  156.     if (bothedge)
  157.         reg |= hwirq << (EXTIRQ_CFG_BOTHEDGE * priv->shift);
  158.     else
  159.         reg &= ~(hwirq << (EXTIRQ_CFG_BOTHEDGE * priv->shift));
  160.  
  161.     __raw_writel(reg, priv->reg);
  162.     raw_spin_unlock(&priv->lock);
  163.  
  164.     irqd_set_trigger_type(data, flow_type);
  165.     if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
  166.         __irq_set_handler_locked(data->irq, handle_level_irq);
  167.     else
  168.         __irq_set_handler_locked(data->irq, handle_edge_irq);
  169.  
  170.     return 0;
  171. }
  172.  
  173. static int bcm6345_ext_intc_map(struct irq_domain *d, unsigned int irq,
  174.                 irq_hw_number_t hw)
  175. {
  176.     struct intc_data *priv = d->host_data;
  177.  
  178.     irq_set_chip_and_handler(irq, &priv->chip, handle_level_irq);
  179.  
  180.     return 0;
  181. }
  182.  
  183. static const struct irq_domain_ops bcm6345_ext_domain_ops = {
  184.     .xlate = irq_domain_xlate_twocell,
  185.     .map = bcm6345_ext_intc_map,
  186. };
  187.  
  188. static int __init __bcm6345_ext_intc_init(struct device_node *node,
  189.                       int num_irqs, int *irqs,
  190.                       void __iomem *reg, int shift)
  191. {
  192.     struct intc_data *data;
  193.     unsigned int i;
  194.     int start = VIRQ_BASE;
  195.  
  196.     data = kzalloc(sizeof(*data), GFP_KERNEL);
  197.     if (!data)
  198.         return -ENOMEM;
  199.  
  200.     raw_spin_lock_init(&data->lock);
  201.  
  202.     for (i = 0; i < num_irqs; i++) {
  203.         data->parent_irq[i] = irqs[i];
  204.  
  205.         irq_set_handler_data(irqs[i], data);
  206.         irq_set_chained_handler(irqs[i], bcm6345_ext_intc_irq_handle);
  207.     }
  208.  
  209.     data->reg = reg;
  210.     data->shift = shift;
  211.  
  212.     data->chip.name = "bcm6345-ext-intc";
  213.     data->chip.irq_ack = bcm6345_ext_intc_irq_ack;
  214.     data->chip.irq_mask = bcm6345_ext_intc_irq_mask;
  215.     data->chip.irq_unmask = bcm6345_ext_intc_irq_unmask;
  216.     data->chip.irq_set_type = bcm6345_ext_intc_set_type;
  217.  
  218.     /*
  219.      * If we have less than 4 irqs, this is the second controller on
  220.      * bcm63xx. So increase the VIRQ start to not overlap with the first
  221.      * one, but only do so if we actually use a non-zero start.
  222.      *
  223.      * This can be removed when bcm63xx has no legacy users anymore.
  224.      */
  225.     if (start && num_irqs < 4)
  226.         start += 4;
  227.  
  228.     data->domain = irq_domain_add_simple(node, num_irqs, start,
  229.                          &bcm6345_ext_domain_ops, data);
  230.     if (!data->domain) {
  231.         kfree(data);
  232.         return -ENOMEM;
  233.     }
  234.  
  235.     return 0;
  236. }
  237.  
  238. void __init bcm6345_ext_intc_init(int num_irqs, int *irqs, void __iomem *reg,
  239.                   int shift)
  240. {
  241.     __bcm6345_ext_intc_init(NULL, num_irqs, irqs, reg, shift);
  242. }
  243.  
  244. #ifdef CONFIG_OF
  245. static int __init bcm6345_ext_intc_of_init(struct device_node *node,
  246.                        struct device_node *parent)
  247. {
  248.     int num_irqs, ret = -EINVAL;
  249.     unsigned i;
  250.     void __iomem *base;
  251.     int irqs[MAX_IRQS] = { 0 };
  252.     u32 shift;
  253.  
  254.     num_irqs = of_irq_count(node);
  255.  
  256.     if (!num_irqs || num_irqs > MAX_IRQS)
  257.         return -EINVAL;
  258.  
  259.     if (of_property_read_u32(node, "brcm,field-width", &shift))
  260.         shift = 4;
  261.  
  262.     for (i = 0; i < num_irqs; i++) {
  263.         irqs[i] = irq_of_parse_and_map(node, i);
  264.         if (!irqs[i]) {
  265.             ret = -ENOMEM;
  266.             goto out_unmap;
  267.         }
  268.     }
  269.  
  270.     base = of_iomap(node, 0);
  271.     if (!base)
  272.         goto out_unmap;
  273.  
  274.     ret = __bcm6345_ext_intc_init(node, num_irqs, irqs, base, shift);
  275.     if (!ret)
  276.         return 0;
  277. out_unmap:
  278.     iounmap(base);
  279.  
  280.     for (i = 0; i < num_irqs; i++)
  281.         irq_dispose_mapping(irqs[i]);
  282.  
  283.     return ret;
  284. }
  285.  
  286. IRQCHIP_DECLARE(bcm6345_ext_intc, "brcm,bcm6345-ext-intc",
  287.         bcm6345_ext_intc_of_init);
  288. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement