From 795e6bf33561ff03e253a6a756d5eb663b4a56bd Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 4 Mar 2008 15:23:45 -0800 Subject: sh: SuperH KEYSC platform driver Add a platform driver for the SuperH KEYSC block. The driver expects to get mode, timing information and keypad layout from the board code as platform data. The board code is resonsible for pin configuration. Both sh7343 and sh7722 should be supported, but only the sh7722 processor has been tested so far. SH_KEYSC_MODE_3 is yet to be tested. Signed-off-by: Magnus Damm Cc: Dmitry Torokhov Signed-off-by: Andrew Morton Signed-off-by: Paul Mundt --- drivers/input/keyboard/Kconfig | 9 ++ drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/sh_keysc.c | 281 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 291 insertions(+) create mode 100644 drivers/input/keyboard/sh_keysc.c (limited to 'drivers') diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 8ea709be3306..efd70a974591 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -314,4 +314,13 @@ config KEYBOARD_BFIN To compile this driver as a module, choose M here: the module will be called bf54x-keys. +config KEYBOARD_SH_KEYSC + tristate "SuperH KEYSC keypad support" + depends on SUPERH + help + Say Y here if you want to use a keypad attached to the KEYSC block + on SuperH processors such as sh7722 and sh7343. + + To compile this driver as a module, choose M here: the + module will be called sh_keysc. endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index e741f4031012..0edc8f285d1c 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -26,3 +26,4 @@ obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o +obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c new file mode 100644 index 000000000000..5d0864a9e94b --- /dev/null +++ b/drivers/input/keyboard/sh_keysc.c @@ -0,0 +1,281 @@ +/* + * SuperH KEYSC Keypad Driver + * + * Copyright (C) 2008 Magnus Damm + * + * Based on gpio_keys.c, Copyright 2005 Phil Blundell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KYCR1_OFFS 0x00 +#define KYCR2_OFFS 0x04 +#define KYINDR_OFFS 0x08 +#define KYOUTDR_OFFS 0x0c + +#define KYCR2_IRQ_LEVEL 0x10 +#define KYCR2_IRQ_DISABLED 0x00 + +static const struct { + unsigned char kymd, keyout, keyin; +} sh_keysc_mode[] = { + [SH_KEYSC_MODE_1] = { 0, 6, 5 }, + [SH_KEYSC_MODE_2] = { 1, 5, 6 }, + [SH_KEYSC_MODE_3] = { 2, 4, 7 }, +}; + +struct sh_keysc_priv { + void __iomem *iomem_base; + unsigned long last_keys; + struct input_dev *input; + struct sh_keysc_info pdata; +}; + +static irqreturn_t sh_keysc_isr(int irq, void *dev_id) +{ + struct platform_device *pdev = dev_id; + struct sh_keysc_priv *priv = platform_get_drvdata(pdev); + struct sh_keysc_info *pdata = &priv->pdata; + unsigned long keys, keys1, keys0, mask; + unsigned char keyin_set, tmp; + int i, k; + + dev_dbg(&pdev->dev, "isr!\n"); + + keys1 = ~0; + keys0 = 0; + + do { + keys = 0; + keyin_set = 0; + + iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS); + + for (i = 0; i < sh_keysc_mode[pdata->mode].keyout; i++) { + iowrite16(0xfff ^ (3 << (i * 2)), + priv->iomem_base + KYOUTDR_OFFS); + udelay(pdata->delay); + tmp = ioread16(priv->iomem_base + KYINDR_OFFS); + keys |= tmp << (sh_keysc_mode[pdata->mode].keyin * i); + tmp ^= (1 << sh_keysc_mode[pdata->mode].keyin) - 1; + keyin_set |= tmp; + } + + iowrite16(0, priv->iomem_base + KYOUTDR_OFFS); + iowrite16(KYCR2_IRQ_LEVEL | (keyin_set << 8), + priv->iomem_base + KYCR2_OFFS); + + keys ^= ~0; + keys &= (1 << (sh_keysc_mode[pdata->mode].keyin * + sh_keysc_mode[pdata->mode].keyout)) - 1; + keys1 &= keys; + keys0 |= keys; + + dev_dbg(&pdev->dev, "keys 0x%08lx\n", keys); + + } while (ioread16(priv->iomem_base + KYCR2_OFFS) & 0x01); + + dev_dbg(&pdev->dev, "last_keys 0x%08lx keys0 0x%08lx keys1 0x%08lx\n", + priv->last_keys, keys0, keys1); + + for (i = 0; i < SH_KEYSC_MAXKEYS; i++) { + k = pdata->keycodes[i]; + if (!k) + continue; + + mask = 1 << i; + + if (!((priv->last_keys ^ keys0) & mask)) + continue; + + if ((keys1 | keys0) & mask) { + input_event(priv->input, EV_KEY, k, 1); + priv->last_keys |= mask; + } + + if (!(keys1 & mask)) { + input_event(priv->input, EV_KEY, k, 0); + priv->last_keys &= ~mask; + } + + } + input_sync(priv->input); + + return IRQ_HANDLED; +} + +#define res_size(res) ((res)->end - (res)->start + 1) + +static int __devinit sh_keysc_probe(struct platform_device *pdev) +{ + struct sh_keysc_priv *priv; + struct sh_keysc_info *pdata; + struct resource *res; + struct input_dev *input; + int i, k; + int irq, error; + + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "no platform data defined\n"); + error = -EINVAL; + goto err0; + } + + error = -ENXIO; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "failed to get I/O memory\n"); + goto err0; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get irq\n"); + goto err0; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (priv == NULL) { + dev_err(&pdev->dev, "failed to allocate driver data\n"); + error = -ENOMEM; + goto err0; + } + + platform_set_drvdata(pdev, priv); + memcpy(&priv->pdata, pdev->dev.platform_data, sizeof(priv->pdata)); + pdata = &priv->pdata; + + res = request_mem_region(res->start, res_size(res), pdev->name); + if (res == NULL) { + dev_err(&pdev->dev, "failed to request I/O memory\n"); + error = -EBUSY; + goto err1; + } + + priv->iomem_base = ioremap_nocache(res->start, res_size(res)); + if (priv->iomem_base == NULL) { + dev_err(&pdev->dev, "failed to remap I/O memory\n"); + error = -ENXIO; + goto err2; + } + + priv->input = input_allocate_device(); + if (!priv->input) { + dev_err(&pdev->dev, "failed to allocate input device\n"); + error = -ENOMEM; + goto err3; + } + + input = priv->input; + input->evbit[0] = BIT_MASK(EV_KEY); + + input->name = pdev->name; + input->phys = "sh-keysc-keys/input0"; + input->dev.parent = &pdev->dev; + + input->id.bustype = BUS_HOST; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0100; + + error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev); + if (error) { + dev_err(&pdev->dev, "failed to request IRQ\n"); + goto err4; + } + + for (i = 0; i < SH_KEYSC_MAXKEYS; i++) { + k = pdata->keycodes[i]; + if (k) + input_set_capability(input, EV_KEY, k); + } + + error = input_register_device(input); + if (error) { + dev_err(&pdev->dev, "failed to register input device\n"); + goto err5; + } + + iowrite16((sh_keysc_mode[pdata->mode].kymd << 8) | + pdata->scan_timing, priv->iomem_base + KYCR1_OFFS); + iowrite16(0, priv->iomem_base + KYOUTDR_OFFS); + iowrite16(KYCR2_IRQ_LEVEL, priv->iomem_base + KYCR2_OFFS); + return 0; + err5: + free_irq(irq, pdev); + err4: + input_free_device(input); + err3: + iounmap(priv->iomem_base); + err2: + release_mem_region(res->start, res_size(res)); + err1: + platform_set_drvdata(pdev, NULL); + kfree(priv); + err0: + return error; +} + +static int __devexit sh_keysc_remove(struct platform_device *pdev) +{ + struct sh_keysc_priv *priv = platform_get_drvdata(pdev); + struct resource *res; + + iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS); + + input_unregister_device(priv->input); + free_irq(platform_get_irq(pdev, 0), pdev); + input_free_device(priv->input); + iounmap(priv->iomem_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res_size(res)); + + platform_set_drvdata(pdev, NULL); + kfree(priv); + return 0; +} + + +#define sh_keysc_suspend NULL +#define sh_keysc_resume NULL + +struct platform_driver sh_keysc_device_driver = { + .probe = sh_keysc_probe, + .remove = __devexit_p(sh_keysc_remove), + .suspend = sh_keysc_suspend, + .resume = sh_keysc_resume, + .driver = { + .name = "sh_keysc", + } +}; + +static int __init sh_keysc_init(void) +{ + return platform_driver_register(&sh_keysc_device_driver); +} + +static void __exit sh_keysc_exit(void) +{ + platform_driver_unregister(&sh_keysc_device_driver); +} + +module_init(sh_keysc_init); +module_exit(sh_keysc_exit); + +MODULE_AUTHOR("Magnus Damm"); +MODULE_DESCRIPTION("SuperH KEYSC Keypad Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From b420b1a7a17ea88531d0e12b2f2679a0c8365803 Mon Sep 17 00:00:00 2001 From: Angelo Castello Date: Thu, 6 Mar 2008 12:50:53 +0900 Subject: rtc: rtc-sh: Add support for periodic IRQs. This adds support for periodic IRQs to the rtc-sh driver. RTC_IRQP_READ/RTC_IRQP_SET are added, with a number of other fixes and reordering across the rest of the code. Signed-off-by: Angelo Castello Signed-off-by: Giuseppe Cavallaro Signed-off-by: Paul Mundt --- drivers/rtc/rtc-sh.c | 296 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 187 insertions(+), 109 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 9e9caa5d7f5f..c594b34c6767 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -1,8 +1,9 @@ /* * SuperH On-Chip RTC Support * - * Copyright (C) 2006, 2007 Paul Mundt + * Copyright (C) 2006, 2007, 2008 Paul Mundt * Copyright (C) 2006 Jamie Lenehan + * Copyright (C) 2008 Angelo Castello * * Based on the old arch/sh/kernel/cpu/rtc.c by: * @@ -26,7 +27,7 @@ #include #define DRV_NAME "sh-rtc" -#define DRV_VERSION "0.1.6" +#define DRV_VERSION "0.2.0" #define RTC_REG(r) ((r) * rtc_reg_size) @@ -63,6 +64,13 @@ /* ALARM Bits - or with BCD encoded value */ #define AR_ENB 0x80 /* Enable for alarm cmp */ +/* Period Bits */ +#define PF_HP 0x100 /* Enable Half Period to support 8,32,128Hz */ +#define PF_COUNT 0x200 /* Half periodic counter */ +#define PF_OXS 0x400 /* Periodic One x Second */ +#define PF_KOU 0x800 /* Kernel or User periodic request 1=kernel */ +#define PF_MASK 0xf00 + /* RCR1 Bits */ #define RCR1_CF 0x80 /* Carry Flag */ #define RCR1_CIE 0x10 /* Carry Interrupt Enable */ @@ -84,33 +92,24 @@ struct sh_rtc { unsigned int alarm_irq, periodic_irq, carry_irq; struct rtc_device *rtc_dev; spinlock_t lock; - int rearm_aie; unsigned long capabilities; /* See asm-sh/rtc.h for cap bits */ + unsigned short periodic_freq; }; static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id) { - struct platform_device *pdev = to_platform_device(dev_id); - struct sh_rtc *rtc = platform_get_drvdata(pdev); - unsigned int tmp, events = 0; + struct sh_rtc *rtc = dev_id; + unsigned int tmp; spin_lock(&rtc->lock); tmp = readb(rtc->regbase + RCR1); tmp &= ~RCR1_CF; - - if (rtc->rearm_aie) { - if (tmp & RCR1_AF) - tmp &= ~RCR1_AF; /* try to clear AF again */ - else { - tmp |= RCR1_AIE; /* AF has cleared, rearm IRQ */ - rtc->rearm_aie = 0; - } - } - writeb(tmp, rtc->regbase + RCR1); - rtc_update_irq(rtc->rtc_dev, 1, events); + /* Users have requested One x Second IRQ */ + if (rtc->periodic_freq & PF_OXS) + rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); spin_unlock(&rtc->lock); @@ -119,47 +118,48 @@ static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id) static irqreturn_t sh_rtc_alarm(int irq, void *dev_id) { - struct platform_device *pdev = to_platform_device(dev_id); - struct sh_rtc *rtc = platform_get_drvdata(pdev); - unsigned int tmp, events = 0; + struct sh_rtc *rtc = dev_id; + unsigned int tmp; spin_lock(&rtc->lock); tmp = readb(rtc->regbase + RCR1); - - /* - * If AF is set then the alarm has triggered. If we clear AF while - * the alarm time still matches the RTC time then AF will - * immediately be set again, and if AIE is enabled then the alarm - * interrupt will immediately be retrigger. So we clear AIE here - * and use rtc->rearm_aie so that the carry interrupt will keep - * trying to clear AF and once it stays cleared it'll re-enable - * AIE. - */ - if (tmp & RCR1_AF) { - events |= RTC_AF | RTC_IRQF; - - tmp &= ~(RCR1_AF|RCR1_AIE); - + tmp &= ~(RCR1_AF | RCR1_AIE); writeb(tmp, rtc->regbase + RCR1); - rtc->rearm_aie = 1; - - rtc_update_irq(rtc->rtc_dev, 1, events); - } + rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); spin_unlock(&rtc->lock); + return IRQ_HANDLED; } static irqreturn_t sh_rtc_periodic(int irq, void *dev_id) { - struct platform_device *pdev = to_platform_device(dev_id); - struct sh_rtc *rtc = platform_get_drvdata(pdev); + struct sh_rtc *rtc = dev_id; + struct rtc_device *rtc_dev = rtc->rtc_dev; + unsigned int tmp; spin_lock(&rtc->lock); - rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); + tmp = readb(rtc->regbase + RCR2); + tmp &= ~RCR2_PEF; + writeb(tmp, rtc->regbase + RCR2); + + /* Half period enabled than one skipped and the next notified */ + if ((rtc->periodic_freq & PF_HP) && (rtc->periodic_freq & PF_COUNT)) + rtc->periodic_freq &= ~PF_COUNT; + else { + if (rtc->periodic_freq & PF_HP) + rtc->periodic_freq |= PF_COUNT; + if (rtc->periodic_freq & PF_KOU) { + spin_lock(&rtc_dev->irq_task_lock); + if (rtc_dev->irq_task) + rtc_dev->irq_task->func(rtc_dev->irq_task->private_data); + spin_unlock(&rtc_dev->irq_task_lock); + } else + rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); + } spin_unlock(&rtc->lock); @@ -176,8 +176,8 @@ static inline void sh_rtc_setpie(struct device *dev, unsigned int enable) tmp = readb(rtc->regbase + RCR2); if (enable) { - tmp &= ~RCR2_PESMASK; - tmp |= RCR2_PEF | (2 << 4); + tmp &= ~RCR2_PEF; /* Clear PES bit */ + tmp |= (rtc->periodic_freq & ~PF_HP); /* Set PES2-0 */ } else tmp &= ~(RCR2_PESMASK | RCR2_PEF); @@ -186,82 +186,81 @@ static inline void sh_rtc_setpie(struct device *dev, unsigned int enable) spin_unlock_irq(&rtc->lock); } -static inline void sh_rtc_setaie(struct device *dev, unsigned int enable) +static inline int sh_rtc_setfreq(struct device *dev, unsigned int freq) { struct sh_rtc *rtc = dev_get_drvdata(dev); - unsigned int tmp; + int tmp, ret = 0; spin_lock_irq(&rtc->lock); + tmp = rtc->periodic_freq & PF_MASK; - tmp = readb(rtc->regbase + RCR1); - - if (!enable) { - tmp &= ~RCR1_AIE; - rtc->rearm_aie = 0; - } else if (rtc->rearm_aie == 0) - tmp |= RCR1_AIE; + switch (freq) { + case 0: + rtc->periodic_freq = 0x00; + break; + case 1: + rtc->periodic_freq = 0x60; + break; + case 2: + rtc->periodic_freq = 0x50; + break; + case 4: + rtc->periodic_freq = 0x40; + break; + case 8: + rtc->periodic_freq = 0x30 | PF_HP; + break; + case 16: + rtc->periodic_freq = 0x30; + break; + case 32: + rtc->periodic_freq = 0x20 | PF_HP; + break; + case 64: + rtc->periodic_freq = 0x20; + break; + case 128: + rtc->periodic_freq = 0x10 | PF_HP; + break; + case 256: + rtc->periodic_freq = 0x10; + break; + default: + ret = -ENOTSUPP; + } - writeb(tmp, rtc->regbase + RCR1); + if (ret == 0) { + rtc->periodic_freq |= tmp; + rtc->rtc_dev->irq_freq = freq; + } spin_unlock_irq(&rtc->lock); + return ret; } -static int sh_rtc_open(struct device *dev) +static inline void sh_rtc_setaie(struct device *dev, unsigned int enable) { struct sh_rtc *rtc = dev_get_drvdata(dev); unsigned int tmp; - int ret; - - tmp = readb(rtc->regbase + RCR1); - tmp &= ~RCR1_CF; - tmp |= RCR1_CIE; - writeb(tmp, rtc->regbase + RCR1); - ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, IRQF_DISABLED, - "sh-rtc period", dev); - if (unlikely(ret)) { - dev_err(dev, "request period IRQ failed with %d, IRQ %d\n", - ret, rtc->periodic_irq); - return ret; - } - - ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, IRQF_DISABLED, - "sh-rtc carry", dev); - if (unlikely(ret)) { - dev_err(dev, "request carry IRQ failed with %d, IRQ %d\n", - ret, rtc->carry_irq); - free_irq(rtc->periodic_irq, dev); - goto err_bad_carry; - } + spin_lock_irq(&rtc->lock); - ret = request_irq(rtc->alarm_irq, sh_rtc_alarm, IRQF_DISABLED, - "sh-rtc alarm", dev); - if (unlikely(ret)) { - dev_err(dev, "request alarm IRQ failed with %d, IRQ %d\n", - ret, rtc->alarm_irq); - goto err_bad_alarm; - } + tmp = readb(rtc->regbase + RCR1); - return 0; + if (!enable) + tmp &= ~RCR1_AIE; + else + tmp |= RCR1_AIE; -err_bad_alarm: - free_irq(rtc->carry_irq, dev); -err_bad_carry: - free_irq(rtc->periodic_irq, dev); + writeb(tmp, rtc->regbase + RCR1); - return ret; + spin_unlock_irq(&rtc->lock); } static void sh_rtc_release(struct device *dev) { - struct sh_rtc *rtc = dev_get_drvdata(dev); - sh_rtc_setpie(dev, 0); sh_rtc_setaie(dev, 0); - - free_irq(rtc->periodic_irq, dev); - free_irq(rtc->carry_irq, dev); - free_irq(rtc->alarm_irq, dev); } static int sh_rtc_proc(struct device *dev, struct seq_file *seq) @@ -270,31 +269,44 @@ static int sh_rtc_proc(struct device *dev, struct seq_file *seq) unsigned int tmp; tmp = readb(rtc->regbase + RCR1); - seq_printf(seq, "carry_IRQ\t: %s\n", - (tmp & RCR1_CIE) ? "yes" : "no"); + seq_printf(seq, "carry_IRQ\t: %s\n", (tmp & RCR1_CIE) ? "yes" : "no"); tmp = readb(rtc->regbase + RCR2); seq_printf(seq, "periodic_IRQ\t: %s\n", - (tmp & RCR2_PEF) ? "yes" : "no"); + (tmp & RCR2_PESMASK) ? "yes" : "no"); return 0; } static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { - unsigned int ret = -ENOIOCTLCMD; + struct sh_rtc *rtc = dev_get_drvdata(dev); + unsigned int ret = 0; switch (cmd) { case RTC_PIE_OFF: case RTC_PIE_ON: sh_rtc_setpie(dev, cmd == RTC_PIE_ON); - ret = 0; break; case RTC_AIE_OFF: case RTC_AIE_ON: sh_rtc_setaie(dev, cmd == RTC_AIE_ON); - ret = 0; break; + case RTC_UIE_OFF: + rtc->periodic_freq &= ~PF_OXS; + break; + case RTC_UIE_ON: + rtc->periodic_freq |= PF_OXS; + break; + case RTC_IRQP_READ: + ret = put_user(rtc->rtc_dev->irq_freq, + (unsigned long __user *)arg); + break; + case RTC_IRQP_SET: + ret = sh_rtc_setfreq(dev, arg); + break; + default: + ret = -ENOIOCTLCMD; } return ret; @@ -421,7 +433,7 @@ static int sh_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) { struct platform_device *pdev = to_platform_device(dev); struct sh_rtc *rtc = platform_get_drvdata(pdev); - struct rtc_time* tm = &wkalrm->time; + struct rtc_time *tm = &wkalrm->time; spin_lock_irq(&rtc->lock); @@ -452,7 +464,7 @@ static inline void sh_rtc_write_alarm_value(struct sh_rtc *rtc, writeb(BIN2BCD(value) | AR_ENB, rtc->regbase + reg_off); } -static int sh_rtc_check_alarm(struct rtc_time* tm) +static int sh_rtc_check_alarm(struct rtc_time *tm) { /* * The original rtc says anything > 0xc0 is "don't care" or "match @@ -503,11 +515,9 @@ static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) /* disable alarm interrupt and clear the alarm flag */ rcr1 = readb(rtc->regbase + RCR1); - rcr1 &= ~(RCR1_AF|RCR1_AIE); + rcr1 &= ~(RCR1_AF | RCR1_AIE); writeb(rcr1, rtc->regbase + RCR1); - rtc->rearm_aie = 0; - /* set alarm time */ sh_rtc_write_alarm_value(rtc, tm->tm_sec, RSECAR); sh_rtc_write_alarm_value(rtc, tm->tm_min, RMINAR); @@ -529,14 +539,34 @@ static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) return 0; } +static int sh_rtc_irq_set_state(struct device *dev, int enabled) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sh_rtc *rtc = platform_get_drvdata(pdev); + + if (enabled) { + rtc->periodic_freq |= PF_KOU; + return sh_rtc_ioctl(dev, RTC_PIE_ON, 0); + } else { + rtc->periodic_freq &= ~PF_KOU; + return sh_rtc_ioctl(dev, RTC_PIE_OFF, 0); + } +} + +static int sh_rtc_irq_set_freq(struct device *dev, int freq) +{ + return sh_rtc_ioctl(dev, RTC_IRQP_SET, freq); +} + static struct rtc_class_ops sh_rtc_ops = { - .open = sh_rtc_open, .release = sh_rtc_release, .ioctl = sh_rtc_ioctl, .read_time = sh_rtc_read_time, .set_time = sh_rtc_set_time, .read_alarm = sh_rtc_read_alarm, .set_alarm = sh_rtc_set_alarm, + .irq_set_state = sh_rtc_irq_set_state, + .irq_set_freq = sh_rtc_irq_set_freq, .proc = sh_rtc_proc, }; @@ -544,6 +574,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) { struct sh_rtc *rtc; struct resource *res; + unsigned int tmp; int ret = -ENOENT; rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL); @@ -552,6 +583,7 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) spin_lock_init(&rtc->lock); + /* get periodic/carry/alarm irqs */ rtc->periodic_irq = platform_get_irq(pdev, 0); if (unlikely(rtc->periodic_irq < 0)) { dev_err(&pdev->dev, "No IRQ for period\n"); @@ -608,8 +640,48 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev) rtc->capabilities |= pinfo->capabilities; } + rtc->rtc_dev->max_user_freq = 256; + rtc->rtc_dev->irq_freq = 1; + rtc->periodic_freq = 0x60; + platform_set_drvdata(pdev, rtc); + /* register periodic/carry/alarm irqs */ + ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, IRQF_DISABLED, + "sh-rtc period", rtc); + if (unlikely(ret)) { + dev_err(&pdev->dev, + "request period IRQ failed with %d, IRQ %d\n", ret, + rtc->periodic_irq); + goto err_badmap; + } + + ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, IRQF_DISABLED, + "sh-rtc carry", rtc); + if (unlikely(ret)) { + dev_err(&pdev->dev, + "request carry IRQ failed with %d, IRQ %d\n", ret, + rtc->carry_irq); + free_irq(rtc->periodic_irq, rtc); + goto err_badmap; + } + + ret = request_irq(rtc->alarm_irq, sh_rtc_alarm, IRQF_DISABLED, + "sh-rtc alarm", rtc); + if (unlikely(ret)) { + dev_err(&pdev->dev, + "request alarm IRQ failed with %d, IRQ %d\n", ret, + rtc->alarm_irq); + free_irq(rtc->carry_irq, rtc); + free_irq(rtc->periodic_irq, rtc); + goto err_badmap; + } + + tmp = readb(rtc->regbase + RCR1); + tmp &= ~RCR1_CF; + tmp |= RCR1_CIE; + writeb(tmp, rtc->regbase + RCR1); + return 0; err_badmap: @@ -630,6 +702,10 @@ static int __devexit sh_rtc_remove(struct platform_device *pdev) sh_rtc_setpie(&pdev->dev, 0); sh_rtc_setaie(&pdev->dev, 0); + free_irq(rtc->carry_irq, rtc); + free_irq(rtc->periodic_irq, rtc); + free_irq(rtc->alarm_irq, rtc); + release_resource(rtc->res); platform_set_drvdata(pdev, NULL); @@ -662,6 +738,8 @@ module_exit(sh_rtc_exit); MODULE_DESCRIPTION("SuperH on-chip RTC driver"); MODULE_VERSION(DRV_VERSION); -MODULE_AUTHOR("Paul Mundt , Jamie Lenehan "); +MODULE_AUTHOR("Paul Mundt , " + "Jamie Lenehan , " + "Angelo Castello "); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRV_NAME); -- cgit v1.2.3 From 6dea7814e1c6a27701a63b271fc580791e066537 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Fri, 21 Mar 2008 20:14:46 +0900 Subject: Fix sh_keysc double free Avoid double free situation from happening by removing input_free_device() after input_unregister_device(). Suggested by Dmitry Torokhov. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- drivers/input/keyboard/sh_keysc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index 5d0864a9e94b..8486abc457ed 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -238,7 +238,6 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev) input_unregister_device(priv->input); free_irq(platform_get_irq(pdev, 0), pdev); - input_free_device(priv->input); iounmap(priv->iomem_base); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- cgit v1.2.3 From 178dd0cd28168287a0be6444a7eef8918b6c544e Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 9 Apr 2008 17:56:18 +0900 Subject: sh: Add support for SH7723 CPU subtype. This adds basic support for the SH7723 MobileR2 CPU. Signed-off-by: Paul Mundt --- arch/sh/Kconfig | 11 +- arch/sh/kernel/cpu/sh4/probe.c | 25 +-- arch/sh/kernel/cpu/sh4a/Makefile | 2 + arch/sh/kernel/cpu/sh4a/setup-sh7723.c | 300 +++++++++++++++++++++++++++++++++ arch/sh/kernel/setup.c | 2 +- drivers/serial/sh-sci.c | 7 +- drivers/serial/sh-sci.h | 60 +++++-- include/asm-sh/cpu-sh4/freq.h | 6 +- include/asm-sh/cpu-sh4/rtc.h | 5 + include/asm-sh/processor.h | 3 +- 10 files changed, 389 insertions(+), 32 deletions(-) create mode 100644 arch/sh/kernel/cpu/sh4a/setup-sh7723.c (limited to 'drivers') diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index df2e2f99b902..6a679c3e15e8 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -276,6 +276,15 @@ config CPU_SUBTYPE_SH4_202 # SH-4A Processor Support +config CPU_SUBTYPE_SH7723 + bool "Support SH7723 processor" + select CPU_SH4A + select CPU_SHX2 + select ARCH_SPARSEMEM_ENABLE + select SYS_SUPPORTS_NUMA + help + Select SH7723 if you have an SH-MobileR2 CPU. + config CPU_SUBTYPE_SH7763 bool "Support SH7763 processor" select CPU_SH4A @@ -600,7 +609,7 @@ config SH_PCLK_FREQ default "27000000" if CPU_SUBTYPE_SH7343 default "31250000" if CPU_SUBTYPE_SH7619 default "32000000" if CPU_SUBTYPE_SH7722 - default "33333333" if CPU_SUBTYPE_SH7770 || \ + default "33333333" if CPU_SUBTYPE_SH7770 || CPU_SUBTYPE_SH7723 || \ CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705 || \ CPU_SUBTYPE_SH7203 || CPU_SUBTYPE_SH7206 || \ CPU_SUBTYPE_SH7263 || CPU_SUBTYPE_MXG diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c index 9e89984c4f1d..c478b16dbf4b 100644 --- a/arch/sh/kernel/cpu/sh4/probe.c +++ b/arch/sh/kernel/cpu/sh4/probe.c @@ -126,17 +126,22 @@ int __init detect_cpu_and_cache_system(void) CPU_HAS_LLSC; break; case 0x3008: - if (prr == 0xa0 || prr == 0xa1) { - boot_cpu_data.type = CPU_SH7722; - boot_cpu_data.icache.ways = 4; - boot_cpu_data.dcache.ways = 4; - boot_cpu_data.flags |= CPU_HAS_LLSC; - } - else if (prr == 0x70) { + boot_cpu_data.icache.ways = 4; + boot_cpu_data.dcache.ways = 4; + boot_cpu_data.flags |= CPU_HAS_LLSC; + + switch (prr) { + case 0x50: + boot_cpu_data.type = CPU_SH7723; + boot_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_L2_CACHE; + break; + case 0x70: boot_cpu_data.type = CPU_SH7366; - boot_cpu_data.icache.ways = 4; - boot_cpu_data.dcache.ways = 4; - boot_cpu_data.flags |= CPU_HAS_LLSC; + break; + case 0xa0: + case 0xa1: + boot_cpu_data.type = CPU_SH7722; + break; } break; case 0x4000: /* 1st cut */ diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile index 5d890ac8e793..a880e7968750 100644 --- a/arch/sh/kernel/cpu/sh4a/Makefile +++ b/arch/sh/kernel/cpu/sh4a/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o obj-$(CONFIG_CPU_SUBTYPE_SH7785) += setup-sh7785.o obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o +obj-$(CONFIG_CPU_SUBTYPE_SH7723) += setup-sh7723.o obj-$(CONFIG_CPU_SUBTYPE_SH7366) += setup-sh7366.o obj-$(CONFIG_CPU_SUBTYPE_SHX3) += setup-shx3.o @@ -22,6 +23,7 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o +clock-$(CONFIG_CPU_SUBTYPE_SH7723) := clock-sh7722.o clock-$(CONFIG_CPU_SUBTYPE_SH7366) := clock-sh7722.o clock-$(CONFIG_CPU_SUBTYPE_SHX3) := clock-shx3.o diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c new file mode 100644 index 000000000000..16925cf28db8 --- /dev/null +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c @@ -0,0 +1,300 @@ +/* + * SH7723 Setup + * + * Copyright (C) 2008 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include + +static struct plat_sci_port sci_platform_data[] = { + { + .mapbase = 0xa4e30000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCI, + .irqs = { 56, 56, 56, 56 }, + },{ + .mapbase = 0xa4e40000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCI, + .irqs = { 88, 88, 88, 88 }, + },{ + .mapbase = 0xa4e50000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCI, + .irqs = { 109, 109, 109, 109 }, + }, { + .flags = 0, + } +}; + +static struct platform_device sci_device = { + .name = "sh-sci", + .id = -1, + .dev = { + .platform_data = sci_platform_data, + }, +}; + +static struct resource rtc_resources[] = { + [0] = { + .start = 0xa465fec0, + .end = 0xa465fec0 + 0x58 - 1, + .flags = IORESOURCE_IO, + }, + [1] = { + /* Period IRQ */ + .start = 69, + .flags = IORESOURCE_IRQ, + }, + [2] = { + /* Carry IRQ */ + .start = 70, + .flags = IORESOURCE_IRQ, + }, + [3] = { + /* Alarm IRQ */ + .start = 68, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device rtc_device = { + .name = "sh-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(rtc_resources), + .resource = rtc_resources, +}; + +static struct platform_device *sh7723_devices[] __initdata = { + &sci_device, + &rtc_device, +}; + +static int __init sh7723_devices_setup(void) +{ + return platform_add_devices(sh7723_devices, + ARRAY_SIZE(sh7723_devices)); +} +__initcall(sh7723_devices_setup); + +enum { + UNUSED=0, + + /* interrupt sources */ + IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7, + HUDI, + DMAC1A_DEI0,DMAC1A_DEI1,DMAC1A_DEI2,DMAC1A_DEI3, + _2DG_TRI,_2DG_INI,_2DG_CEI, + DMAC0A_DEI0,DMAC0A_DEI1,DMAC0A_DEI2,DMAC0A_DEI3, + VIO_CEUI,VIO_BEUI,VIO_VEU2HI,VIO_VOUI, + SCIFA_SCIFA0, + VPU_VPUI, + TPU_TPUI, + ADC_ADI, + USB_USI0, + RTC_ATI,RTC_PRI,RTC_CUI, + DMAC1B_DEI4,DMAC1B_DEI5,DMAC1B_DADERR, + DMAC0B_DEI4,DMAC0B_DEI5,DMAC0B_DADERR, + KEYSC_KEYI, + SCIF_SCIF0,SCIF_SCIF1,SCIF_SCIF2, + MSIOF_MSIOFI0,MSIOF_MSIOFI1, + SCIFA_SCIFA1, + FLCTL_FLSTEI,FLCTL_FLTENDI,FLCTL_FLTREQ0I,FLCTL_FLTREQ1I, + I2C_ALI,I2C_TACKI,I2C_WAITI,I2C_DTEI, + SDHI0_SDHII0,SDHI0_SDHII1,SDHI0_SDHII2, + CMT_CMTI, + TSIF_TSIFI, + SIU_SIUI, + SCIFA_SCIFA2, + TMU0_TUNI0, TMU0_TUNI1, TMU0_TUNI2, + IRDA_IRDAI, + ATAPI_ATAPII, + SDHI1_SDHII0,SDHI1_SDHII1,SDHI1_SDHII2, + VEU2H1_VEU2HI, + LCDC_LCDCI, + TMU1_TUNI0,TMU1_TUNI1,TMU1_TUNI2, + + /* interrupt groups */ + DMAC1A, DMAC0A, VIO, DMAC0B, FLCTL, I2C, _2DG, + SDHI1, RTC, DMAC1B, SDHI0, +}; + +static struct intc_vect vectors[] __initdata = { + INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620), + INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660), + INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0), + INTC_VECT(IRQ6, 0x6c0), INTC_VECT(IRQ7, 0x6e0), + + INTC_VECT(DMAC1A_DEI0,0x700), + INTC_VECT(DMAC1A_DEI1,0x720), + INTC_VECT(DMAC1A_DEI2,0x740), + INTC_VECT(DMAC1A_DEI3,0x760), + + INTC_VECT(_2DG_TRI, 0x780), + INTC_VECT(_2DG_INI, 0x7A0), + INTC_VECT(_2DG_CEI, 0x7C0), + + INTC_VECT(DMAC0A_DEI0,0x800), + INTC_VECT(DMAC0A_DEI1,0x820), + INTC_VECT(DMAC0A_DEI2,0x840), + INTC_VECT(DMAC0A_DEI3,0x860), + + INTC_VECT(VIO_CEUI,0x880), + INTC_VECT(VIO_BEUI,0x8A0), + INTC_VECT(VIO_VEU2HI,0x8C0), + INTC_VECT(VIO_VOUI,0x8E0), + + INTC_VECT(SCIFA_SCIFA0,0x900), + INTC_VECT(VPU_VPUI,0x920), + INTC_VECT(TPU_TPUI,0x9A0), + INTC_VECT(ADC_ADI,0x9E0), + INTC_VECT(USB_USI0,0xA20), + + INTC_VECT(RTC_ATI,0xA80), + INTC_VECT(RTC_PRI,0xAA0), + INTC_VECT(RTC_CUI,0xAC0), + + INTC_VECT(DMAC1B_DEI4,0xB00), + INTC_VECT(DMAC1B_DEI5,0xB20), + INTC_VECT(DMAC1B_DADERR,0xB40), + + INTC_VECT(DMAC0B_DEI4,0xB80), + INTC_VECT(DMAC0B_DEI5,0xBA0), + INTC_VECT(DMAC0B_DADERR,0xBC0), + + INTC_VECT(KEYSC_KEYI,0xBE0), + INTC_VECT(SCIF_SCIF0,0xC00), + INTC_VECT(SCIF_SCIF1,0xC20), + INTC_VECT(SCIF_SCIF2,0xC40), + INTC_VECT(MSIOF_MSIOFI0,0xC80), + INTC_VECT(MSIOF_MSIOFI1,0xCA0), + INTC_VECT(SCIFA_SCIFA1,0xD00), + + INTC_VECT(FLCTL_FLSTEI,0xD80), + INTC_VECT(FLCTL_FLTENDI,0xDA0), + INTC_VECT(FLCTL_FLTREQ0I,0xDC0), + INTC_VECT(FLCTL_FLTREQ1I,0xDE0), + + INTC_VECT(I2C_ALI,0xE00), + INTC_VECT(I2C_TACKI,0xE20), + INTC_VECT(I2C_WAITI,0xE40), + INTC_VECT(I2C_DTEI,0xE60), + + INTC_VECT(SDHI0_SDHII0,0xE80), + INTC_VECT(SDHI0_SDHII1,0xEA0), + INTC_VECT(SDHI0_SDHII2,0xEC0), + + INTC_VECT(CMT_CMTI,0xF00), + INTC_VECT(TSIF_TSIFI,0xF20), + INTC_VECT(SIU_SIUI,0xF80), + INTC_VECT(SCIFA_SCIFA2,0xFA0), + + INTC_VECT(TMU0_TUNI0,0x400), + INTC_VECT(TMU0_TUNI1,0x420), + INTC_VECT(TMU0_TUNI2,0x440), + + INTC_VECT(IRDA_IRDAI,0x480), + INTC_VECT(ATAPI_ATAPII,0x4A0), + + INTC_VECT(SDHI1_SDHII0,0x4E0), + INTC_VECT(SDHI1_SDHII1,0x500), + INTC_VECT(SDHI1_SDHII2,0x520), + + INTC_VECT(VEU2H1_VEU2HI,0x560), + INTC_VECT(LCDC_LCDCI,0x580), + + INTC_VECT(TMU1_TUNI0,0x920), + INTC_VECT(TMU1_TUNI1,0x940), + INTC_VECT(TMU1_TUNI2,0x960), + +}; + +static struct intc_group groups[] __initdata = { + INTC_GROUP(DMAC1A,DMAC1A_DEI0,DMAC1A_DEI1,DMAC1A_DEI2,DMAC1A_DEI3), + INTC_GROUP(DMAC0A,DMAC0A_DEI0,DMAC0A_DEI1,DMAC0A_DEI2,DMAC0A_DEI3), + INTC_GROUP(VIO, VIO_CEUI,VIO_BEUI,VIO_VEU2HI,VIO_VOUI), + INTC_GROUP(DMAC0B, DMAC0B_DEI4,DMAC0B_DEI5,DMAC0B_DADERR), + INTC_GROUP(FLCTL,FLCTL_FLSTEI,FLCTL_FLTENDI,FLCTL_FLTREQ0I,FLCTL_FLTREQ1I), + INTC_GROUP(I2C,I2C_ALI,I2C_TACKI,I2C_WAITI,I2C_DTEI), + INTC_GROUP(_2DG, _2DG_TRI,_2DG_INI,_2DG_CEI), + INTC_GROUP(SDHI1, SDHI1_SDHII0,SDHI1_SDHII1,SDHI1_SDHII2), + INTC_GROUP(RTC, RTC_ATI,RTC_PRI,RTC_CUI), + INTC_GROUP(DMAC1B, DMAC1B_DEI4,DMAC1B_DEI5,DMAC1B_DADERR), + INTC_GROUP(SDHI0,SDHI0_SDHII0,SDHI0_SDHII1,SDHI0_SDHII2), +}; + +static struct intc_mask_reg mask_registers[] __initdata = { + { 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */ + { 0, TMU1_TUNI2,TMU1_TUNI1,TMU1_TUNI0,0,SDHI1_SDHII2,SDHI1_SDHII1,SDHI1_SDHII0} }, + { 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */ + { VIO_VOUI, VIO_VEU2HI,VIO_BEUI,VIO_CEUI,DMAC0A_DEI3,DMAC0A_DEI2,DMAC0A_DEI1,DMAC0A_DEI0 } }, + { 0xa4080088, 0xa40800c8, 8, /* IMR2 / IMCR2 */ + { 0, 0, 0, VPU_VPUI,0,0,0,SCIFA_SCIFA0 } }, + { 0xa408008c, 0xa40800cc, 8, /* IMR3 / IMCR3 */ + { DMAC1A_DEI3,DMAC1A_DEI2,DMAC1A_DEI1,DMAC1A_DEI0,0,0,0,IRDA_IRDAI } }, + { 0xa4080090, 0xa40800d0, 8, /* IMR4 / IMCR4 */ + { 0,TMU0_TUNI2,TMU0_TUNI1,TMU0_TUNI0,VEU2H1_VEU2HI,0,0,LCDC_LCDCI } }, + { 0xa4080094, 0xa40800d4, 8, /* IMR5 / IMCR5 */ + { KEYSC_KEYI,DMAC0B_DADERR,DMAC0B_DEI5,DMAC0B_DEI4,0,SCIF_SCIF2,SCIF_SCIF1,SCIF_SCIF0 } }, + { 0xa4080098, 0xa40800d8, 8, /* IMR6 / IMCR6 */ + { 0,0,0,SCIFA_SCIFA1,ADC_ADI,0,MSIOF_MSIOFI1,MSIOF_MSIOFI0 } }, + { 0xa408009c, 0xa40800dc, 8, /* IMR7 / IMCR7 */ + { I2C_DTEI, I2C_WAITI, I2C_TACKI, I2C_ALI, + FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLTENDI, FLCTL_FLSTEI } }, + { 0xa40800a0, 0xa40800e0, 8, /* IMR8 / IMCR8 */ + { 0,SDHI0_SDHII2,SDHI0_SDHII1,SDHI0_SDHII0,0,0,SCIFA_SCIFA2,SIU_SIUI } }, + { 0xa40800a4, 0xa40800e4, 8, /* IMR9 / IMCR9 */ + { 0, 0, 0, CMT_CMTI, 0, 0, USB_USI0,0 } }, + { 0xa40800a8, 0xa40800e8, 8, /* IMR10 / IMCR10 */ + { 0, DMAC1B_DADERR,DMAC1B_DEI5,DMAC1B_DEI4,0,RTC_ATI,RTC_PRI,RTC_CUI } }, + { 0xa40800ac, 0xa40800ec, 8, /* IMR11 / IMCR11 */ + { 0,_2DG_CEI,_2DG_INI,_2DG_TRI,0,TPU_TPUI,0,TSIF_TSIFI } }, + { 0xa40800b0, 0xa40800f0, 8, /* IMR12 / IMCR12 */ + { 0,0,0,0,0,0,0,ATAPI_ATAPII } }, + { 0xa4140044, 0xa4140064, 8, /* INTMSK00 / INTMSKCLR00 */ + { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } }, +}; + +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xa4080000, 0, 16, 4, /* IPRA */ { TMU0_TUNI0, TMU0_TUNI1, TMU0_TUNI2, IRDA_IRDAI } }, + { 0xa4080004, 0, 16, 4, /* IPRB */ { VEU2H1_VEU2HI, LCDC_LCDCI, DMAC1A, 0} }, + { 0xa4080008, 0, 16, 4, /* IPRC */ { TMU1_TUNI0, TMU1_TUNI1, TMU1_TUNI2, 0} }, + { 0xa408000c, 0, 16, 4, /* IPRD */ { } }, + { 0xa4080010, 0, 16, 4, /* IPRE */ { DMAC0A, VIO, SCIFA_SCIFA0, VPU_VPUI } }, + { 0xa4080014, 0, 16, 4, /* IPRF */ { KEYSC_KEYI, DMAC0B, USB_USI0, CMT_CMTI } }, + { 0xa4080018, 0, 16, 4, /* IPRG */ { SCIF_SCIF0, SCIF_SCIF1, SCIF_SCIF2,0 } }, + { 0xa408001c, 0, 16, 4, /* IPRH */ { MSIOF_MSIOFI0,MSIOF_MSIOFI1, FLCTL, I2C } }, + { 0xa4080020, 0, 16, 4, /* IPRI */ { SCIFA_SCIFA1,0,TSIF_TSIFI,_2DG } }, + { 0xa4080024, 0, 16, 4, /* IPRJ */ { ADC_ADI,0,SIU_SIUI,SDHI1 } }, + { 0xa4080028, 0, 16, 4, /* IPRK */ { RTC,DMAC1B,0,SDHI0 } }, + { 0xa408002c, 0, 16, 4, /* IPRL */ { SCIFA_SCIFA2,0,TPU_TPUI,ATAPI_ATAPII } }, + { 0xa4140010, 0, 32, 4, /* INTPRI00 */ + { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } }, +}; + +static struct intc_sense_reg sense_registers[] __initdata = { + { 0xa414001c, 16, 2, /* ICR1 */ + { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } }, +}; + +static DECLARE_INTC_DESC(intc_desc, "sh7723", vectors, groups, + mask_registers, prio_registers, sense_registers); + +void __init plat_irq_setup(void) +{ + register_intc_controller(&intc_desc); +} + +void __init plat_mem_setup(void) +{ + /* Register the URAM space as Node 1 */ + setup_bootmem_node(1, 0x055f0000, 0x05610000); +} diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 0ee776888c65..284f66f1ebbe 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -335,7 +335,7 @@ static const char *cpu_name[] = { [CPU_SH7343] = "SH7343", [CPU_SH7785] = "SH7785", [CPU_SH7722] = "SH7722", [CPU_SHX3] = "SH-X3", [CPU_SH5_101] = "SH5-101", [CPU_SH5_103] = "SH5-103", - [CPU_MXG] = "MX-G", + [CPU_MXG] = "MX-G", [CPU_SH7723] = "SH7723", [CPU_SH7366] = "SH7366", [CPU_SH_NONE] = "Unknown" }; diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index eff593080d4f..c2ea5d4df44a 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -333,7 +333,6 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) } sci_out(port, SCFCR, fcr_val); } - #elif defined(CONFIG_CPU_SH3) /* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) @@ -384,6 +383,12 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) sci_out(port, SCFCR, fcr_val); } +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) +static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) +{ + /* Nothing to do here.. */ + sci_out(port, SCFCR, 0); +} #else /* For SH7750 */ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index 01a9dd715f5d..fa8700a968fc 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -1,20 +1,5 @@ -/* $Id: sh-sci.h,v 1.4 2004/02/19 16:43:56 lethal Exp $ - * - * linux/drivers/serial/sh-sci.h - * - * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) - * Copyright (C) 1999, 2000 Niibe Yutaka - * Copyright (C) 2000 Greg Banks - * Copyright (C) 2002, 2003 Paul Mundt - * Modified to support multiple serial ports. Stuart Menefy (May 2000). - * Modified to support SH7300(SH-Mobile) SCIF. Takashi Kusuda (Jun 2003). - * Modified to support H8/300 Series Yoshinori Sato (Feb 2004). - * Removed SH7300 support (Jul 2007). - * Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Aug 2007). - */ #include #include - #include #if defined(CONFIG_H83007) || defined(CONFIG_H83068) @@ -102,6 +87,15 @@ # define SCSPTR0 SCPDR0 # define SCIF_ORER 0x0001 /* overrun error bit */ # define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) +# define SCSPTR0 0xa4050160 +# define SCSPTR1 0xa405013e +# define SCSPTR2 0xa4050160 +# define SCSPTR3 0xa405013e +# define SCSPTR4 0xa4050128 +# define SCSPTR5 0xa4050128 +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ # define SCIF_ONLY #elif defined(CONFIG_CPU_SUBTYPE_SH4_202) # define SCSPTR2 0xffe80020 /* 16 bit SCIF */ @@ -395,6 +389,11 @@ h8_sci_offset, h8_sci_size) \ CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size) #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) + #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) + #define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) #else #define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \ @@ -419,6 +418,18 @@ SCIF_FNS(SCFDR, 0x1c, 16) SCIF_FNS(SCxTDR, 0x20, 8) SCIF_FNS(SCxRDR, 0x24, 8) SCIF_FNS(SCLSR, 0x24, 16) +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) +SCIx_FNS(SCSMR, 0x00, 16, 0x00, 16) +SCIx_FNS(SCBRR, 0x04, 8, 0x04, 8) +SCIx_FNS(SCSCR, 0x08, 16, 0x08, 16) +SCIx_FNS(SCxTDR, 0x20, 8, 0x0c, 8) +SCIx_FNS(SCxSR, 0x14, 16, 0x10, 16) +SCIx_FNS(SCxRDR, 0x24, 8, 0x14, 8) +SCIF_FNS(SCTDSR, 0x0c, 8) +SCIF_FNS(SCFER, 0x10, 16) +SCIF_FNS(SCFCR, 0x18, 16) +SCIF_FNS(SCFDR, 0x1c, 16) +SCIF_FNS(SCLSR, 0x24, 16) #else /* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 SCI/H8*/ /* name off sz off sz off sz off sz off sz*/ @@ -589,6 +600,23 @@ static inline int sci_rxd_in(struct uart_port *port) return ctrl_inb(SCPDR0) & 0x0001 ? 1 : 0; /* SCIF0 */ return 1; } +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == 0xffe00000) + return ctrl_inb(SCSPTR0) & 0x0008 ? 1 : 0; /* SCIF0 */ + if (port->mapbase == 0xffe10000) + return ctrl_inb(SCSPTR1) & 0x0020 ? 1 : 0; /* SCIF1 */ + if (port->mapbase == 0xffe20000) + return ctrl_inb(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF2 */ + if (port->mapbase == 0xa4e30000) + return ctrl_inb(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF3 */ + if (port->mapbase == 0xa4e40000) + return ctrl_inb(SCSPTR4) & 0x0001 ? 1 : 0; /* SCIF4 */ + if (port->mapbase == 0xa4e50000) + return ctrl_inb(SCSPTR5) & 0x0008 ? 1 : 0; /* SCIF5 */ + return 1; +} #elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) static inline int sci_rxd_in(struct uart_port *port) { @@ -727,6 +755,8 @@ static inline int sci_rxd_in(struct uart_port *port) defined(CONFIG_CPU_SUBTYPE_SH7720) || \ defined(CONFIG_CPU_SUBTYPE_SH7721) #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) +#elif defined(CONFIG_CPU_SUBTYPE_SH7723) +#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(16*bps)-1) #elif defined(__H8300H__) || defined(__H8300S__) #define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1) #elif defined(CONFIG_SUPERH64) diff --git a/include/asm-sh/cpu-sh4/freq.h b/include/asm-sh/cpu-sh4/freq.h index ec028c649215..da46e67ae26d 100644 --- a/include/asm-sh/cpu-sh4/freq.h +++ b/include/asm-sh/cpu-sh4/freq.h @@ -10,14 +10,14 @@ #ifndef __ASM_CPU_SH4_FREQ_H #define __ASM_CPU_SH4_FREQ_H -#if defined(CONFIG_CPU_SUBTYPE_SH7722) || defined(CONFIG_CPU_SUBTYPE_SH7366) +#if defined(CONFIG_CPU_SUBTYPE_SH7722) || \ + defined(CONFIG_CPU_SUBTYPE_SH7723) || \ + defined(CONFIG_CPU_SUBTYPE_SH7366) #define FRQCR 0xa4150000 #define VCLKCR 0xa4150004 #define SCLKACR 0xa4150008 #define SCLKBCR 0xa415000c -#if defined(CONFIG_CPU_SUBTYPE_SH7722) #define IrDACLKCR 0xa4150010 -#endif #elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \ defined(CONFIG_CPU_SUBTYPE_SH7780) #define FRQCR 0xffc80000 diff --git a/include/asm-sh/cpu-sh4/rtc.h b/include/asm-sh/cpu-sh4/rtc.h index f3d0f53275e4..25b1e6adfe8c 100644 --- a/include/asm-sh/cpu-sh4/rtc.h +++ b/include/asm-sh/cpu-sh4/rtc.h @@ -1,7 +1,12 @@ #ifndef __ASM_SH_CPU_SH4_RTC_H #define __ASM_SH_CPU_SH4_RTC_H +#ifdef CONFIG_CPU_SUBTYPE_SH7723 +#define rtc_reg_size sizeof(u16) +#else #define rtc_reg_size sizeof(u32) +#endif + #define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */ #define RTC_DEF_CAPABILITIES RTC_CAP_4_DIGIT_YEAR diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h index f1b3a81191d4..b7c7ce80f03e 100644 --- a/include/asm-sh/processor.h +++ b/include/asm-sh/processor.h @@ -29,7 +29,8 @@ enum cpu_type { CPU_SH7760, CPU_SH4_202, CPU_SH4_501, /* SH-4A types */ - CPU_SH7763, CPU_SH7770, CPU_SH7780, CPU_SH7781, CPU_SH7785, CPU_SHX3, + CPU_SH7763, CPU_SH7770, CPU_SH7780, CPU_SH7781, CPU_SH7785, + CPU_SH7723, CPU_SHX3, /* SH4AL-DSP types */ CPU_SH7343, CPU_SH7722, CPU_SH7366, -- cgit v1.2.3