diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2010-02-19 14:38:23 +1100 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2010-02-19 14:38:23 +1100 |
commit | 87d31345c0a90ccdf185feed9923ed14764f45dc (patch) | |
tree | 2816764e59f93379e0e3843fa0c417aafe02c503 /drivers | |
parent | e98efaf303ccbff11522a054d155593d7f2bb41f (diff) | |
parent | d24720a45ad2928f687c6371482cdfba19b74fc5 (diff) |
Merge commit 'gcl/next' into next
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/rtc/Kconfig | 10 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-mpc5121.c | 387 | ||||
-rw-r--r-- | drivers/serial/mpc52xx_uart.c | 251 | ||||
-rw-r--r-- | drivers/video/fsl-diu-fb.c | 5 |
5 files changed, 639 insertions, 15 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 8167e9e6827..2bb8a8b7ffa 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -868,4 +868,14 @@ config RTC_DRV_MC13783 help This enables support for the Freescale MC13783 PMIC RTC +config RTC_DRV_MPC5121 + tristate "Freescale MPC5121 built-in RTC" + depends on PPC_MPC512x && RTC_CLASS + help + If you say yes here you will get support for the + built-in RTC MPC5121. + + This driver can also be built as a module. If so, the module + will be called rtc-mpc5121. + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index e5160fddc44..b7148afb8f5 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o obj-$(CONFIG_RTC_DRV_MC13783) += rtc-mc13783.o obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o +obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c new file mode 100644 index 00000000000..4313ca03a96 --- /dev/null +++ b/drivers/rtc/rtc-mpc5121.c @@ -0,0 +1,387 @@ +/* + * Real-time clock driver for MPC5121 + * + * Copyright 2007, Domen Puncer <domen.puncer@telargo.com> + * Copyright 2008, Freescale Semiconductor, Inc. All rights reserved. + * + * 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 <linux/init.h> +#include <linux/module.h> +#include <linux/rtc.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> +#include <linux/io.h> + +struct mpc5121_rtc_regs { + u8 set_time; /* RTC + 0x00 */ + u8 hour_set; /* RTC + 0x01 */ + u8 minute_set; /* RTC + 0x02 */ + u8 second_set; /* RTC + 0x03 */ + + u8 set_date; /* RTC + 0x04 */ + u8 month_set; /* RTC + 0x05 */ + u8 weekday_set; /* RTC + 0x06 */ + u8 date_set; /* RTC + 0x07 */ + + u8 write_sw; /* RTC + 0x08 */ + u8 sw_set; /* RTC + 0x09 */ + u16 year_set; /* RTC + 0x0a */ + + u8 alm_enable; /* RTC + 0x0c */ + u8 alm_hour_set; /* RTC + 0x0d */ + u8 alm_min_set; /* RTC + 0x0e */ + u8 int_enable; /* RTC + 0x0f */ + + u8 reserved1; + u8 hour; /* RTC + 0x11 */ + u8 minute; /* RTC + 0x12 */ + u8 second; /* RTC + 0x13 */ + + u8 month; /* RTC + 0x14 */ + u8 wday_mday; /* RTC + 0x15 */ + u16 year; /* RTC + 0x16 */ + + u8 int_alm; /* RTC + 0x18 */ + u8 int_sw; /* RTC + 0x19 */ + u8 alm_status; /* RTC + 0x1a */ + u8 sw_minute; /* RTC + 0x1b */ + + u8 bus_error_1; /* RTC + 0x1c */ + u8 int_day; /* RTC + 0x1d */ + u8 int_min; /* RTC + 0x1e */ + u8 int_sec; /* RTC + 0x1f */ + + /* + * target_time: + * intended to be used for hibernation but hibernation + * does not work on silicon rev 1.5 so use it for non-volatile + * storage of offset between the actual_time register and linux + * time + */ + u32 target_time; /* RTC + 0x20 */ + /* + * actual_time: + * readonly time since VBAT_RTC was last connected + */ + u32 actual_time; /* RTC + 0x24 */ + u32 keep_alive; /* RTC + 0x28 */ +}; + +struct mpc5121_rtc_data { + unsigned irq; + unsigned irq_periodic; + struct mpc5121_rtc_regs __iomem *regs; + struct rtc_device *rtc; + struct rtc_wkalrm wkalarm; +}; + +/* + * Update second/minute/hour registers. + * + * This is just so alarm will work. + */ +static void mpc5121_rtc_update_smh(struct mpc5121_rtc_regs __iomem *regs, + struct rtc_time *tm) +{ + out_8(®s->second_set, tm->tm_sec); + out_8(®s->minute_set, tm->tm_min); + out_8(®s->hour_set, tm->tm_hour); + + /* set time sequence */ + out_8(®s->set_time, 0x1); + out_8(®s->set_time, 0x3); + out_8(®s->set_time, 0x1); + out_8(®s->set_time, 0x0); +} + +static int mpc5121_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev); + struct mpc5121_rtc_regs __iomem *regs = rtc->regs; + unsigned long now; + + /* + * linux time is actual_time plus the offset saved in target_time + */ + now = in_be32(®s->actual_time) + in_be32(®s->target_time); + + rtc_time_to_tm(now, tm); + + /* + * update second minute hour registers + * so alarms will work + */ + mpc5121_rtc_update_smh(regs, tm); + + return rtc_valid_tm(tm); +} + +static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev); + struct mpc5121_rtc_regs __iomem *regs = rtc->regs; + int ret; + unsigned long now; + + /* + * The actual_time register is read only so we write the offset + * between it and linux time to the target_time register. + */ + ret = rtc_tm_to_time(tm, &now); + if (ret == 0) + out_be32(®s->target_time, now - in_be32(®s->actual_time)); + + /* + * update second minute hour registers + * so alarms will work + */ + mpc5121_rtc_update_smh(regs, tm); + + return 0; +} + +static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev); + struct mpc5121_rtc_regs __iomem *regs = rtc->regs; + + *alarm = rtc->wkalarm; + + alarm->pending = in_8(®s->alm_status); + + return 0; +} + +static int mpc5121_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev); + struct mpc5121_rtc_regs __iomem *regs = rtc->regs; + + /* + * the alarm has no seconds so deal with it + */ + if (alarm->time.tm_sec) { + alarm->time.tm_sec = 0; + alarm->time.tm_min++; + if (alarm->time.tm_min >= 60) { + alarm->time.tm_min = 0; + alarm->time.tm_hour++; + if (alarm->time.tm_hour >= 24) + alarm->time.tm_hour = 0; + } + } + + alarm->time.tm_mday = -1; + alarm->time.tm_mon = -1; + alarm->time.tm_year = -1; + + out_8(®s->alm_min_set, alarm->time.tm_min); + out_8(®s->alm_hour_set, alarm->time.tm_hour); + + out_8(®s->alm_enable, alarm->enabled); + + rtc->wkalarm = *alarm; + return 0; +} + +static irqreturn_t mpc5121_rtc_handler(int irq, void *dev) +{ + struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev); + struct mpc5121_rtc_regs __iomem *regs = rtc->regs; + + if (in_8(®s->int_alm)) { + /* acknowledge and clear status */ + out_8(®s->int_alm, 1); + out_8(®s->alm_status, 1); + + rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static irqreturn_t mpc5121_rtc_handler_upd(int irq, void *dev) +{ + struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev); + struct mpc5121_rtc_regs __iomem *regs = rtc->regs; + + if (in_8(®s->int_sec) && (in_8(®s->int_enable) & 0x1)) { + /* acknowledge */ + out_8(®s->int_sec, 1); + + rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_UF); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int mpc5121_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev); + struct mpc5121_rtc_regs __iomem *regs = rtc->regs; + int val; + + if (enabled) + val = 1; + else + val = 0; + + out_8(®s->alm_enable, val); + rtc->wkalarm.enabled = val; + + return 0; +} + +static int mpc5121_rtc_update_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev); + struct mpc5121_rtc_regs __iomem *regs = rtc->regs; + int val; + + val = in_8(®s->int_enable); + + if (enabled) + val = (val & ~0x8) | 0x1; + else + val &= ~0x1; + + out_8(®s->int_enable, val); + + return 0; +} + +static const struct rtc_class_ops mpc5121_rtc_ops = { + .read_time = mpc5121_rtc_read_time, + .set_time = mpc5121_rtc_set_time, + .read_alarm = mpc5121_rtc_read_alarm, + .set_alarm = mpc5121_rtc_set_alarm, + .alarm_irq_enable = mpc5121_rtc_alarm_irq_enable, + .update_irq_enable = mpc5121_rtc_update_irq_enable, +}; + +static int __devinit mpc5121_rtc_probe(struct of_device *op, + const struct of_device_id *match) +{ + struct mpc5121_rtc_data *rtc; + int err = 0; + u32 ka; + + rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + rtc->regs = of_iomap(op->node, 0); + if (!rtc->regs) { + dev_err(&op->dev, "%s: couldn't map io space\n", __func__); + err = -ENOSYS; + goto out_free; + } + + device_init_wakeup(&op->dev, 1); + + dev_set_drvdata(&op->dev, rtc); + + rtc->irq = irq_of_parse_and_map(op->node, 1); + err = request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DISABLED, + "mpc5121-rtc", &op->dev); + if (err) { + dev_err(&op->dev, "%s: could not request irq: %i\n", + __func__, rtc->irq); + goto out_dispose; + } + + rtc->irq_periodic = irq_of_parse_and_map(op->node, 0); + err = request_irq(rtc->irq_periodic, mpc5121_rtc_handler_upd, + IRQF_DISABLED, "mpc5121-rtc_upd", &op->dev); + if (err) { + dev_err(&op->dev, "%s: could not request irq: %i\n", + __func__, rtc->irq_periodic); + goto out_dispose2; + } + + ka = in_be32(&rtc->regs->keep_alive); + if (ka & 0x02) { + dev_warn(&op->dev, + "mpc5121-rtc: Battery or oscillator failure!\n"); + out_be32(&rtc->regs->keep_alive, ka); + } + + rtc->rtc = rtc_device_register("mpc5121-rtc", &op->dev, + &mpc5121_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc->rtc)) { + err = PTR_ERR(rtc->rtc); + goto out_free_irq; + } + + return 0; + +out_free_irq: + free_irq(rtc->irq_periodic, &op->dev); +out_dispose2: + irq_dispose_mapping(rtc->irq_periodic); + free_irq(rtc->irq, &op->dev); +out_dispose: + irq_dispose_mapping(rtc->irq); + iounmap(rtc->regs); +out_free: + kfree(rtc); + + return err; +} + +static int __devexit mpc5121_rtc_remove(struct of_device *op) +{ + struct mpc5121_rtc_data *rtc = dev_get_drvdata(&op->dev); + struct mpc5121_rtc_regs __iomem *regs = rtc->regs; + + /* disable interrupt, so there are no nasty surprises */ + out_8(®s->alm_enable, 0); + out_8(®s->int_enable, in_8(®s->int_enable) & ~0x1); + + rtc_device_unregister(rtc->rtc); + iounmap(rtc->regs); + free_irq(rtc->irq, &op->dev); + free_irq(rtc->irq_periodic, &op->dev); + irq_dispose_mapping(rtc->irq); + irq_dispose_mapping(rtc->irq_periodic); + dev_set_drvdata(&op->dev, NULL); + kfree(rtc); + + return 0; +} + +static struct of_device_id mpc5121_rtc_match[] __devinitdata = { + { .compatible = "fsl,mpc5121-rtc", }, + {}, +}; + +static struct of_platform_driver mpc5121_rtc_driver = { + .owner = THIS_MODULE, + .name = "mpc5121-rtc", + .match_table = mpc5121_rtc_match, + .probe = mpc5121_rtc_probe, + .remove = __devexit_p(mpc5121_rtc_remove), +}; + +static int __init mpc5121_rtc_init(void) +{ + return of_register_platform_driver(&mpc5121_rtc_driver); +} +module_init(mpc5121_rtc_init); + +static void __exit mpc5121_rtc_exit(void) +{ + of_unregister_platform_driver(&mpc5121_rtc_driver); +} +module_exit(mpc5121_rtc_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("John Rigby <jcrigby@gmail.com>"); diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 7ce9e9f567a..3119fddaedb 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -74,6 +74,7 @@ #include <linux/io.h> #include <linux/of.h> #include <linux/of_platform.h> +#include <linux/clk.h> #include <asm/mpc52xx.h> #include <asm/mpc52xx_psc.h> @@ -113,6 +114,7 @@ static void mpc52xx_uart_of_enumerate(void); /* Forward declaration of the interruption handling routine */ static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id); +static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port); /* Simple macro to test if a port is console or not. This one is taken @@ -145,6 +147,11 @@ struct psc_ops { void (*cw_disable_ints)(struct uart_port *port); void (*cw_restore_ints)(struct uart_port *port); unsigned long (*getuartclk)(void *p); + int (*clock)(struct uart_port *port, int enable); + int (*fifoc_init)(void); + void (*fifoc_uninit)(void); + void (*get_irq)(struct uart_port *, struct device_node *); + irqreturn_t (*handle_irq)(struct uart_port *port); }; #ifdef CONFIG_PPC_MPC52xx @@ -256,6 +263,18 @@ static unsigned long mpc52xx_getuartclk(void *p) return mpc5xxx_get_bus_frequency(p) / 2; } +static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np) +{ + port->irqflags = IRQF_DISABLED; + port->irq = irq_of_parse_and_map(np, 0); +} + +/* 52xx specific interrupt handler. The caller holds the port lock */ +static irqreturn_t mpc52xx_psc_handle_irq(struct uart_port *port) +{ + return mpc5xxx_uart_process_int(port); +} + static struct psc_ops mpc52xx_psc_ops = { .fifo_init = mpc52xx_psc_fifo_init, .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy, @@ -273,14 +292,32 @@ static struct psc_ops mpc52xx_psc_ops = { .cw_disable_ints = mpc52xx_psc_cw_disable_ints, .cw_restore_ints = mpc52xx_psc_cw_restore_ints, .getuartclk = mpc52xx_getuartclk, + .get_irq = mpc52xx_psc_get_irq, + .handle_irq = mpc52xx_psc_handle_irq, }; #endif /* CONFIG_MPC52xx */ #ifdef CONFIG_PPC_MPC512x #define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1)) + +/* PSC FIFO Controller for mpc512x */ +struct psc_fifoc { + u32 fifoc_cmd; + u32 fifoc_int; + u32 fifoc_dma; + u32 fifoc_axe; + u32 fifoc_debug; +}; + +static struct psc_fifoc __iomem *psc_fifoc; +static unsigned int psc_fifoc_irq; + static void mpc512x_psc_fifo_init(struct uart_port *port) { + /* /32 prescaler */ + out_be16(&PSC(port)->mpc52xx_psc_clock_select, 0xdd00); + out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE); out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); out_be32(&FIFO_512x(port)->txalarm, 1); @@ -393,6 +430,160 @@ static unsigned long mpc512x_getuartclk(void *p) return mpc5xxx_get_bus_frequency(p); } +#define DEFAULT_FIFO_SIZE 16 + +static unsigned int __init get_fifo_size(struct device_node *np, + char *fifo_name) +{ + const unsigned int *fp; + + fp = of_get_property(np, fifo_name, NULL); + if (fp) + return *fp; + + pr_warning("no %s property in %s node, defaulting to %d\n", + fifo_name, np->full_name, DEFAULT_FIFO_SIZE); + + return DEFAULT_FIFO_SIZE; +} + +#define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \ + ((u32)(_base) + sizeof(struct mpc52xx_psc))) + +/* Init PSC FIFO Controller */ +static int __init mpc512x_psc_fifoc_init(void) +{ + struct device_node *np; + void __iomem *psc; + unsigned int tx_fifo_size; + unsigned int rx_fifo_size; + int fifobase = 0; /* current fifo address in 32 bit words */ + + np = of_find_compatible_node(NULL, NULL, + "fsl,mpc5121-psc-fifo"); + if (!np) { + pr_err("%s: Can't find FIFOC node\n", __func__); + return -ENODEV; + } + + psc_fifoc = of_iomap(np, 0); + if (!psc_fifoc) { + pr_err("%s: Can't map FIFOC\n", __func__); + return -ENODEV; + } + + psc_fifoc_irq = irq_of_parse_and_map(np, 0); + of_node_put(np); + if (psc_fifoc_irq == NO_IRQ) { + pr_err("%s: Can't get FIFOC irq\n", __func__); + iounmap(psc_fifoc); + return -ENODEV; + } + + for_each_compatible_node(np, NULL, "fsl,mpc5121-psc-uart") { + tx_fifo_size = get_fifo_size(np, "fsl,tx-fifo-size"); + rx_fifo_size = get_fifo_size(np, "fsl,rx-fifo-size"); + + /* size in register is in 4 byte units */ + tx_fifo_size /= 4; + rx_fifo_size /= 4; + if (!tx_fifo_size) + tx_fifo_size = 1; + if (!rx_fifo_size) + rx_fifo_size = 1; + + psc = of_iomap(np, 0); + if (!psc) { + pr_err("%s: Can't map %s device\n", + __func__, np->full_name); + continue; + } + + /* FIFO space is 4KiB, check if requested size is available */ + if ((fifobase + tx_fifo_size + rx_fifo_size) > 0x1000) { + pr_err("%s: no fifo space available for %s\n", + __func__, np->full_name); + iounmap(psc); + /* + * chances are that another device requests less + * fifo space, so we continue. + */ + continue; + } + /* set tx and rx fifo size registers */ + out_be32(&FIFOC(psc)->txsz, (fifobase << 16) | tx_fifo_size); + fifobase += tx_fifo_size; + out_be32(&FIFOC(psc)->rxsz, (fifobase << 16) | rx_fifo_size); + fifobase += rx_fifo_size; + + /* reset and enable the slices */ + out_be32(&FIFOC(psc)->txcmd, 0x80); + out_be32(&FIFOC(psc)->txcmd, 0x01); + out_be32(&FIFOC(psc)->rxcmd, 0x80); + out_be32(&FIFOC(psc)->rxcmd, 0x01); + + iounmap(psc); + } + + return 0; +} + +static void __exit mpc512x_psc_fifoc_uninit(void) +{ + iounmap(psc_fifoc); +} + +/* 512x specific interrupt handler. The caller holds the port lock */ +static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port) +{ + unsigned long fifoc_int; + int psc_num; + + /* Read pending PSC FIFOC interrupts */ + fifoc_int = in_be32(&psc_fifoc->fifoc_int); + + /* Check if it is an interrupt for this port */ + psc_num = (port->mapbase & 0xf00) >> 8; + if (test_bit(psc_num, &fifoc_int) || + test_bit(psc_num + 16, &fifoc_int)) + return mpc5xxx_uart_process_int(port); + + return IRQ_NONE; +} + +static int mpc512x_psc_clock(struct uart_port *port, int enable) +{ + struct clk *psc_clk; + int psc_num; + char clk_name[10]; + + if (uart_console(port)) + return 0; + + psc_num = (port->mapbase & 0xf00) >> 8; + snprintf(clk_name, sizeof(clk_name), "psc%d_clk", psc_num); + psc_clk = clk_get(port->dev, clk_name); + if (IS_ERR(psc_clk)) { + dev_err(port->dev, "Failed to get PSC clock entry!\n"); + return -ENODEV; + } + + dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis"); + + if (enable) + clk_enable(psc_clk); + else + clk_disable(psc_clk); + + return 0; +} + +static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np) +{ + port->irqflags = IRQF_SHARED; + port->irq = psc_fifoc_irq; +} + static struct psc_ops mpc512x_psc_ops = { .fifo_init = mpc512x_psc_fifo_init, .raw_rx_rdy = mpc512x_psc_raw_rx_rdy, @@ -410,6 +601,11 @@ static struct psc_ops mpc512x_psc_ops = { .cw_disable_ints = mpc512x_psc_cw_disable_ints, .cw_restore_ints = mpc512x_psc_cw_restore_ints, .getuartclk = mpc512x_getuartclk, + .clock = mpc512x_psc_clock, + .fifoc_init = mpc512x_psc_fifoc_init, + .fifoc_uninit = mpc512x_psc_fifoc_uninit, + .get_irq = mpc512x_psc_get_irq, + .handle_irq = mpc512x_psc_handle_irq, }; #endif @@ -519,10 +715,15 @@ mpc52xx_uart_startup(struct uart_port *port) struct mpc52xx_psc __iomem *psc = PSC(port); int ret; + if (psc_ops->clock) { + ret = psc_ops->clock(port, 1); + if (ret) + return ret; + } + /* Request IRQ */ ret = request_irq(port->irq, mpc52xx_uart_int, - IRQF_DISABLED | IRQF_SAMPLE_RANDOM, - "mpc52xx_psc_uart", port); + port->irqflags, "mpc52xx_psc_uart", port); if (ret) return ret; @@ -553,6 +754,9 @@ mpc52xx_uart_shutdown(struct uart_port *port) port->read_status_mask = 0; out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); + if (psc_ops->clock) + psc_ops->clock(port, 0); + /* Release interrupt */ free_irq(port->irq, port); } @@ -851,15 +1055,12 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port) } static irqreturn_t -mpc52xx_uart_int(int irq, void *dev_id) +mpc5xxx_uart_process_int(struct uart_port *port) { - struct uart_port *port = dev_id; unsigned long pass = ISR_PASS_LIMIT; unsigned int keepgoing; u8 status; - spin_lock(&port->lock); - /* While we have stuff to do, we continue */ do { /* If we don't find anything to do, we stop */ @@ -886,11 +1087,23 @@ mpc52xx_uart_int(int irq, void *dev_id) } while (keepgoing); - spin_unlock(&port->lock); - return IRQ_HANDLED; } +static irqreturn_t +mpc52xx_uart_int(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + irqreturn_t ret; + + spin_lock(&port->lock); + + ret = psc_ops->handle_irq(port); + + spin_unlock(&port->lock); + + return ret; +} /* ======================================================================== */ /* Console ( if applicable ) */ @@ -1152,7 +1365,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) return -EINVAL; } - port->irq = irq_of_parse_and_map(op->node, 0); + psc_ops->get_irq(port, op->node); if (port->irq == NO_IRQ) { dev_dbg(&op->dev, "Could not get irq\n"); return -EINVAL; @@ -1163,10 +1376,8 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) /* Add the port to the uart sub-system */ ret = uart_add_one_port(&mpc52xx_uart_driver, port); - if (ret) { - irq_dispose_mapping(port->irq); + if (ret) return ret; - } dev_set_drvdata(&op->dev, (void *)port); return 0; @@ -1178,10 +1389,8 @@ mpc52xx_uart_of_remove(struct of_device *op) struct uart_port *port = dev_get_drvdata(&op->dev); dev_set_drvdata(&op->dev, NULL); - if (port) { + if (port) uart_remove_one_port(&mpc52xx_uart_driver, port); - irq_dispose_mapping(port->irq); - } return 0; } @@ -1288,6 +1497,15 @@ mpc52xx_uart_init(void) mpc52xx_uart_of_enumerate(); + /* + * Map the PSC FIFO Controller and init if on MPC512x. + */ + if (psc_ops->fifoc_init) { + ret = psc_ops->fifoc_init(); + if (ret) + return ret; + } + ret = of_register_platform_driver(&mpc52xx_uart_of_driver); if (ret) { printk(KERN_ERR "%s: of_register_platform_driver failed (%i)\n", @@ -1302,6 +1520,9 @@ mpc52xx_uart_init(void) static void __exit mpc52xx_uart_exit(void) { + if (psc_ops->fifoc_uninit) + psc_ops->fifoc_uninit(); + of_unregister_platform_driver(&mpc52xx_uart_of_driver); uart_unregister_driver(&mpc52xx_uart_driver); } diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index 72d68b3dc47..4637bcbe03a 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -1633,6 +1633,11 @@ static int __init fsl_diu_setup(char *options) #endif static struct of_device_id fsl_diu_match[] = { +#ifdef CONFIG_PPC_MPC512x + { + .compatible = "fsl,mpc5121-diu", + }, +#endif { .compatible = "fsl,diu", }, |