diff options
Diffstat (limited to 'drivers')
41 files changed, 1655 insertions, 403 deletions
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 1b8e592a824..0bba3a914e8 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -838,10 +838,10 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr) * Migrate task to the cpu pointed by pr. */ saved_mask = current->cpus_allowed; - set_cpus_allowed(current, cpumask_of_cpu(pr->id)); + set_cpus_allowed_ptr(current, &cpumask_of_cpu(pr->id)); ret = pr->throttling.acpi_processor_get_throttling(pr); /* restore the previous state */ - set_cpus_allowed(current, saved_mask); + set_cpus_allowed_ptr(current, &saved_mask); return ret; } @@ -1025,7 +1025,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state) * it can be called only for the cpu pointed by pr. */ if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) { - set_cpus_allowed(current, cpumask_of_cpu(pr->id)); + set_cpus_allowed_ptr(current, &cpumask_of_cpu(pr->id)); ret = p_throttling->acpi_processor_set_throttling(pr, t_state.target_state); } else { @@ -1056,7 +1056,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state) continue; } t_state.cpu = i; - set_cpus_allowed(current, cpumask_of_cpu(i)); + set_cpus_allowed_ptr(current, &cpumask_of_cpu(i)); ret = match_pr->throttling. acpi_processor_set_throttling( match_pr, t_state.target_state); @@ -1074,7 +1074,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state) &t_state); } /* restore the previous state */ - set_cpus_allowed(current, saved_mask); + set_cpus_allowed_ptr(current, &saved_mask); return ret; } diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 05ff8c77649..d52ce118832 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -76,6 +76,7 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/ata_platform.h> +#include <linux/mbus.h> #include <scsi/scsi_host.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> @@ -370,6 +371,9 @@ enum { #define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE) #define HAS_PCI(host) (!((host)->ports[0]->flags & MV_FLAG_SOC)) +#define WINDOW_CTRL(i) (0x20030 + ((i) << 4)) +#define WINDOW_BASE(i) (0x20034 + ((i) << 4)) + enum { /* DMA boundary 0xffff is required by the s/g splitting * we need on /length/ in mv_fill-sg(). @@ -2769,6 +2773,27 @@ static int mv_create_dma_pools(struct mv_host_priv *hpriv, struct device *dev) return 0; } +static void mv_conf_mbus_windows(struct mv_host_priv *hpriv, + struct mbus_dram_target_info *dram) +{ + int i; + + for (i = 0; i < 4; i++) { + writel(0, hpriv->base + WINDOW_CTRL(i)); + writel(0, hpriv->base + WINDOW_BASE(i)); + } + + for (i = 0; i < dram->num_cs; i++) { + struct mbus_dram_window *cs = dram->cs + i; + + writel(((cs->size - 1) & 0xffff0000) | + (cs->mbus_attr << 8) | + (dram->mbus_dram_target_id << 4) | 1, + hpriv->base + WINDOW_CTRL(i)); + writel(cs->base, hpriv->base + WINDOW_BASE(i)); + } +} + /** * mv_platform_probe - handle a positive probe of an soc Marvell * host @@ -2823,6 +2848,12 @@ static int mv_platform_probe(struct platform_device *pdev) res->end - res->start + 1); hpriv->base -= MV_SATAHC0_REG_BASE; + /* + * (Re-)program MBUS remapping windows if we are asked to. + */ + if (mv_platform_data->dram != NULL) + mv_conf_mbus_windows(hpriv, mv_platform_data->dram); + rc = mv_create_dma_pools(hpriv, &pdev->dev); if (rc) return rc; diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 499b003f927..2c76afff3b1 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -103,6 +103,51 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL); #endif /* + * Print cpu online, possible, present, and system maps + */ +static ssize_t print_cpus_map(char *buf, cpumask_t *map) +{ + int n = cpulist_scnprintf(buf, PAGE_SIZE-2, *map); + + buf[n++] = '\n'; + buf[n] = '\0'; + return n; +} + +#define print_cpus_func(type) \ +static ssize_t print_cpus_##type(struct sysdev_class *class, char *buf) \ +{ \ + return print_cpus_map(buf, &cpu_##type##_map); \ +} \ +struct sysdev_class_attribute attr_##type##_map = \ + _SYSDEV_CLASS_ATTR(type, 0444, print_cpus_##type, NULL) + +print_cpus_func(online); +print_cpus_func(possible); +print_cpus_func(present); + +struct sysdev_class_attribute *cpu_state_attr[] = { + &attr_online_map, + &attr_possible_map, + &attr_present_map, +}; + +static int cpu_states_init(void) +{ + int i; + int err = 0; + + for (i = 0; i < ARRAY_SIZE(cpu_state_attr); i++) { + int ret; + ret = sysdev_class_create_file(&cpu_sysdev_class, + cpu_state_attr[i]); + if (!err) + err = ret; + } + return err; +} + +/* * register_cpu - Setup a sysfs device for a CPU. * @cpu - cpu->hotpluggable field set to 1 will generate a control file in * sysfs for this CPU. @@ -147,6 +192,9 @@ int __init cpu_dev_init(void) int err; err = sysdev_class_register(&cpu_sysdev_class); + if (!err) + err = cpu_states_init(); + #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) if (!err) err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class); diff --git a/drivers/base/node.c b/drivers/base/node.c index e59861f18ce..12fde2d03d6 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -19,21 +19,34 @@ static struct sysdev_class node_class = { }; -static ssize_t node_read_cpumap(struct sys_device * dev, char * buf) +static ssize_t node_read_cpumap(struct sys_device *dev, int type, char *buf) { struct node *node_dev = to_node(dev); - cpumask_t mask = node_to_cpumask(node_dev->sysdev.id); + node_to_cpumask_ptr(mask, node_dev->sysdev.id); int len; - /* 2004/06/03: buf currently PAGE_SIZE, need > 1 char per 4 bits. */ - BUILD_BUG_ON(MAX_NUMNODES/4 > PAGE_SIZE/2); + /* 2008/04/07: buf currently PAGE_SIZE, need 9 chars per 32 bits. */ + BUILD_BUG_ON((NR_CPUS/32 * 9) > (PAGE_SIZE-1)); - len = cpumask_scnprintf(buf, PAGE_SIZE-1, mask); - len += sprintf(buf + len, "\n"); + len = type? + cpulist_scnprintf(buf, PAGE_SIZE-2, *mask): + cpumask_scnprintf(buf, PAGE_SIZE-2, *mask); + buf[len++] = '\n'; + buf[len] = '\0'; return len; } -static SYSDEV_ATTR(cpumap, S_IRUGO, node_read_cpumap, NULL); +static inline ssize_t node_read_cpumask(struct sys_device *dev, char *buf) +{ + return node_read_cpumap(dev, 0, buf); +} +static inline ssize_t node_read_cpulist(struct sys_device *dev, char *buf) +{ + return node_read_cpumap(dev, 1, buf); +} + +static SYSDEV_ATTR(cpumap, S_IRUGO, node_read_cpumask, NULL); +static SYSDEV_ATTR(cpulist, S_IRUGO, node_read_cpulist, NULL); #define K(x) ((x) << (PAGE_SHIFT - 10)) static ssize_t node_read_meminfo(struct sys_device * dev, char * buf) @@ -149,6 +162,7 @@ int register_node(struct node *node, int num, struct node *parent) if (!error){ sysdev_create_file(&node->sysdev, &attr_cpumap); + sysdev_create_file(&node->sysdev, &attr_cpulist); sysdev_create_file(&node->sysdev, &attr_meminfo); sysdev_create_file(&node->sysdev, &attr_numastat); sysdev_create_file(&node->sysdev, &attr_distance); @@ -166,6 +180,7 @@ int register_node(struct node *node, int num, struct node *parent) void unregister_node(struct node *node) { sysdev_remove_file(&node->sysdev, &attr_cpumap); + sysdev_remove_file(&node->sysdev, &attr_cpulist); sysdev_remove_file(&node->sysdev, &attr_meminfo); sysdev_remove_file(&node->sysdev, &attr_numastat); sysdev_remove_file(&node->sysdev, &attr_distance); diff --git a/drivers/base/topology.c b/drivers/base/topology.c index e1d3ad4db2f..fdf4044d2e7 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -40,15 +40,38 @@ static ssize_t show_##name(struct sys_device *dev, char *buf) \ return sprintf(buf, "%d\n", topology_##name(cpu)); \ } -#define define_siblings_show_func(name) \ -static ssize_t show_##name(struct sys_device *dev, char *buf) \ +static ssize_t show_cpumap(int type, cpumask_t *mask, char *buf) +{ + ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf; + int n = 0; + + if (len > 1) { + n = type? + cpulist_scnprintf(buf, len-2, *mask): + cpumask_scnprintf(buf, len-2, *mask); + buf[n++] = '\n'; + buf[n] = '\0'; + } + return n; +} + +#define define_siblings_show_map(name) \ +static inline ssize_t show_##name(struct sys_device *dev, char *buf) \ { \ - ssize_t len = -1; \ unsigned int cpu = dev->id; \ - len = cpumask_scnprintf(buf, NR_CPUS+1, topology_##name(cpu)); \ - return (len + sprintf(buf + len, "\n")); \ + return show_cpumap(0, &(topology_##name(cpu)), buf); \ } +#define define_siblings_show_list(name) \ +static inline ssize_t show_##name##_list(struct sys_device *dev, char *buf) \ +{ \ + unsigned int cpu = dev->id; \ + return show_cpumap(1, &(topology_##name(cpu)), buf); \ +} + +#define define_siblings_show_func(name) \ + define_siblings_show_map(name); define_siblings_show_list(name) + #ifdef topology_physical_package_id define_id_show_func(physical_package_id); define_one_ro(physical_package_id); @@ -68,7 +91,9 @@ define_one_ro(core_id); #ifdef topology_thread_siblings define_siblings_show_func(thread_siblings); define_one_ro(thread_siblings); -#define ref_thread_siblings_attr &attr_thread_siblings.attr, +define_one_ro(thread_siblings_list); +#define ref_thread_siblings_attr \ + &attr_thread_siblings.attr, &attr_thread_siblings_list.attr, #else #define ref_thread_siblings_attr #endif @@ -76,7 +101,9 @@ define_one_ro(thread_siblings); #ifdef topology_core_siblings define_siblings_show_func(core_siblings); define_one_ro(core_siblings); -#define ref_core_siblings_attr &attr_core_siblings.attr, +define_one_ro(core_siblings_list); +#define ref_core_siblings_attr \ + &attr_core_siblings.attr, &attr_core_siblings_list.attr, #else #define ref_core_siblings_attr #endif diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index d8822eedba6..f235940719e 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c @@ -264,7 +264,7 @@ static int smi_request(struct smi_cmd *smi_cmd) /* SMI requires CPU 0 */ old_mask = current->cpus_allowed; - set_cpus_allowed(current, cpumask_of_cpu(0)); + set_cpus_allowed_ptr(current, &cpumask_of_cpu(0)); if (smp_processor_id() != 0) { dev_dbg(&dcdbas_pdev->dev, "%s: failed to get CPU 0\n", __FUNCTION__); @@ -284,7 +284,7 @@ static int smi_request(struct smi_cmd *smi_cmd) ); out: - set_cpus_allowed(current, old_mask); + set_cpus_allowed_ptr(current, &old_mask); return ret; } diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 5fa9c3c67e0..b04c99580d0 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -645,7 +645,7 @@ config I2C_PCA_ISA config I2C_MV64XXX tristate "Marvell mv64xxx I2C Controller" - depends on (MV64X60 || ARCH_ORION) && EXPERIMENTAL + depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL help If you say yes to this option, support will be included for the built-in I2C interface on the Marvell 64xxx line of host bridges. diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 2d2087ad708..6fd2d6a84ef 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -39,6 +39,7 @@ #include <asm/io.h> #include <asm/arch/i2c.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-gpio.h> struct pxa_i2c { spinlock_t lock; diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index b21593f9358..2da2edfa68e 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -93,6 +93,7 @@ config ISP1301_OMAP config TPS65010 tristate "TPS6501x Power Management chips" + depends on HAVE_GPIO_LIB default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK help If you say yes here you get support for the TPS6501x series of diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index 4154a910885..b67f69c2e7f 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -30,9 +30,13 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/mutex.h> +#include <linux/platform_device.h> #include <linux/i2c/tps65010.h> +#include <asm/gpio.h> + + /*-------------------------------------------------------------------------*/ #define DRIVER_VERSION "2 May 2005" @@ -84,7 +88,9 @@ struct tps65010 { u8 chgstatus, regstatus, chgconf; u8 nmask1, nmask2; - /* not currently tracking GPIO state */ + u8 outmask; + struct gpio_chip chip; + struct platform_device *leds; }; #define POWER_POLL_DELAY msecs_to_jiffies(5000) @@ -449,12 +455,72 @@ static irqreturn_t tps65010_irq(int irq, void *_tps) /*-------------------------------------------------------------------------*/ +/* offsets 0..3 == GPIO1..GPIO4 + * offsets 4..5 == LED1/nPG, LED2 (we set one of the non-BLINK modes) + */ +static void +tps65010_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + if (offset < 4) + tps65010_set_gpio_out_value(offset + 1, value); + else + tps65010_set_led(offset - 3, value ? ON : OFF); +} + +static int +tps65010_output(struct gpio_chip *chip, unsigned offset, int value) +{ + /* GPIOs may be input-only */ + if (offset < 4) { + struct tps65010 *tps; + + tps = container_of(chip, struct tps65010, chip); + if (!(tps->outmask & (1 << offset))) + return -EINVAL; + tps65010_set_gpio_out_value(offset + 1, value); + } else + tps65010_set_led(offset - 3, value ? ON : OFF); + + return 0; +} + +static int tps65010_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + int value; + struct tps65010 *tps; + + tps = container_of(chip, struct tps65010, chip); + + if (offset < 4) { + value = i2c_smbus_read_byte_data(tps->client, TPS_DEFGPIO); + if (value < 0) + return 0; + if (value & (1 << (offset + 4))) /* output */ + return !(value & (1 << offset)); + else /* input */ + return (value & (1 << offset)); + } + + /* REVISIT we *could* report LED1/nPG and LED2 state ... */ + return 0; +} + + +/*-------------------------------------------------------------------------*/ + static struct tps65010 *the_tps; static int __exit tps65010_remove(struct i2c_client *client) { struct tps65010 *tps = i2c_get_clientdata(client); + struct tps65010_board *board = client->dev.platform_data; + if (board && board->teardown) { + int status = board->teardown(client, board->context); + if (status < 0) + dev_dbg(&client->dev, "board %s %s err %d\n", + "teardown", client->name, status); + } if (client->irq > 0) free_irq(client->irq, tps); cancel_delayed_work(&tps->work); @@ -469,6 +535,7 @@ static int tps65010_probe(struct i2c_client *client) { struct tps65010 *tps; int status; + struct tps65010_board *board = client->dev.platform_data; if (the_tps) { dev_dbg(&client->dev, "only one tps6501x chip allowed\n"); @@ -577,6 +644,38 @@ static int tps65010_probe(struct i2c_client *client) tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL, tps, DEBUG_FOPS); + + /* optionally register GPIOs */ + if (board && board->base > 0) { + tps->outmask = board->outmask; + + tps->chip.label = client->name; + + tps->chip.set = tps65010_gpio_set; + tps->chip.direction_output = tps65010_output; + + /* NOTE: only partial support for inputs; nyet IRQs */ + tps->chip.get = tps65010_gpio_get; + + tps->chip.base = board->base; + tps->chip.ngpio = 6; + tps->chip.can_sleep = 1; + + status = gpiochip_add(&tps->chip); + if (status < 0) + dev_err(&client->dev, "can't add gpiochip, err %d\n", + status); + else if (board->setup) { + status = board->setup(client, board->context); + if (status < 0) { + dev_dbg(&client->dev, + "board %s %s err %d\n", + "setup", client->name, status); + status = 0; + } + } + } + return 0; fail1: kfree(tps); diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 8ea709be330..efd70a97459 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 e741f403101..0edc8f285d1 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/corgikbd.c b/drivers/input/keyboard/corgikbd.c index 790fed368aa..5d6cc7f1dc9 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c @@ -23,6 +23,7 @@ #include <asm/arch/corgi.h> #include <asm/arch/hardware.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-gpio.h> #include <asm/hardware/scoop.h> #define KB_ROWS 8 diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c new file mode 100644 index 00000000000..8486abc457e --- /dev/null +++ b/drivers/input/keyboard/sh_keysc.c @@ -0,0 +1,280 @@ +/* + * 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/io.h> +#include <asm/sh_keysc.h> + +#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); + 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"); diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index 1d59a2dc3c1..0be74bfc58f 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c @@ -23,6 +23,7 @@ #include <asm/arch/spitz.h> #include <asm/arch/hardware.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-gpio.h> #define KB_ROWS 7 #define KB_COLS 11 diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 57a1c28bf12..39573b91c8d 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -28,13 +28,6 @@ #include <linux/spi/ads7846.h> #include <asm/irq.h> -#ifdef CONFIG_ARM -#include <asm/mach-types.h> -#ifdef CONFIG_ARCH_OMAP -#include <asm/arch/gpio.h> -#endif -#endif - /* * This code has been heavily tested on a Nokia 770, and lightly @@ -1174,31 +1167,6 @@ static struct spi_driver ads7846_driver = { static int __init ads7846_init(void) { - /* grr, board-specific init should stay out of drivers!! */ - -#ifdef CONFIG_ARCH_OMAP - if (machine_is_omap_osk()) { - /* GPIO4 = PENIRQ; GPIO6 = BUSY */ - omap_request_gpio(4); - omap_set_gpio_direction(4, 1); - omap_request_gpio(6); - omap_set_gpio_direction(6, 1); - } - // also TI 1510 Innovator, bitbanging through FPGA - // also Nokia 770 - // also Palm Tungsten T2 -#endif - - // PXA: - // also Dell Axim X50 - // also HP iPaq H191x/H192x/H415x/H435x - // also Intel Lubbock (additional to UCB1400; as temperature sensor) - // also Sharp Zaurus C7xx, C8xx (corgi/sheperd/husky) - - // Atmel at91sam9261-EK uses ads7843 - - // also various AMD Au1x00 devel boards - return spi_register_driver(&ads7846_driver); } module_init(ads7846_init); @@ -1206,14 +1174,6 @@ module_init(ads7846_init); static void __exit ads7846_exit(void) { spi_unregister_driver(&ads7846_driver); - -#ifdef CONFIG_ARCH_OMAP - if (machine_is_omap_osk()) { - omap_free_gpio(4); - omap_free_gpio(6); - } -#endif - } module_exit(ads7846_exit); diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index 99d92f5c93d..a22576779ac 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c @@ -22,6 +22,7 @@ #include <asm/arch/sharpsl.h> #include <asm/arch/hardware.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-gpio.h> #define PWR_MODE_ACTIVE 0 diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 859814f62cb..a3a6199639f 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -46,13 +46,6 @@ config LEDS_SPITZ This option enables support for the LEDs on Sharp Zaurus SL-Cxx00 series (C1000, C3000, C3100). -config LEDS_TOSA - tristate "LED Support for the Sharp SL-6000 series" - depends on LEDS_CLASS && PXA_SHARPSL - help - This option enables support for the LEDs on Sharp Zaurus - SL-6000 series. - config LEDS_S3C24XX tristate "LED Support for Samsung S3C24XX GPIO LEDs" depends on LEDS_CLASS && ARCH_S3C2410 diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 84ced3b1a13..e54f42da21a 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o obj-$(CONFIG_LEDS_CORGI) += leds-corgi.o obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o -obj-$(CONFIG_LEDS_TOSA) += leds-tosa.o obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o diff --git a/drivers/leds/leds-tosa.c b/drivers/leds/leds-tosa.c deleted file mode 100644 index 7ebecc41a9b..00000000000 --- a/drivers/leds/leds-tosa.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * LED Triggers Core - * - * Copyright 2005 Dirk Opfer - * - * Author: Dirk Opfer <Dirk@Opfer-Online.de> - * based on spitz.c - * - * 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/kernel.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/leds.h> -#include <asm/hardware/scoop.h> -#include <asm/mach-types.h> -#include <asm/arch/hardware.h> -#include <asm/arch/pxa-regs.h> -#include <asm/arch/tosa.h> - -static void tosaled_amber_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - if (value) - set_scoop_gpio(&tosascoop_jc_device.dev, - TOSA_SCOOP_JC_CHRG_ERR_LED); - else - reset_scoop_gpio(&tosascoop_jc_device.dev, - TOSA_SCOOP_JC_CHRG_ERR_LED); -} - -static void tosaled_green_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - if (value) - set_scoop_gpio(&tosascoop_jc_device.dev, - TOSA_SCOOP_JC_NOTE_LED); - else - reset_scoop_gpio(&tosascoop_jc_device.dev, - TOSA_SCOOP_JC_NOTE_LED); -} - -static struct led_classdev tosa_amber_led = { - .name = "tosa:amber:charge", - .default_trigger = "sharpsl-charge", - .brightness_set = tosaled_amber_set, -}; - -static struct led_classdev tosa_green_led = { - .name = "tosa:green:mail", - .default_trigger = "nand-disk", - .brightness_set = tosaled_green_set, -}; - -#ifdef CONFIG_PM -static int tosaled_suspend(struct platform_device *dev, pm_message_t state) -{ -#ifdef CONFIG_LEDS_TRIGGERS - if (tosa_amber_led.trigger && strcmp(tosa_amber_led.trigger->name, - "sharpsl-charge")) -#endif - led_classdev_suspend(&tosa_amber_led); - led_classdev_suspend(&tosa_green_led); - return 0; -} - -static int tosaled_resume(struct platform_device *dev) -{ - led_classdev_resume(&tosa_amber_led); - led_classdev_resume(&tosa_green_led); - return 0; -} -#else -#define tosaled_suspend NULL -#define tosaled_resume NULL -#endif - -static int tosaled_probe(struct platform_device *pdev) -{ - int ret; - - ret = led_classdev_register(&pdev->dev, &tosa_amber_led); - if (ret < 0) - return ret; - - ret = led_classdev_register(&pdev->dev, &tosa_green_led); - if (ret < 0) - led_classdev_unregister(&tosa_amber_led); - - return ret; -} - -static int tosaled_remove(struct platform_device *pdev) -{ - led_classdev_unregister(&tosa_amber_led); - led_classdev_unregister(&tosa_green_led); - - return 0; -} - -static struct platform_driver tosaled_driver = { - .probe = tosaled_probe, - .remove = tosaled_remove, - .suspend = tosaled_suspend, - .resume = tosaled_resume, - .driver = { - .name = "tosa-led", - .owner = THIS_MODULE, - }, -}; - -static int __init tosaled_init(void) -{ - return platform_driver_register(&tosaled_driver); -} - -static void __exit tosaled_exit(void) -{ - platform_driver_unregister(&tosaled_driver); -} - -module_init(tosaled_init); -module_exit(tosaled_exit); - -MODULE_AUTHOR("Dirk Opfer <Dirk@Opfer-Online.de>"); -MODULE_DESCRIPTION("Tosa LED driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:tosa-led"); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 0c886c88238..2566479937c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -22,6 +22,22 @@ config MFD_ASIC3 This driver supports the ASIC3 multifunction chip found on many PDAs (mainly iPAQ and HTC based ones) +config HTC_EGPIO + bool "HTC EGPIO support" + depends on GENERIC_HARDIRQS && HAVE_GPIO_LIB + help + This driver supports the CPLD egpio chip present on + several HTC phones. It provides basic support for input + pins, output pins, and irqs. + +config HTC_PASIC3 + tristate "HTC PASIC3 LED/DS1WM chip support" + help + This core driver provides register access for the LED/DS1WM + chips labeled "AIC2" and "AIC3", found on HTC Blueangel and + HTC Magician devices, respectively. Actual functionality is + handled by the leds-pasic3 and ds1wm drivers. + endmenu menu "Multimedia Capabilities Port drivers" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 521cd5cb68a..eef4e26807d 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -5,6 +5,9 @@ obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_MFD_ASIC3) += asic3.o +obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o +obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o + obj-$(CONFIG_MCP) += mcp-core.o obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c new file mode 100644 index 00000000000..8872cc07751 --- /dev/null +++ b/drivers/mfd/htc-egpio.c @@ -0,0 +1,440 @@ +/* + * Support for the GPIO/IRQ expander chips present on several HTC phones. + * These are implemented in CPLD chips present on the board. + * + * Copyright (c) 2007 Kevin O'Connor <kevin@koconnor.net> + * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com> + * + * This file may be distributed under the terms of the GNU GPL license. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/mfd/htc-egpio.h> + +struct egpio_chip { + int reg_start; + int cached_values; + unsigned long is_out; + struct device *dev; + struct gpio_chip chip; +}; + +struct egpio_info { + spinlock_t lock; + + /* iomem info */ + void __iomem *base_addr; + int bus_shift; /* byte shift */ + int reg_shift; /* bit shift */ + int reg_mask; + + /* irq info */ + int ack_register; + int ack_write; + u16 irqs_enabled; + uint irq_start; + int nirqs; + uint chained_irq; + + /* egpio info */ + struct egpio_chip *chip; + int nchips; +}; + +static inline void egpio_writew(u16 value, struct egpio_info *ei, int reg) +{ + writew(value, ei->base_addr + (reg << ei->bus_shift)); +} + +static inline u16 egpio_readw(struct egpio_info *ei, int reg) +{ + return readw(ei->base_addr + (reg << ei->bus_shift)); +} + +/* + * IRQs + */ + +static inline void ack_irqs(struct egpio_info *ei) +{ + egpio_writew(ei->ack_write, ei, ei->ack_register); + pr_debug("EGPIO ack - write %x to base+%x\n", + ei->ack_write, ei->ack_register << ei->bus_shift); +} + +static void egpio_ack(unsigned int irq) +{ +} + +/* There does not appear to be a way to proactively mask interrupts + * on the egpio chip itself. So, we simply ignore interrupts that + * aren't desired. */ +static void egpio_mask(unsigned int irq) +{ + struct egpio_info *ei = get_irq_chip_data(irq); + ei->irqs_enabled &= ~(1 << (irq - ei->irq_start)); + pr_debug("EGPIO mask %d %04x\n", irq, ei->irqs_enabled); +} +static void egpio_unmask(unsigned int irq) +{ + struct egpio_info *ei = get_irq_chip_data(irq); + ei->irqs_enabled |= 1 << (irq - ei->irq_start); + pr_debug("EGPIO unmask %d %04x\n", irq, ei->irqs_enabled); +} + +static struct irq_chip egpio_muxed_chip = { + .name = "htc-egpio", + .ack = egpio_ack, + .mask = egpio_mask, + .unmask = egpio_unmask, +}; + +static void egpio_handler(unsigned int irq, struct irq_desc *desc) +{ + struct egpio_info *ei = get_irq_data(irq); + int irqpin; + + /* Read current pins. */ + unsigned long readval = egpio_readw(ei, ei->ack_register); + pr_debug("IRQ reg: %x\n", (unsigned int)readval); + /* Ack/unmask interrupts. */ + ack_irqs(ei); + /* Process all set pins. */ + readval &= ei->irqs_enabled; + for_each_bit(irqpin, &readval, ei->nirqs) { + /* Run irq handler */ + pr_debug("got IRQ %d\n", irqpin); + irq = ei->irq_start + irqpin; + desc = &irq_desc[irq]; + desc->handle_irq(irq, desc); + } +} + +int htc_egpio_get_wakeup_irq(struct device *dev) +{ + struct egpio_info *ei = dev_get_drvdata(dev); + + /* Read current pins. */ + u16 readval = egpio_readw(ei, ei->ack_register); + /* Ack/unmask interrupts. */ + ack_irqs(ei); + /* Return first set pin. */ + readval &= ei->irqs_enabled; + return ei->irq_start + ffs(readval) - 1; +} +EXPORT_SYMBOL(htc_egpio_get_wakeup_irq); + +static inline int egpio_pos(struct egpio_info *ei, int bit) +{ + return bit >> ei->reg_shift; +} + +static inline int egpio_bit(struct egpio_info *ei, int bit) +{ + return 1 << (bit & ((1 << ei->reg_shift)-1)); +} + +/* + * Input pins + */ + +static int egpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct egpio_chip *egpio; + struct egpio_info *ei; + unsigned bit; + int reg; + int value; + + pr_debug("egpio_get_value(%d)\n", chip->base + offset); + + egpio = container_of(chip, struct egpio_chip, chip); + ei = dev_get_drvdata(egpio->dev); + bit = egpio_bit(ei, offset); + reg = egpio->reg_start + egpio_pos(ei, offset); + + value = egpio_readw(ei, reg); + pr_debug("readw(%p + %x) = %x\n", + ei->base_addr, reg << ei->bus_shift, value); + return value & bit; +} + +static int egpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct egpio_chip *egpio; + + egpio = container_of(chip, struct egpio_chip, chip); + return test_bit(offset, &egpio->is_out) ? -EINVAL : 0; +} + + +/* + * Output pins + */ + +static void egpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + unsigned long flag; + struct egpio_chip *egpio; + struct egpio_info *ei; + unsigned bit; + int pos; + int reg; + int shift; + + pr_debug("egpio_set(%s, %d(%d), %d)\n", + chip->label, offset, offset+chip->base, value); + + egpio = container_of(chip, struct egpio_chip, chip); + ei = dev_get_drvdata(egpio->dev); + bit = egpio_bit(ei, offset); + pos = egpio_pos(ei, offset); + reg = egpio->reg_start + pos; + shift = pos << ei->reg_shift; + + pr_debug("egpio %s: reg %d = 0x%04x\n", value ? "set" : "clear", + reg, (egpio->cached_values >> shift) & ei->reg_mask); + + spin_lock_irqsave(&ei->lock, flag); + if (value) + egpio->cached_values |= (1 << offset); + else + egpio->cached_values &= ~(1 << offset); + egpio_writew((egpio->cached_values >> shift) & ei->reg_mask, ei, reg); + spin_unlock_irqrestore(&ei->lock, flag); +} + +static int egpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct egpio_chip *egpio; + + egpio = container_of(chip, struct egpio_chip, chip); + if (test_bit(offset, &egpio->is_out)) { + egpio_set(chip, offset, value); + return 0; + } else { + return -EINVAL; + } +} + +static void egpio_write_cache(struct egpio_info *ei) +{ + int i; + struct egpio_chip *egpio; + int shift; + + for (i = 0; i < ei->nchips; i++) { + egpio = &(ei->chip[i]); + if (!egpio->is_out) + continue; + + for (shift = 0; shift < egpio->chip.ngpio; + shift += (1<<ei->reg_shift)) { + + int reg = egpio->reg_start + egpio_pos(ei, shift); + + if (!((egpio->is_out >> shift) & ei->reg_mask)) + continue; + + pr_debug("EGPIO: setting %x to %x, was %x\n", reg, + (egpio->cached_values >> shift) & ei->reg_mask, + egpio_readw(ei, reg)); + + egpio_writew((egpio->cached_values >> shift) + & ei->reg_mask, ei, reg); + } + } +} + + +/* + * Setup + */ + +static int __init egpio_probe(struct platform_device *pdev) +{ + struct htc_egpio_platform_data *pdata = pdev->dev.platform_data; + struct resource *res; + struct egpio_info *ei; + struct gpio_chip *chip; + unsigned int irq, irq_end; + int i; + int ret; + + /* Initialize ei data structure. */ + ei = kzalloc(sizeof(*ei), GFP_KERNEL); + if (!ei) + return -ENOMEM; + + spin_lock_init(&ei->lock); + + /* Find chained irq */ + ret = -EINVAL; + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res) + ei->chained_irq = res->start; + + /* Map egpio chip into virtual address space. */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + goto fail; + ei->base_addr = ioremap_nocache(res->start, res->end - res->start); + if (!ei->base_addr) + goto fail; + pr_debug("EGPIO phys=%08x virt=%p\n", res->start, ei->base_addr); + + if ((pdata->bus_width != 16) && (pdata->bus_width != 32)) + goto fail; + ei->bus_shift = fls(pdata->bus_width - 1) - 3; + pr_debug("bus_shift = %d\n", ei->bus_shift); + + if ((pdata->reg_width != 8) && (pdata->reg_width != 16)) + goto fail; + ei->reg_shift = fls(pdata->reg_width - 1); + pr_debug("reg_shift = %d\n", ei->reg_shift); + + ei->reg_mask = (1 << pdata->reg_width) - 1; + + platform_set_drvdata(pdev, ei); + + ei->nchips = pdata->num_chips; + ei->chip = kzalloc(sizeof(struct egpio_chip) * ei->nchips, GFP_KERNEL); + if (!ei) { + ret = -ENOMEM; + goto fail; + } + for (i = 0; i < ei->nchips; i++) { + ei->chip[i].reg_start = pdata->chip[i].reg_start; + ei->chip[i].cached_values = pdata->chip[i].initial_values; + ei->chip[i].is_out = pdata->chip[i].direction; + ei->chip[i].dev = &(pdev->dev); + chip = &(ei->chip[i].chip); + chip->label = "htc-egpio"; + chip->get = egpio_get; + chip->set = egpio_set; + chip->direction_input = egpio_direction_input; + chip->direction_output = egpio_direction_output; + chip->base = pdata->chip[i].gpio_base; + chip->ngpio = pdata->chip[i].num_gpios; + + gpiochip_add(chip); + } + + /* Set initial pin values */ + egpio_write_cache(ei); + + ei->irq_start = pdata->irq_base; + ei->nirqs = pdata->num_irqs; + ei->ack_register = pdata->ack_register; + + if (ei->chained_irq) { + /* Setup irq handlers */ + ei->ack_write = 0xFFFF; + if (pdata->invert_acks) + ei->ack_write = 0; + irq_end = ei->irq_start + ei->nirqs; + for (irq = ei->irq_start; irq < irq_end; irq++) { + set_irq_chip(irq, &egpio_muxed_chip); + set_irq_chip_data(irq, ei); + set_irq_handler(irq, handle_simple_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING); + set_irq_data(ei->chained_irq, ei); + set_irq_chained_handler(ei->chained_irq, egpio_handler); + ack_irqs(ei); + + device_init_wakeup(&pdev->dev, 1); + } + + return 0; + +fail: + printk(KERN_ERR "EGPIO failed to setup\n"); + kfree(ei); + return ret; +} + +static int __exit egpio_remove(struct platform_device *pdev) +{ + struct egpio_info *ei = platform_get_drvdata(pdev); + unsigned int irq, irq_end; + + if (ei->chained_irq) { + irq_end = ei->irq_start + ei->nirqs; + for (irq = ei->irq_start; irq < irq_end; irq++) { + set_irq_chip(irq, NULL); + set_irq_handler(irq, NULL); + set_irq_flags(irq, 0); + } + set_irq_chained_handler(ei->chained_irq, NULL); + device_init_wakeup(&pdev->dev, 0); + } + iounmap(ei->base_addr); + kfree(ei->chip); + kfree(ei); + + return 0; +} + +#ifdef CONFIG_PM +static int egpio_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct egpio_info *ei = platform_get_drvdata(pdev); + + if (ei->chained_irq && device_may_wakeup(&pdev->dev)) + enable_irq_wake(ei->chained_irq); + return 0; +} + +static int egpio_resume(struct platform_device *pdev) +{ + struct egpio_info *ei = platform_get_drvdata(pdev); + + if (ei->chained_irq && device_may_wakeup(&pdev->dev)) + disable_irq_wake(ei->chained_irq); + + /* Update registers from the cache, in case + the CPLD was powered off during suspend */ + egpio_write_cache(ei); + return 0; +} +#else +#define egpio_suspend NULL +#define egpio_resume NULL +#endif + + +static struct platform_driver egpio_driver = { + .driver = { + .name = "htc-egpio", + }, + .remove = __exit_p(egpio_remove), + .suspend = egpio_suspend, + .resume = egpio_resume, +}; + +static int __init egpio_init(void) +{ + return platform_driver_probe(&egpio_driver, egpio_probe); +} + +static void __exit egpio_exit(void) +{ + platform_driver_unregister(&egpio_driver); +} + +/* start early for dependencies */ +subsys_initcall(egpio_init); +module_exit(egpio_exit) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin O'Connor <kevin@koconnor.net>"); diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c new file mode 100644 index 00000000000..af66f4f2830 --- /dev/null +++ b/drivers/mfd/htc-pasic3.c @@ -0,0 +1,265 @@ +/* + * Core driver for HTC PASIC3 LED/DS1WM chip. + * + * Copyright (C) 2006 Philipp Zabel <philipp.zabel@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include <linux/ds1wm.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/mfd/htc-pasic3.h> + +#include <asm/arch/pxa-regs.h> + +struct pasic3_data { + void __iomem *mapping; + unsigned int bus_shift; + struct platform_device *ds1wm_pdev; + struct platform_device *led_pdev; +}; + +#define REG_ADDR 5 +#define REG_DATA 6 +#define NUM_REGS 7 + +#define READ_MODE 0x80 + +/* + * write to a secondary register on the PASIC3 + */ +void pasic3_write_register(struct device *dev, u32 reg, u8 val) +{ + struct pasic3_data *asic = dev->driver_data; + int bus_shift = asic->bus_shift; + void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift); + void __iomem *data = asic->mapping + (REG_DATA << bus_shift); + + __raw_writeb(~READ_MODE & reg, addr); + __raw_writeb(val, data); +} +EXPORT_SYMBOL(pasic3_write_register); /* for leds-pasic3 */ + +/* + * read from a secondary register on the PASIC3 + */ +u8 pasic3_read_register(struct device *dev, u32 reg) +{ + struct pasic3_data *asic = dev->driver_data; + int bus_shift = asic->bus_shift; + void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift); + void __iomem *data = asic->mapping + (REG_DATA << bus_shift); + + __raw_writeb(READ_MODE | reg, addr); + return __raw_readb(data); +} +EXPORT_SYMBOL(pasic3_read_register); /* for leds-pasic3 */ + +/* + * LEDs + */ + +static int led_device_add(struct device *pasic3_dev, + const struct pasic3_leds_machinfo *pdata) +{ + struct pasic3_data *asic = pasic3_dev->driver_data; + struct platform_device *pdev; + int ret; + + pdev = platform_device_alloc("pasic3-led", -1); + if (!pdev) { + dev_dbg(pasic3_dev, "failed to allocate LED platform device\n"); + return -ENOMEM; + } + + ret = platform_device_add_data(pdev, pdata, + sizeof(struct pasic3_leds_machinfo)); + if (ret < 0) { + dev_dbg(pasic3_dev, "failed to add LED platform data\n"); + goto exit_pdev_put; + } + + pdev->dev.parent = pasic3_dev; + ret = platform_device_add(pdev); + if (ret < 0) { + dev_dbg(pasic3_dev, "failed to add LED platform device\n"); + goto exit_pdev_put; + } + + asic->led_pdev = pdev; + return 0; + +exit_pdev_put: + platform_device_put(pdev); + return ret; +} + +/* + * DS1WM + */ + +static void ds1wm_enable(struct platform_device *pdev) +{ + struct device *dev = pdev->dev.parent; + int c; + + c = pasic3_read_register(dev, 0x28); + pasic3_write_register(dev, 0x28, c & 0x7f); + + dev_dbg(dev, "DS1WM OWM_EN low (active) %02x\n", c & 0x7f); +} + +static void ds1wm_disable(struct platform_device *pdev) +{ + struct device *dev = pdev->dev.parent; + int c; + + c = pasic3_read_register(dev, 0x28); + pasic3_write_register(dev, 0x28, c | 0x80); + + dev_dbg(dev, "DS1WM OWM_EN high (inactive) %02x\n", c | 0x80); +} + +static struct ds1wm_platform_data ds1wm_pdata = { + .bus_shift = 2, + .enable = ds1wm_enable, + .disable = ds1wm_disable, +}; + +static int ds1wm_device_add(struct device *pasic3_dev, int bus_shift) +{ + struct pasic3_data *asic = pasic3_dev->driver_data; + struct platform_device *pdev; + int ret; + + pdev = platform_device_alloc("ds1wm", -1); + if (!pdev) { + dev_dbg(pasic3_dev, "failed to allocate DS1WM platform device\n"); + return -ENOMEM; + } + + ret = platform_device_add_resources(pdev, pdev->resource, + pdev->num_resources); + if (ret < 0) { + dev_dbg(pasic3_dev, "failed to add DS1WM resources\n"); + goto exit_pdev_put; + } + + ds1wm_pdata.bus_shift = asic->bus_shift; + ret = platform_device_add_data(pdev, &ds1wm_pdata, + sizeof(struct ds1wm_platform_data)); + if (ret < 0) { + dev_dbg(pasic3_dev, "failed to add DS1WM platform data\n"); + goto exit_pdev_put; + } + + pdev->dev.parent = pasic3_dev; + ret = platform_device_add(pdev); + if (ret < 0) { + dev_dbg(pasic3_dev, "failed to add DS1WM platform device\n"); + goto exit_pdev_put; + } + + asic->ds1wm_pdev = pdev; + return 0; + +exit_pdev_put: + platform_device_put(pdev); + return ret; +} + +static int __init pasic3_probe(struct platform_device *pdev) +{ + struct pasic3_platform_data *pdata = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + struct pasic3_data *asic; + struct resource *r; + int ret; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) + return -ENXIO; + + if (!request_mem_region(r->start, r->end - r->start + 1, "pasic3")) + return -EBUSY; + + asic = kzalloc(sizeof(struct pasic3_data), GFP_KERNEL); + if (!asic) + return -ENOMEM; + + platform_set_drvdata(pdev, asic); + + if (pdata && pdata->bus_shift) + asic->bus_shift = pdata->bus_shift; + else + asic->bus_shift = 2; + + asic->mapping = ioremap(r->start, r->end - r->start + 1); + if (!asic->mapping) { + dev_err(dev, "couldn't ioremap PASIC3\n"); + kfree(asic); + return -ENOMEM; + } + + ret = ds1wm_device_add(dev, asic->bus_shift); + if (ret < 0) + dev_warn(dev, "failed to register DS1WM\n"); + + if (pdata->led_pdata) { + ret = led_device_add(dev, pdata->led_pdata); + if (ret < 0) + dev_warn(dev, "failed to register LED device\n"); + } + + return 0; +} + +static int pasic3_remove(struct platform_device *pdev) +{ + struct pasic3_data *asic = platform_get_drvdata(pdev); + struct resource *r; + + if (asic->led_pdev) + platform_device_unregister(asic->led_pdev); + if (asic->ds1wm_pdev) + platform_device_unregister(asic->ds1wm_pdev); + + iounmap(asic->mapping); + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(r->start, r->end - r->start + 1); + kfree(asic); + return 0; +} + +static struct platform_driver pasic3_driver = { + .driver = { + .name = "pasic3", + }, + .remove = pasic3_remove, +}; + +static int __init pasic3_base_init(void) +{ + return platform_driver_probe(&pasic3_driver, pasic3_probe); +} + +static void __exit pasic3_base_exit(void) +{ + platform_driver_unregister(&pasic3_driver); +} + +module_init(pasic3_base_init); +module_exit(pasic3_base_exit); + +MODULE_AUTHOR("Philipp Zabel <philipp.zabel@gmail.com>"); +MODULE_DESCRIPTION("Core driver for HTC PASIC3"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 4a3c6759492..959fb86cda0 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -314,7 +314,7 @@ config MTD_ALAUDA config MTD_NAND_ORION tristate "NAND Flash support for Marvell Orion SoC" - depends on ARCH_ORION && MTD_NAND + depends on PLAT_ORION && MTD_NAND help This enables the NAND flash controller on Orion machines. diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 9162cca0182..ec5ad28b237 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -18,8 +18,8 @@ #include <linux/mtd/partitions.h> #include <asm/io.h> #include <asm/sizes.h> -#include <asm/arch/platform.h> #include <asm/arch/hardware.h> +#include <asm/plat-orion/orion_nand.h> #ifdef CONFIG_MTD_CMDLINE_PARTS static const char *part_probes[] = { "cmdlinepart", NULL }; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 45c3a208d93..2399a3796f6 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2335,7 +2335,7 @@ config UGETH_TX_ON_DEMAND config MV643XX_ETH tristate "Marvell Discovery (643XX) and Orion ethernet support" - depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || ARCH_ORION + depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || PLAT_ORION select MII help This driver supports the gigabit ethernet MACs in the diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 0ae0d83e5d2..978e20a1791 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -1043,7 +1043,9 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add } else if (machine_is_csb337()) { /* mix link activity status into LED2 link state */ write_phy(phy_address, MII_LEDCTRL_REG, 0x0d22); - } + } else if (machine_is_ecbat91()) + write_phy(phy_address, MII_LEDCTRL_REG, 0x156A); + disable_mdi(); spin_unlock_irq(&lp->lock); diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index 8c09344f58d..8db71ab2045 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -36,6 +36,7 @@ #include <asm/hardware.h> #include <asm/arch/irda.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-gpio.h> #ifdef CONFIG_MACH_MAINSTONE #include <asm/arch/mainstone.h> @@ -831,6 +832,11 @@ static int pxa_irda_probe(struct platform_device *pdev) if (err) goto err_mem_5; + if (si->pdata->startup) + err = si->pdata->startup(si->dev); + if (err) + goto err_startup; + dev->hard_start_xmit = pxa_irda_hard_xmit; dev->open = pxa_irda_start; dev->stop = pxa_irda_stop; @@ -856,6 +862,9 @@ static int pxa_irda_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, dev); if (err) { + if (si->pdata->shutdown) + si->pdata->shutdown(si->dev); +err_startup: kfree(si->tx_buff.head); err_mem_5: kfree(si->rx_buff.head); @@ -881,6 +890,8 @@ static int pxa_irda_remove(struct platform_device *_dev) if (dev) { struct pxa_irda *si = netdev_priv(dev); unregister_netdev(dev); + if (si->pdata->shutdown) + si->pdata->shutdown(si->dev); kfree(si->tx_buff.head); kfree(si->rx_buff.head); clk_put(si->fir_clk); diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index e571c72e675..e8d94fafc28 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -182,15 +182,18 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, struct mempolicy *oldpol; cpumask_t oldmask = current->cpus_allowed; int node = pcibus_to_node(dev->bus); - if (node >= 0 && node_online(node)) - set_cpus_allowed(current, node_to_cpumask(node)); + + if (node >= 0) { + node_to_cpumask_ptr(nodecpumask, node); + set_cpus_allowed_ptr(current, nodecpumask); + } /* And set default memory allocation policy */ oldpol = current->mempolicy; current->mempolicy = NULL; /* fall back to system default policy */ #endif error = drv->probe(dev, id); #ifdef CONFIG_NUMA - set_cpus_allowed(current, oldmask); + set_cpus_allowed_ptr(current, &oldmask); current->mempolicy = oldpol; #endif return error; diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 8dcf1458aa2..8d9d648daeb 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -73,8 +73,23 @@ static ssize_t local_cpus_show(struct device *dev, mask = pcibus_to_cpumask(to_pci_dev(dev)->bus); len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask); - strcat(buf,"\n"); - return 1+len; + buf[len++] = '\n'; + buf[len] = '\0'; + return len; +} + + +static ssize_t local_cpulist_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + cpumask_t mask; + int len; + + mask = pcibus_to_cpumask(to_pci_dev(dev)->bus); + len = cpulist_scnprintf(buf, PAGE_SIZE-2, mask); + buf[len++] = '\n'; + buf[len] = '\0'; + return len; } /* show resources */ @@ -201,6 +216,7 @@ struct device_attribute pci_dev_attrs[] = { __ATTR_RO(class), __ATTR_RO(irq), __ATTR_RO(local_cpus), + __ATTR_RO(local_cpulist), __ATTR_RO(modalias), #ifdef CONFIG_NUMA __ATTR_RO(numa_node), diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 2db2e4bb0d1..4b3011a23ef 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -82,6 +82,7 @@ void pci_remove_legacy_files(struct pci_bus *bus) { return; } * PCI Bus Class Devices */ static ssize_t pci_bus_show_cpuaffinity(struct device *dev, + int type, struct device_attribute *attr, char *buf) { @@ -89,12 +90,30 @@ static ssize_t pci_bus_show_cpuaffinity(struct device *dev, cpumask_t cpumask; cpumask = pcibus_to_cpumask(to_pci_bus(dev)); - ret = cpumask_scnprintf(buf, PAGE_SIZE, cpumask); - if (ret < PAGE_SIZE) - buf[ret++] = '\n'; + ret = type? + cpulist_scnprintf(buf, PAGE_SIZE-2, cpumask): + cpumask_scnprintf(buf, PAGE_SIZE-2, cpumask); + buf[ret++] = '\n'; + buf[ret] = '\0'; return ret; } -DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL); + +static ssize_t inline pci_bus_show_cpumaskaffinity(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return pci_bus_show_cpuaffinity(dev, 0, attr, buf); +} + +static ssize_t inline pci_bus_show_cpulistaffinity(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return pci_bus_show_cpuaffinity(dev, 1, attr, buf); +} + +DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpumaskaffinity, NULL); +DEVICE_ATTR(cpulistaffinity, S_IRUGO, pci_bus_show_cpulistaffinity, NULL); /* * PCI Bus Class diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 8b22281b087..ed8c0690480 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -200,6 +200,7 @@ config PCMCIA_AU1X00 config PCMCIA_SA1100 tristate "SA1100 support" depends on ARM && ARCH_SA1100 && PCMCIA + depends on ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL || MACH_ARMCORE help Say Y here to include support for SA11x0-based PCMCIA or CF sockets, found on HP iPAQs, Yopy, and other StrongARM(R)/ diff --git a/drivers/pcmcia/pxa2xx_cm_x270.c b/drivers/pcmcia/pxa2xx_cm_x270.c index fbf2f3a6984..e7ab060ff11 100644 --- a/drivers/pcmcia/pxa2xx_cm_x270.c +++ b/drivers/pcmcia/pxa2xx_cm_x270.c @@ -20,6 +20,7 @@ #include <asm/hardware.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-gpio.h> #include <asm/arch/cm-x270.h> #include "soc_common.h" diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 9e9caa5d7f5..c594b34c676 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 <asm/rtc.h> #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 <lethal@linux-sh.org>, Jamie Lenehan <lenehan@twibble.org>"); +MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, " + "Jamie Lenehan <lenehan@twibble.org>, " + "Angelo Castello <angelo.castello@st.com>"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 16ba9ac7a56..5a375bf0ebf 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -166,15 +166,6 @@ #define SERIAL_IMX_MAJOR 204 #define MINOR_START 41 -#define NR_PORTS 2 - -#define IMX_ISR_PASS_LIMIT 256 - -/* - * This is the size of our serial port register set. - */ -#define UART_PORT_SIZE 0x100 - /* * This determines how often we check the modem status signals * for any change. They generally aren't connected to an IRQ @@ -358,66 +349,60 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) struct tty_struct *tty = sport->port.info->tty; unsigned long flags, temp; - rx = readl(sport->port.membase + URXD0); spin_lock_irqsave(&sport->port.lock,flags); - do { + while (readl(sport->port.membase + USR2) & USR2_RDR) { flg = TTY_NORMAL; sport->port.icount.rx++; + rx = readl(sport->port.membase + URXD0); + temp = readl(sport->port.membase + USR2); - if( temp & USR2_BRCD ) { + if (temp & USR2_BRCD) { writel(temp | USR2_BRCD, sport->port.membase + USR2); - if(uart_handle_break(&sport->port)) - goto ignore_char; + if (uart_handle_break(&sport->port)) + continue; } if (uart_handle_sysrq_char (&sport->port, (unsigned char)rx)) - goto ignore_char; + continue; + + if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) { + if (rx & URXD_PRERR) + sport->port.icount.parity++; + else if (rx & URXD_FRMERR) + sport->port.icount.frame++; + if (rx & URXD_OVRRUN) + sport->port.icount.overrun++; + + if (rx & sport->port.ignore_status_mask) { + if (++ignored > 100) + goto out; + continue; + } + + rx &= sport->port.read_status_mask; + + if (rx & URXD_PRERR) + flg = TTY_PARITY; + else if (rx & URXD_FRMERR) + flg = TTY_FRAME; + if (rx & URXD_OVRRUN) + flg = TTY_OVERRUN; - if( rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) - goto handle_error; +#ifdef SUPPORT_SYSRQ + sport->port.sysrq = 0; +#endif + } - error_return: tty_insert_flip_char(tty, rx, flg); - - ignore_char: - rx = readl(sport->port.membase + URXD0); - } while(rx & URXD_CHARRDY); + } out: spin_unlock_irqrestore(&sport->port.lock,flags); tty_flip_buffer_push(tty); return IRQ_HANDLED; - -handle_error: - if (rx & URXD_PRERR) - sport->port.icount.parity++; - else if (rx & URXD_FRMERR) - sport->port.icount.frame++; - if (rx & URXD_OVRRUN) - sport->port.icount.overrun++; - - if (rx & sport->port.ignore_status_mask) { - if (++ignored > 100) - goto out; - goto ignore_char; - } - - rx &= sport->port.read_status_mask; - - if (rx & URXD_PRERR) - flg = TTY_PARITY; - else if (rx & URXD_FRMERR) - flg = TTY_FRAME; - if (rx & URXD_OVRRUN) - flg = TTY_OVERRUN; - -#ifdef SUPPORT_SYSRQ - sport->port.sysrq = 0; -#endif - goto error_return; } /* @@ -546,7 +531,7 @@ static int imx_startup(struct uart_port *port) writel(USR1_RTSD, sport->port.membase + USR1); temp = readl(sport->port.membase + UCR1); - temp |= (UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); + temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; writel(temp, sport->port.membase + UCR1); temp = readl(sport->port.membase + UCR2); @@ -731,9 +716,11 @@ static const char *imx_type(struct uart_port *port) */ static void imx_release_port(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *mmres; - release_mem_region(sport->port.mapbase, UART_PORT_SIZE); + mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(mmres->start, mmres->end - mmres->start + 1); } /* @@ -741,10 +728,18 @@ static void imx_release_port(struct uart_port *port) */ static int imx_request_port(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *mmres; + void *ret; + + mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mmres) + return -ENODEV; + + ret = request_mem_region(mmres->start, mmres->end - mmres->start + 1, + "imx-uart"); - return request_mem_region(sport->port.mapbase, UART_PORT_SIZE, - "imx-uart") != NULL ? 0 : -EBUSY; + return ret ? 0 : -EBUSY; } /* @@ -815,7 +810,7 @@ static struct imx_port imx_ports[] = { .type = PORT_IMX, .iotype = UPIO_MEM, .membase = (void *)IMX_UART1_BASE, - .mapbase = IMX_UART1_BASE, /* FIXME */ + .mapbase = 0x00206000, .irq = UART1_MINT_RX, .uartclk = 16000000, .fifosize = 32, @@ -831,7 +826,7 @@ static struct imx_port imx_ports[] = { .type = PORT_IMX, .iotype = UPIO_MEM, .membase = (void *)IMX_UART2_BASE, - .mapbase = IMX_UART2_BASE, /* FIXME */ + .mapbase = 0x00207000, .irq = UART2_MINT_RX, .uartclk = 16000000, .fifosize = 32, diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index eff593080d4..c2ea5d4df44 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 01a9dd715f5..fa8700a968f 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 <linux/serial_core.h> #include <asm/io.h> - #include <asm/gpio.h> #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/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 46ee7f4c091..85074cb36f3 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1033,7 +1033,7 @@ MODULE_LICENSE ("GPL"); #define OF_PLATFORM_DRIVER ehci_hcd_ppc_of_driver #endif -#ifdef CONFIG_ARCH_ORION +#ifdef CONFIG_PLAT_ORION #include "ehci-orion.c" #define PLATFORM_DRIVER ehci_orion_driver #endif diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index e129981f139..d187d031374 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -11,15 +11,18 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <asm/arch/orion.h> +#include <linux/mbus.h> +#include <asm/plat-orion/ehci-orion.h> #define rdl(off) __raw_readl(hcd->regs + (off)) #define wrl(off, val) __raw_writel((val), hcd->regs + (off)) -#define USB_CAUSE 0x310 -#define USB_MASK 0x314 #define USB_CMD 0x140 #define USB_MODE 0x1a8 +#define USB_CAUSE 0x310 +#define USB_MASK 0x314 +#define USB_WINDOW_CTRL(i) (0x320 + ((i) << 4)) +#define USB_WINDOW_BASE(i) (0x324 + ((i) << 4)) #define USB_IPG 0x360 #define USB_PHY_PWR_CTRL 0x400 #define USB_PHY_TX_CTRL 0x420 @@ -162,8 +165,30 @@ static const struct hc_driver ehci_orion_hc_driver = { .bus_resume = ehci_bus_resume, }; +static void __init +ehci_orion_conf_mbus_windows(struct usb_hcd *hcd, + struct mbus_dram_target_info *dram) +{ + int i; + + for (i = 0; i < 4; i++) { + wrl(USB_WINDOW_CTRL(i), 0); + wrl(USB_WINDOW_BASE(i), 0); + } + + for (i = 0; i < dram->num_cs; i++) { + struct mbus_dram_window *cs = dram->cs + i; + + wrl(USB_WINDOW_CTRL(i), ((cs->size - 1) & 0xffff0000) | + (cs->mbus_attr << 8) | + (dram->mbus_dram_target_id << 4) | 1); + wrl(USB_WINDOW_BASE(i), cs->base); + } +} + static int __init ehci_orion_drv_probe(struct platform_device *pdev) { + struct orion_ehci_data *pd = pdev->dev.platform_data; struct resource *res; struct usb_hcd *hcd; struct ehci_hcd *ehci; @@ -227,6 +252,12 @@ static int __init ehci_orion_drv_probe(struct platform_device *pdev) ehci->sbrn = 0x20; /* + * (Re-)program MBUS remapping windows if we are asked to. + */ + if (pd != NULL && pd->dram != NULL) + ehci_orion_conf_mbus_windows(hcd, pd->dram); + + /* * setup Orion USB controller */ orion_usb_setup(hcd); diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 97facb121c7..757651954e6 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -45,6 +45,7 @@ #include <asm/irq.h> #include <asm/div64.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-gpio.h> #include <asm/arch/bitfield.h> #include <asm/arch/pxafb.h> |