diff options
Diffstat (limited to 'arch/arm/mach-sa1100')
-rw-r--r-- | arch/arm/mach-sa1100/Kconfig | 2 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/assabet.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/clock.c | 132 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/collie.c | 30 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/collie_pm.c | 278 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/cpu-sa1100.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-sa1100/generic.c | 6 |
8 files changed, 450 insertions, 3 deletions
diff --git a/arch/arm/mach-sa1100/Kconfig b/arch/arm/mach-sa1100/Kconfig index 6923316b3d0..cd67ab1b217 100644 --- a/arch/arm/mach-sa1100/Kconfig +++ b/arch/arm/mach-sa1100/Kconfig @@ -111,7 +111,7 @@ config SA1100_LART bool "LART" help Say Y here if you are using the Linux Advanced Radio Terminal - (also known as the LART). See <http://www.lart.tudelft.nl/> for + (also known as the LART). See <http://www.lartmaker.nl/> for information on the LART. config SA1100_PLEB diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile index e4a4a3e8aa8..e27f15042a2 100644 --- a/arch/arm/mach-sa1100/Makefile +++ b/arch/arm/mach-sa1100/Makefile @@ -3,7 +3,7 @@ # # Common support -obj-y := generic.o irq.o dma.o time.o +obj-y := clock.o generic.o irq.o dma.o time.o #nmi-oopser.o obj-m := obj-n := obj- := diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index a599bb0d4ab..c58f12ba7a9 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -26,6 +26,7 @@ #include <asm/irq.h> #include <asm/setup.h> #include <asm/page.h> +#include <asm/pgtable-hwdef.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> diff --git a/arch/arm/mach-sa1100/clock.c b/arch/arm/mach-sa1100/clock.c new file mode 100644 index 00000000000..b1e8fd766c1 --- /dev/null +++ b/arch/arm/mach-sa1100/clock.c @@ -0,0 +1,132 @@ +/* + * linux/arch/arm/mach-sa1100/clock.c + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/string.h> +#include <linux/clk.h> +#include <linux/spinlock.h> + +#include <asm/hardware.h> +#include <asm/semaphore.h> + +struct clk { + struct list_head node; + unsigned long rate; + struct module *owner; + const char *name; + unsigned int enabled; + void (*enable)(void); + void (*disable)(void); +}; + +static LIST_HEAD(clocks); +static DECLARE_MUTEX(clocks_sem); +static DEFINE_SPINLOCK(clocks_lock); + +struct clk *clk_get(struct device *dev, const char *id) +{ + struct clk *p, *clk = ERR_PTR(-ENOENT); + + down(&clocks_sem); + list_for_each_entry(p, &clocks, node) { + if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { + clk = p; + break; + } + } + up(&clocks_sem); + + return clk; +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ + module_put(clk->owner); +} +EXPORT_SYMBOL(clk_put); + +int clk_enable(struct clk *clk) +{ + unsigned long flags; + + spin_lock_irqsave(&clocks_lock, flags); + if (clk->enabled++ == 0) + clk->enable(); + spin_unlock_irqrestore(&clocks_lock, flags); + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ + unsigned long flags; + + WARN_ON(clk->enabled == 0); + + spin_lock_irqsave(&clocks_lock, flags); + if (--clk->enabled == 0) + clk->disable(); + spin_unlock_irqrestore(&clocks_lock, flags); +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + return clk->rate; +} +EXPORT_SYMBOL(clk_get_rate); + + +static void clk_gpio27_enable(void) +{ + /* + * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: + * (SA-1110 Developer's Manual, section 9.1.2.1) + */ + GAFR |= GPIO_32_768kHz; + GPDR |= GPIO_32_768kHz; + TUCR = TUCR_3_6864MHz; +} + +static void clk_gpio27_disable(void) +{ + TUCR = 0; + GPDR &= ~GPIO_32_768kHz; + GAFR &= ~GPIO_32_768kHz; +} + +static struct clk clk_gpio27 = { + .name = "GPIO27_CLK", + .rate = 3686400, + .enable = clk_gpio27_enable, + .disable = clk_gpio27_disable, +}; + +int clk_register(struct clk *clk) +{ + down(&clocks_sem); + list_add(&clk->node, &clocks); + up(&clocks_sem); + return 0; +} +EXPORT_SYMBOL(clk_register); + +void clk_unregister(struct clk *clk) +{ + down(&clocks_sem); + list_del(&clk->node); + up(&clocks_sem); +} +EXPORT_SYMBOL(clk_unregister); + +static int __init clk_init(void) +{ + clk_register(&clk_gpio27); + return 0; +} +arch_initcall(clk_init); diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index 6888816a193..10245408247 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c @@ -40,6 +40,7 @@ #include <asm/hardware/scoop.h> #include <asm/mach/sharpsl_param.h> #include <asm/hardware/locomo.h> +#include <asm/arch/mcp.h> #include "generic.h" @@ -66,6 +67,32 @@ struct platform_device colliescoop_device = { .resource = collie_scoop_resources, }; +static struct scoop_pcmcia_dev collie_pcmcia_scoop[] = { +{ + .dev = &colliescoop_device.dev, + .irq = COLLIE_IRQ_GPIO_CF_IRQ, + .cd_irq = COLLIE_IRQ_GPIO_CF_CD, + .cd_irq_str = "PCMCIA0 CD", +}, +}; + +static struct scoop_pcmcia_config collie_pcmcia_config = { + .devs = &collie_pcmcia_scoop[0], + .num_devs = 1, +}; + + +static struct mcp_plat_data collie_mcp_data = { + .mccr0 = MCCR0_ADM, + .sclk_rate = 11981000, +}; + + +static struct sa1100_port_fns collie_port_fns __initdata = { + .set_mctrl = collie_uart_set_mctrl, + .get_mctrl = collie_uart_get_mctrl, +}; + static struct resource locomo_resources[] = { [0] = { @@ -159,6 +186,8 @@ static void __init collie_init(void) GPDR |= GPIO_32_768kHz; TUCR = TUCR_32_768kHz; + platform_scoop_config = &collie_pcmcia_config; + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); if (ret) { printk(KERN_WARNING "collie: Unable to register LoCoMo device\n"); @@ -166,6 +195,7 @@ static void __init collie_init(void) sa11x0_set_flash_data(&collie_flash_data, collie_flash_resources, ARRAY_SIZE(collie_flash_resources)); + sa11x0_set_mcp_data(&collie_mcp_data); sharpsl_save_param(); } diff --git a/arch/arm/mach-sa1100/collie_pm.c b/arch/arm/mach-sa1100/collie_pm.c new file mode 100644 index 00000000000..696d7d29c8a --- /dev/null +++ b/arch/arm/mach-sa1100/collie_pm.c @@ -0,0 +1,278 @@ +/* + * Based on spitz_pm.c and sharp code. + * + * Copyright (C) 2001 SHARP + * Copyright 2005 Pavel Machek <pavel@suse.cz> + * + * Distribute under GPLv2. + * + * Li-ion batteries are angry beasts, and they like to explode. This driver is not finished, + * and sometimes charges them when it should not. If it makes angry lithium to come your way... + * ...well, you have been warned. + */ + +#include <linux/module.h> +#include <linux/stat.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/platform_device.h> + +#include <asm/irq.h> +#include <asm/mach-types.h> +#include <asm/hardware.h> +#include <asm/hardware/scoop.h> +#include <asm/dma.h> +#include <asm/arch/collie.h> +#include <asm/mach/sharpsl_param.h> +#include <asm/hardware/sharpsl_pm.h> + +#include "../drivers/mfd/ucb1x00.h" + +static struct ucb1x00 *ucb; +static int ad_revise; + +#define ADCtoPower(x) ((330 * x * 2) / 1024) + +static void collie_charger_init(void) +{ + int err; + + if (sharpsl_param.adadj != -1) { + ad_revise = sharpsl_param.adadj; + } + + /* Register interrupt handler. */ + if ((err = request_irq(COLLIE_IRQ_GPIO_AC_IN, sharpsl_ac_isr, SA_INTERRUPT, + "ACIN", sharpsl_ac_isr))) { + printk("Could not get irq %d.\n", COLLIE_IRQ_GPIO_AC_IN); + return; + } + if ((err = request_irq(COLLIE_IRQ_GPIO_CO, sharpsl_chrg_full_isr, SA_INTERRUPT, + "CO", sharpsl_chrg_full_isr))) { + free_irq(COLLIE_IRQ_GPIO_AC_IN, sharpsl_ac_isr); + printk("Could not get irq %d.\n", COLLIE_IRQ_GPIO_CO); + return; + } + + ucb1x00_io_set_dir(ucb, 0, COLLIE_TC35143_GPIO_MBAT_ON | COLLIE_TC35143_GPIO_TMP_ON | + COLLIE_TC35143_GPIO_BBAT_ON); + return; +} + +static void collie_measure_temp(int on) +{ + if (on) + ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0); + else + ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON); +} + +static void collie_charge(int on) +{ + if (on) { + printk("Should start charger\n"); + } else { + printk("Should stop charger\n"); + } +#ifdef I_AM_SURE + + /* Zaurus seems to contain LTC1731 ; it should know when to + * stop charging itself, so setting charge on should be + * relatively harmless (as long as it is not done too often). + */ +#define CF_BUF_CTRL_BASE 0xF0800000 +#define SCOOP_REG(adr) (*(volatile unsigned short*)(CF_BUF_CTRL_BASE+(adr))) +#define SCOOP_REG_GPWR SCOOP_REG(SCOOP_GPWR) + + if (on) { + set_scoop_gpio(&colliescoop_device.dev, COLLIE_SCP_CHARGE_ON); + } else { + reset_scoop_gpio(&colliescoop_device.dev, COLLIE_SCP_CHARGE_ON); + } +#endif +} + +static void collie_discharge(int on) +{ +} + +static void collie_discharge1(int on) +{ +} + +static void collie_presuspend(void) +{ +} + +static void collie_postsuspend(void) +{ +} + +static int collie_should_wakeup(unsigned int resume_on_alarm) +{ + return 0; +} + +static unsigned long collie_charger_wakeup(void) +{ + return 0; +} + +int collie_read_backup_battery(void) +{ + int voltage; + + ucb1x00_adc_enable(ucb); + + /* Gives 75..130 */ + ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_BBAT_ON, 0); + voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD1, UCB_SYNC); + + ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_BBAT_ON); + ucb1x00_adc_disable(ucb); + + printk("Backup battery = %d(%d)\n", ADCtoPower(voltage), voltage); + + return ADCtoPower(voltage); +} + +int collie_read_main_battery(void) +{ + int voltage, voltage_rev, voltage_volts; + + ucb1x00_adc_enable(ucb); + ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_BBAT_ON); + ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_MBAT_ON, 0); + /* gives values 160..255 with battery removed... and + 145..255 with battery inserted. (on AC), goes as low as + 80 on DC. */ + voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD1, UCB_SYNC); + + ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_MBAT_ON); + ucb1x00_adc_disable(ucb); + + voltage_rev = voltage + ((ad_revise * voltage) / 652); + voltage_volts = ADCtoPower(voltage_rev); + + printk("Main battery = %d(%d)\n", voltage_volts, voltage); + + if (voltage != -1) + return voltage_volts; + else + return voltage; +} + +int collie_read_temp(void) +{ + int voltage; + + /* According to Sharp, temp must be > 973, main battery must be < 465, + FIXME: sharpsl_pm.c has both conditions negated? FIXME: values + are way out of range? */ + + ucb1x00_adc_enable(ucb); + ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0); + /* >1010 = battery removed, 460 = 22C ?, higer = lower temp ? */ + voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD0, UCB_SYNC); + ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON); + ucb1x00_adc_disable(ucb); + + printk("Battery temp = %d\n", voltage); + return voltage; +} + +static unsigned long read_devdata(int which) +{ + switch (which) { + case SHARPSL_BATT_VOLT: + return collie_read_main_battery(); + case SHARPSL_BATT_TEMP: + return collie_read_temp(); + case SHARPSL_ACIN_VOLT: + return 0x1; + case SHARPSL_STATUS_ACIN: { + int ret = GPLR & COLLIE_GPIO_AC_IN; + printk("AC status = %d\n", ret); + return ret; + } + case SHARPSL_STATUS_FATAL: { + int ret = GPLR & COLLIE_GPIO_MAIN_BAT_LOW; + printk("Fatal bat = %d\n", ret); + return ret; + } + default: + return ~0; + } +} + +struct battery_thresh collie_battery_levels[] = { + { 368, 100}, + { 358, 25}, + { 356, 5}, + { 0, 0}, +}; + +struct sharpsl_charger_machinfo collie_pm_machinfo = { + .init = collie_charger_init, + .read_devdata = read_devdata, + .discharge = collie_discharge, + .discharge1 = collie_discharge1, + .charge = collie_charge, + .measure_temp = collie_measure_temp, + .presuspend = collie_presuspend, + .postsuspend = collie_postsuspend, + .charger_wakeup = collie_charger_wakeup, + .should_wakeup = collie_should_wakeup, + .bat_levels = 3, + .bat_levels_noac = collie_battery_levels, + .bat_levels_acin = collie_battery_levels, + .status_high_acin = 368, + .status_low_acin = 358, + .status_high_noac = 368, + .status_low_noac = 358, +}; + +static int __init collie_pm_ucb_add(struct ucb1x00_dev *pdev) +{ + sharpsl_pm.machinfo = &collie_pm_machinfo; + ucb = pdev->ucb; + return 0; +} + +static struct ucb1x00_driver collie_pm_ucb_driver = { + .add = collie_pm_ucb_add, +}; + +static struct platform_device *collie_pm_device; + +static int __init collie_pm_init(void) +{ + int ret; + + collie_pm_device = platform_device_alloc("sharpsl-pm", -1); + if (!collie_pm_device) + return -ENOMEM; + + collie_pm_device->dev.platform_data = &collie_pm_machinfo; + ret = platform_device_add(collie_pm_device); + + if (ret) + platform_device_put(collie_pm_device); + + if (!ret) + ret = ucb1x00_register_driver(&collie_pm_ucb_driver); + + return ret; +} + +static void __exit collie_pm_exit(void) +{ + ucb1x00_unregister_driver(&collie_pm_ucb_driver); + platform_device_unregister(collie_pm_device); +} + +module_init(collie_pm_init); +module_exit(collie_pm_exit); diff --git a/arch/arm/mach-sa1100/cpu-sa1100.c b/arch/arm/mach-sa1100/cpu-sa1100.c index 6435b2e48ff..d68630b74d7 100644 --- a/arch/arm/mach-sa1100/cpu-sa1100.c +++ b/arch/arm/mach-sa1100/cpu-sa1100.c @@ -11,7 +11,7 @@ * linux-2.4.5-rmk1 * * This software has been developed while working on the LART - * computing board (http://www.lart.tudelft.nl/), which is + * computing board (http://www.lartmaker.nl/), which is * sponsored by the Mobile Multi-media Communications * (http://www.mmc.tudelft.nl/) and Ubiquitous Communications * (http://www.ubicom.tudelft.nl/) projects. diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 2abdc419e98..9ea71551fc0 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -324,6 +324,11 @@ void sa11x0_set_irda_data(struct irda_platform_data *irda) sa11x0ir_device.dev.platform_data = irda; } +static struct platform_device sa11x0rtc_device = { + .name = "sa1100-rtc", + .id = -1, +}; + static struct platform_device *sa11x0_devices[] __initdata = { &sa11x0udc_device, &sa11x0uart1_device, @@ -333,6 +338,7 @@ static struct platform_device *sa11x0_devices[] __initdata = { &sa11x0pcmcia_device, &sa11x0fb_device, &sa11x0mtd_device, + &sa11x0rtc_device, }; static int __init sa1100_init(void) |