1b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan/* 2b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * IMG PowerDown Controller (PDC) 3b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * 4b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * Copyright 2010-2013 Imagination Technologies Ltd. 5b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * 6b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * Exposes the syswake and PDC peripheral wake interrupts to the system. 7b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * 8b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan */ 9b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 10b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#include <linux/bitops.h> 11b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#include <linux/interrupt.h> 12b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#include <linux/irqdomain.h> 13b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#include <linux/io.h> 14b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#include <linux/kernel.h> 15b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#include <linux/of.h> 16b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#include <linux/platform_device.h> 17b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#include <linux/spinlock.h> 18b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 19b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan/* PDC interrupt register numbers */ 20b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 21b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_STATUS 0x310 22b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_ENABLE 0x314 23b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_CLEAR 0x318 24b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_ROUTE 0x31c 25b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_SYS_WAKE_BASE 0x330 26b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_SYS_WAKE_STRIDE 0x8 27b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_SYS_WAKE_CONFIG_BASE 0x334 28b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_SYS_WAKE_CONFIG_STRIDE 0x8 29b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 30b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan/* PDC interrupt register field masks */ 31b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 32b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_SYS3 0x08 33b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_SYS2 0x04 34b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_SYS1 0x02 35b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_SYS0 0x01 36b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_ROUTE_WU_EN_SYS3 0x08000000 37b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_ROUTE_WU_EN_SYS2 0x04000000 38b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_ROUTE_WU_EN_SYS1 0x02000000 39b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_ROUTE_WU_EN_SYS0 0x01000000 40b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_ROUTE_WU_EN_WD 0x00040000 41b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_ROUTE_WU_EN_IR 0x00020000 42b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_ROUTE_WU_EN_RTC 0x00010000 43b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_ROUTE_EXT_EN_SYS3 0x00000800 44b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_ROUTE_EXT_EN_SYS2 0x00000400 45b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_ROUTE_EXT_EN_SYS1 0x00000200 46b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_ROUTE_EXT_EN_SYS0 0x00000100 47b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_ROUTE_EXT_EN_WD 0x00000004 48b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_ROUTE_EXT_EN_IR 0x00000002 49b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_IRQ_ROUTE_EXT_EN_RTC 0x00000001 50b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_SYS_WAKE_RESET 0x00000010 51b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_SYS_WAKE_INT_MODE 0x0000000e 52b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_SYS_WAKE_INT_MODE_SHIFT 1 53b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_SYS_WAKE_PIN_VAL 0x00000001 54b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 55b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan/* PDC interrupt constants */ 56b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 57b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_SYS_WAKE_INT_LOW 0x0 58b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_SYS_WAKE_INT_HIGH 0x1 59b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_SYS_WAKE_INT_DOWN 0x2 60b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_SYS_WAKE_INT_UP 0x3 61b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_SYS_WAKE_INT_CHANGE 0x6 62b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define PDC_SYS_WAKE_INT_NONE 0x4 63b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 64b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan/** 65b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * struct pdc_intc_priv - private pdc interrupt data. 66b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * @nr_perips: Number of peripheral interrupt signals. 67b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * @nr_syswakes: Number of syswake signals. 68b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * @perip_irqs: List of peripheral IRQ numbers handled. 69b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * @syswake_irq: Shared PDC syswake IRQ number. 70b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * @domain: IRQ domain for PDC peripheral and syswake IRQs. 71b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * @pdc_base: Base of PDC registers. 72b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * @irq_route: Cached version of PDC_IRQ_ROUTE register. 73b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * @lock: Lock to protect the PDC syswake registers and the cached 74b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * values of those registers in this struct. 75b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan */ 76b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstruct pdc_intc_priv { 77b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int nr_perips; 78b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int nr_syswakes; 79b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int *perip_irqs; 80b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int syswake_irq; 81b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan struct irq_domain *domain; 82b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan void __iomem *pdc_base; 83b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 84b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan u32 irq_route; 85b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan raw_spinlock_t lock; 86b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan}; 87b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 88b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic void pdc_write(struct pdc_intc_priv *priv, unsigned int reg_offs, 89b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int data) 90b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan{ 91b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan iowrite32(data, priv->pdc_base + reg_offs); 92b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan} 93b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 94b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic unsigned int pdc_read(struct pdc_intc_priv *priv, 95b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int reg_offs) 96b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan{ 97b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return ioread32(priv->pdc_base + reg_offs); 98b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan} 99b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 100b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan/* Generic IRQ callbacks */ 101b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 102b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan#define SYS0_HWIRQ 8 103b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 104b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic unsigned int hwirq_is_syswake(irq_hw_number_t hw) 105b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan{ 106b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return hw >= SYS0_HWIRQ; 107b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan} 108b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 109b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic unsigned int hwirq_to_syswake(irq_hw_number_t hw) 110b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan{ 111b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return hw - SYS0_HWIRQ; 112b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan} 113b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 114b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic irq_hw_number_t syswake_to_hwirq(unsigned int syswake) 115b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan{ 116b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return SYS0_HWIRQ + syswake; 117b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan} 118b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 119b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic struct pdc_intc_priv *irqd_to_priv(struct irq_data *data) 120b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan{ 121b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return (struct pdc_intc_priv *)data->domain->host_data; 122b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan} 123b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 124b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan/* 125b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * perip_irq_mask() and perip_irq_unmask() use IRQ_ROUTE which also contains 126b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * wake bits, therefore we cannot use the generic irqchip mask callbacks as they 127b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * cache the mask. 128b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan */ 129b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 130b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic void perip_irq_mask(struct irq_data *data) 131b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan{ 132b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan struct pdc_intc_priv *priv = irqd_to_priv(data); 133b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 134b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan raw_spin_lock(&priv->lock); 135b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv->irq_route &= ~data->mask; 136b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan pdc_write(priv, PDC_IRQ_ROUTE, priv->irq_route); 137b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan raw_spin_unlock(&priv->lock); 138b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan} 139b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 140b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic void perip_irq_unmask(struct irq_data *data) 141b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan{ 142b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan struct pdc_intc_priv *priv = irqd_to_priv(data); 143b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 144b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan raw_spin_lock(&priv->lock); 145b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv->irq_route |= data->mask; 146b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan pdc_write(priv, PDC_IRQ_ROUTE, priv->irq_route); 147b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan raw_spin_unlock(&priv->lock); 148b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan} 149b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 150b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic int syswake_irq_set_type(struct irq_data *data, unsigned int flow_type) 151b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan{ 152b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan struct pdc_intc_priv *priv = irqd_to_priv(data); 153b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int syswake = hwirq_to_syswake(data->hwirq); 154b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int irq_mode; 155b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int soc_sys_wake_regoff, soc_sys_wake; 156b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 157b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* translate to syswake IRQ mode */ 158b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan switch (flow_type) { 159b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan case IRQ_TYPE_EDGE_BOTH: 160b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq_mode = PDC_SYS_WAKE_INT_CHANGE; 161b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan break; 162b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan case IRQ_TYPE_EDGE_RISING: 163b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq_mode = PDC_SYS_WAKE_INT_UP; 164b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan break; 165b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan case IRQ_TYPE_EDGE_FALLING: 166b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq_mode = PDC_SYS_WAKE_INT_DOWN; 167b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan break; 168b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan case IRQ_TYPE_LEVEL_HIGH: 169b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq_mode = PDC_SYS_WAKE_INT_HIGH; 170b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan break; 171b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan case IRQ_TYPE_LEVEL_LOW: 172b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq_mode = PDC_SYS_WAKE_INT_LOW; 173b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan break; 174b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan default: 175b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return -EINVAL; 176b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan } 177b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 178b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan raw_spin_lock(&priv->lock); 179b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 180b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* set the IRQ mode */ 181b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan soc_sys_wake_regoff = PDC_SYS_WAKE_BASE + syswake*PDC_SYS_WAKE_STRIDE; 182b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan soc_sys_wake = pdc_read(priv, soc_sys_wake_regoff); 183b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan soc_sys_wake &= ~PDC_SYS_WAKE_INT_MODE; 184b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan soc_sys_wake |= irq_mode << PDC_SYS_WAKE_INT_MODE_SHIFT; 185b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan pdc_write(priv, soc_sys_wake_regoff, soc_sys_wake); 186b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 187b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* and update the handler */ 188b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq_setup_alt_chip(data, flow_type); 189b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 190b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan raw_spin_unlock(&priv->lock); 191b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 192b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return 0; 193b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan} 194b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 195b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan/* applies to both peripheral and syswake interrupts */ 196b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic int pdc_irq_set_wake(struct irq_data *data, unsigned int on) 197b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan{ 198b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan struct pdc_intc_priv *priv = irqd_to_priv(data); 199b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq_hw_number_t hw = data->hwirq; 200b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int mask = (1 << 16) << hw; 201b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int dst_irq; 202b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 203b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan raw_spin_lock(&priv->lock); 204b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (on) 205b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv->irq_route |= mask; 206b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan else 207b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv->irq_route &= ~mask; 208b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan pdc_write(priv, PDC_IRQ_ROUTE, priv->irq_route); 209b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan raw_spin_unlock(&priv->lock); 210b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 211b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* control the destination IRQ wakeup too for standby mode */ 212b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (hwirq_is_syswake(hw)) 213b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan dst_irq = priv->syswake_irq; 214b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan else 215b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan dst_irq = priv->perip_irqs[hw]; 216b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq_set_irq_wake(dst_irq, on); 217b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 218b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return 0; 219b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan} 220b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 221b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic void pdc_intc_perip_isr(unsigned int irq, struct irq_desc *desc) 222b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan{ 223b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan struct pdc_intc_priv *priv; 224b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int i, irq_no; 225b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 226b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv = (struct pdc_intc_priv *)irq_desc_get_handler_data(desc); 227b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 228b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* find the peripheral number */ 229b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan for (i = 0; i < priv->nr_perips; ++i) 230b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (irq == priv->perip_irqs[i]) 231b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan goto found; 232b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 233b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* should never get here */ 234b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return; 235b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganfound: 236b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 237b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* pass on the interrupt */ 238b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq_no = irq_linear_revmap(priv->domain, i); 239b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan generic_handle_irq(irq_no); 240b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan} 241b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 242b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic void pdc_intc_syswake_isr(unsigned int irq, struct irq_desc *desc) 243b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan{ 244b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan struct pdc_intc_priv *priv; 245b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int syswake, irq_no; 246b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int status; 247b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 248b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv = (struct pdc_intc_priv *)irq_desc_get_handler_data(desc); 249b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 250b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan status = pdc_read(priv, PDC_IRQ_STATUS) & 251b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan pdc_read(priv, PDC_IRQ_ENABLE); 252b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan status &= (1 << priv->nr_syswakes) - 1; 253b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 254b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan for (syswake = 0; status; status >>= 1, ++syswake) { 255b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* Has this sys_wake triggered? */ 256b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (!(status & 1)) 257b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan continue; 258b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 259b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq_no = irq_linear_revmap(priv->domain, 260b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan syswake_to_hwirq(syswake)); 261b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan generic_handle_irq(irq_no); 262b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan } 263b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan} 264b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 265b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic void pdc_intc_setup(struct pdc_intc_priv *priv) 266b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan{ 267b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan int i; 268b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int soc_sys_wake_regoff; 269b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int soc_sys_wake; 270b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 271b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* 272b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * Mask all syswake interrupts before routing, or we could receive an 273b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * interrupt before we're ready to handle it. 274b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan */ 275b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan pdc_write(priv, PDC_IRQ_ENABLE, 0); 276b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 277b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* 278b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * Enable routing of all syswakes 279b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * Disable all wake sources 280b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan */ 281b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv->irq_route = ((PDC_IRQ_ROUTE_EXT_EN_SYS0 << priv->nr_syswakes) - 282b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan PDC_IRQ_ROUTE_EXT_EN_SYS0); 283b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan pdc_write(priv, PDC_IRQ_ROUTE, priv->irq_route); 284b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 285b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* Initialise syswake IRQ */ 286b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan for (i = 0; i < priv->nr_syswakes; ++i) { 287b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* set the IRQ mode to none */ 288b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan soc_sys_wake_regoff = PDC_SYS_WAKE_BASE + i*PDC_SYS_WAKE_STRIDE; 289b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan soc_sys_wake = PDC_SYS_WAKE_INT_NONE 290b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan << PDC_SYS_WAKE_INT_MODE_SHIFT; 291b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan pdc_write(priv, soc_sys_wake_regoff, soc_sys_wake); 292b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan } 293b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan} 294b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 295b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic int pdc_intc_probe(struct platform_device *pdev) 296b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan{ 297b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan struct pdc_intc_priv *priv; 298b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan struct device_node *node = pdev->dev.of_node; 299b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan struct resource *res_regs; 300b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan struct irq_chip_generic *gc; 301b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan unsigned int i; 302b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan int irq, ret; 303b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan u32 val; 304b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 305b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (!node) 306b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return -ENOENT; 307b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 308b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* Get registers */ 309b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 310b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (res_regs == NULL) { 311b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan dev_err(&pdev->dev, "cannot find registers resource\n"); 312b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return -ENOENT; 313b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan } 314b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 315b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* Allocate driver data */ 316b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 317b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (!priv) { 318b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan dev_err(&pdev->dev, "cannot allocate device data\n"); 319b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return -ENOMEM; 320b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan } 321b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan raw_spin_lock_init(&priv->lock); 322b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan platform_set_drvdata(pdev, priv); 323b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 324b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* Ioremap the registers */ 325b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv->pdc_base = devm_ioremap(&pdev->dev, res_regs->start, 326b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan res_regs->end - res_regs->start); 327b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (!priv->pdc_base) 328b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return -EIO; 329b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 330b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* Get number of peripherals */ 331b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan ret = of_property_read_u32(node, "num-perips", &val); 332b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (ret) { 333b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan dev_err(&pdev->dev, "No num-perips node property found\n"); 334b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return -EINVAL; 335b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan } 336b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (val > SYS0_HWIRQ) { 337b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan dev_err(&pdev->dev, "num-perips (%u) out of range\n", val); 338b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return -EINVAL; 339b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan } 340b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv->nr_perips = val; 341b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 342b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* Get number of syswakes */ 343b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan ret = of_property_read_u32(node, "num-syswakes", &val); 344b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (ret) { 345b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan dev_err(&pdev->dev, "No num-syswakes node property found\n"); 346b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return -EINVAL; 347b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan } 348b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (val > SYS0_HWIRQ) { 349b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan dev_err(&pdev->dev, "num-syswakes (%u) out of range\n", val); 350b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return -EINVAL; 351b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan } 352b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv->nr_syswakes = val; 353b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 354b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* Get peripheral IRQ numbers */ 355b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv->perip_irqs = devm_kzalloc(&pdev->dev, 4 * priv->nr_perips, 356b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan GFP_KERNEL); 357b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (!priv->perip_irqs) { 358b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan dev_err(&pdev->dev, "cannot allocate perip IRQ list\n"); 359b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return -ENOMEM; 360b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan } 361b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan for (i = 0; i < priv->nr_perips; ++i) { 362b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq = platform_get_irq(pdev, 1 + i); 363b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (irq < 0) { 364b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan dev_err(&pdev->dev, "cannot find perip IRQ #%u\n", i); 365b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return irq; 366b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan } 367b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv->perip_irqs[i] = irq; 368b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan } 369b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* check if too many were provided */ 370b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (platform_get_irq(pdev, 1 + i) >= 0) { 371b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan dev_err(&pdev->dev, "surplus perip IRQs detected\n"); 372b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return -EINVAL; 373b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan } 374b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 375b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* Get syswake IRQ number */ 376b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq = platform_get_irq(pdev, 0); 377b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (irq < 0) { 378b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan dev_err(&pdev->dev, "cannot find syswake IRQ\n"); 379b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return irq; 380b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan } 381b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv->syswake_irq = irq; 382b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 383b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* Set up an IRQ domain */ 384b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv->domain = irq_domain_add_linear(node, 16, &irq_generic_chip_ops, 385b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv); 386b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (unlikely(!priv->domain)) { 387b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan dev_err(&pdev->dev, "cannot add IRQ domain\n"); 388b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return -ENOMEM; 389b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan } 390b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 391b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* 392b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * Set up 2 generic irq chips with 2 chip types. 393b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * The first one for peripheral irqs (only 1 chip type used) 394b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * The second one for syswake irqs (edge and level chip types) 395b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan */ 396b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan ret = irq_alloc_domain_generic_chips(priv->domain, 8, 2, "pdc", 397b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan handle_level_irq, 0, 0, 398b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan IRQ_GC_INIT_NESTED_LOCK); 399b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan if (ret) 400b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan goto err_generic; 401b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 402b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* peripheral interrupt chip */ 403b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 404b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc = irq_get_domain_generic_chip(priv->domain, 0); 405b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->unused = ~(BIT(priv->nr_perips) - 1); 406b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->reg_base = priv->pdc_base; 407b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* 408b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * IRQ_ROUTE contains wake bits, so we can't use the generic versions as 409b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan * they cache the mask 410b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan */ 411b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[0].regs.mask = PDC_IRQ_ROUTE; 412b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[0].chip.irq_mask = perip_irq_mask; 413b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[0].chip.irq_unmask = perip_irq_unmask; 414b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[0].chip.irq_set_wake = pdc_irq_set_wake; 415b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 416b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* syswake interrupt chip */ 417b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 418b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc = irq_get_domain_generic_chip(priv->domain, 8); 419b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->unused = ~(BIT(priv->nr_syswakes) - 1); 420b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->reg_base = priv->pdc_base; 421b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 422b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* edge interrupts */ 423b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[0].type = IRQ_TYPE_EDGE_BOTH; 424b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[0].handler = handle_edge_irq; 425b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[0].regs.ack = PDC_IRQ_CLEAR; 426b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[0].regs.mask = PDC_IRQ_ENABLE; 427b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit; 428b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; 429b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; 430b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[0].chip.irq_set_type = syswake_irq_set_type; 431b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[0].chip.irq_set_wake = pdc_irq_set_wake; 432b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* for standby we pass on to the shared syswake IRQ */ 433b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND; 434b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 435b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* level interrupts */ 436b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[1].type = IRQ_TYPE_LEVEL_MASK; 437b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[1].handler = handle_level_irq; 438b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[1].regs.ack = PDC_IRQ_CLEAR; 439b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[1].regs.mask = PDC_IRQ_ENABLE; 440b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[1].chip.irq_ack = irq_gc_ack_set_bit; 441b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit; 442b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit; 443b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[1].chip.irq_set_type = syswake_irq_set_type; 444b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[1].chip.irq_set_wake = pdc_irq_set_wake; 445b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* for standby we pass on to the shared syswake IRQ */ 446b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND; 447b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 448b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* Set up the hardware to enable interrupt routing */ 449b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan pdc_intc_setup(priv); 450b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 451b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* Setup chained handlers for the peripheral IRQs */ 452b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan for (i = 0; i < priv->nr_perips; ++i) { 453b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq = priv->perip_irqs[i]; 454b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq_set_handler_data(irq, priv); 455b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq_set_chained_handler(irq, pdc_intc_perip_isr); 456b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan } 457b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 458b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan /* Setup chained handler for the syswake IRQ */ 459b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq_set_handler_data(priv->syswake_irq, priv); 460b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq_set_chained_handler(priv->syswake_irq, pdc_intc_syswake_isr); 461b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 462b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan dev_info(&pdev->dev, 463b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan "PDC IRQ controller initialised (%u perip IRQs, %u syswake IRQs)\n", 464b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv->nr_perips, 465b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan priv->nr_syswakes); 466b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 467b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return 0; 468b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganerr_generic: 469b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq_domain_remove(priv->domain); 470b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return ret; 471b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan} 472b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 473b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic int pdc_intc_remove(struct platform_device *pdev) 474b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan{ 475b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan struct pdc_intc_priv *priv = platform_get_drvdata(pdev); 476b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 477b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan irq_domain_remove(priv->domain); 478b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return 0; 479b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan} 480b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 481b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic const struct of_device_id pdc_intc_match[] = { 482b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan { .compatible = "img,pdc-intc" }, 483b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan {} 484b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan}; 485b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 486b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic struct platform_driver pdc_intc_driver = { 487b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan .driver = { 488b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan .name = "pdc-intc", 489b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan .of_match_table = pdc_intc_match, 490b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan }, 491b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan .probe = pdc_intc_probe, 492b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan .remove = pdc_intc_remove, 493b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan}; 494b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan 495b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hoganstatic int __init pdc_intc_init(void) 496b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan{ 497b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan return platform_driver_register(&pdc_intc_driver); 498b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogan} 499b6ef9161e43ad58c3824bd76dc87716276f0cd70James Hogancore_initcall(pdc_intc_init); 500