linux/arch/arm/plat-samsung/irq-uart.c
<<
>>
Prefs
   1/* arch/arm/plat-samsung/irq-uart.c
   2 *      originally part of arch/arm/plat-s3c64xx/irq.c
   3 *
   4 * Copyright 2008 Openmoko, Inc.
   5 * Copyright 2008 Simtec Electronics
   6 *      Ben Dooks <ben@simtec.co.uk>
   7 *      http://armlinux.simtec.co.uk/
   8 *
   9 * Samsung- UART Interrupt handling
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License version 2 as
  13 * published by the Free Software Foundation.
  14 */
  15
  16#include <linux/kernel.h>
  17#include <linux/interrupt.h>
  18#include <linux/serial_core.h>
  19#include <linux/irq.h>
  20#include <linux/io.h>
  21
  22#include <mach/map.h>
  23#include <plat/irq-uart.h>
  24#include <plat/regs-serial.h>
  25#include <plat/cpu.h>
  26
  27/* Note, we make use of the fact that the parent IRQs, IRQ_UART[0..3]
  28 * are consecutive when looking up the interrupt in the demux routines.
  29 */
  30
  31static inline void __iomem *s3c_irq_uart_base(struct irq_data *data)
  32{
  33        struct s3c_uart_irq *uirq = irq_data_get_irq_chip_data(data);
  34        return uirq->regs;
  35}
  36
  37static inline unsigned int s3c_irq_uart_bit(unsigned int irq)
  38{
  39        return irq & 3;
  40}
  41
  42static void s3c_irq_uart_mask(struct irq_data *data)
  43{
  44        void __iomem *regs = s3c_irq_uart_base(data);
  45        unsigned int bit = s3c_irq_uart_bit(data->irq);
  46        u32 reg;
  47
  48        reg = __raw_readl(regs + S3C64XX_UINTM);
  49        reg |= (1 << bit);
  50        __raw_writel(reg, regs + S3C64XX_UINTM);
  51}
  52
  53static void s3c_irq_uart_maskack(struct irq_data *data)
  54{
  55        void __iomem *regs = s3c_irq_uart_base(data);
  56        unsigned int bit = s3c_irq_uart_bit(data->irq);
  57        u32 reg;
  58
  59        reg = __raw_readl(regs + S3C64XX_UINTM);
  60        reg |= (1 << bit);
  61        __raw_writel(reg, regs + S3C64XX_UINTM);
  62        __raw_writel(1 << bit, regs + S3C64XX_UINTP);
  63}
  64
  65static void s3c_irq_uart_unmask(struct irq_data *data)
  66{
  67        void __iomem *regs = s3c_irq_uart_base(data);
  68        unsigned int bit = s3c_irq_uart_bit(data->irq);
  69        u32 reg;
  70
  71        reg = __raw_readl(regs + S3C64XX_UINTM);
  72        reg &= ~(1 << bit);
  73        __raw_writel(reg, regs + S3C64XX_UINTM);
  74}
  75
  76static void s3c_irq_uart_ack(struct irq_data *data)
  77{
  78        void __iomem *regs = s3c_irq_uart_base(data);
  79        unsigned int bit = s3c_irq_uart_bit(data->irq);
  80
  81        __raw_writel(1 << bit, regs + S3C64XX_UINTP);
  82}
  83
  84static void s3c_irq_demux_uart(unsigned int irq, struct irq_desc *desc)
  85{
  86        struct s3c_uart_irq *uirq = desc->irq_data.handler_data;
  87        u32 pend = __raw_readl(uirq->regs + S3C64XX_UINTP);
  88        int base = uirq->base_irq;
  89
  90        if (pend & (1 << 0))
  91                generic_handle_irq(base);
  92        if (pend & (1 << 1))
  93                generic_handle_irq(base + 1);
  94        if (pend & (1 << 2))
  95                generic_handle_irq(base + 2);
  96        if (pend & (1 << 3))
  97                generic_handle_irq(base + 3);
  98}
  99
 100static struct irq_chip s3c_irq_uart = {
 101        .name           = "s3c-uart",
 102        .irq_mask       = s3c_irq_uart_mask,
 103        .irq_unmask     = s3c_irq_uart_unmask,
 104        .irq_mask_ack   = s3c_irq_uart_maskack,
 105        .irq_ack        = s3c_irq_uart_ack,
 106};
 107
 108static void __init s3c_init_uart_irq(struct s3c_uart_irq *uirq)
 109{
 110        struct irq_desc *desc = irq_to_desc(uirq->parent_irq);
 111        void __iomem *reg_base = uirq->regs;
 112        unsigned int irq;
 113        int offs;
 114
 115        /* mask all interrupts at the start. */
 116        __raw_writel(0xf, reg_base + S3C64XX_UINTM);
 117
 118        for (offs = 0; offs < 3; offs++) {
 119                irq = uirq->base_irq + offs;
 120
 121                set_irq_chip(irq, &s3c_irq_uart);
 122                set_irq_chip_data(irq, uirq);
 123                set_irq_handler(irq, handle_level_irq);
 124                set_irq_flags(irq, IRQF_VALID);
 125        }
 126
 127        desc->irq_data.handler_data = uirq;
 128        set_irq_chained_handler(uirq->parent_irq, s3c_irq_demux_uart);
 129}
 130
 131/**
 132 * s3c_init_uart_irqs() - initialise UART IRQs and the necessary demuxing
 133 * @irq: The interrupt data for registering
 134 * @nr_irqs: The number of interrupt descriptions in @irq.
 135 *
 136 * Register the UART interrupts specified by @irq including the demuxing
 137 * routines. This supports the S3C6400 and newer style of devices.
 138 */
 139void __init s3c_init_uart_irqs(struct s3c_uart_irq *irq, unsigned int nr_irqs)
 140{
 141        for (; nr_irqs > 0; nr_irqs--, irq++)
 142                s3c_init_uart_irq(irq);
 143}
 144