diff options
44 files changed, 2016 insertions, 190 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index c3b215970f7b..1f02d96a5dbf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -636,7 +636,7 @@ P: Dirk Opfer M: dirk@opfer-online.de S: Maintained -ARM/PALMTX,PALMT5,PALMLD SUPPORT +ARM/PALMTX,PALMT5,PALMLD,PALMTE2 SUPPORT P: Marek Vasut M: marek.vasut@gmail.com W: http://hackndev.com @@ -3057,7 +3057,7 @@ S: Supported MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM P: Pierre Ossman -M: drzeus-mmc@drzeus.cx +M: pierre@ossman.eu L: linux-kernel@vger.kernel.org S: Maintained @@ -3939,7 +3939,7 @@ S: Maintained SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER P: Pierre Ossman -M: drzeus-sdhci@drzeus.cx +M: pierre@ossman.eu L: sdhci-devel@lists.ossman.eu S: Maintained @@ -4926,7 +4926,7 @@ S: Maintained W83L51xD SD/MMC CARD INTERFACE DRIVER P: Pierre Ossman -M: drzeus-wbsd@drzeus.cx +M: pierre@ossman.eu L: linux-kernel@vger.kernel.org S: Maintained diff --git a/arch/arm/configs/magician_defconfig b/arch/arm/configs/magician_defconfig index 82428c2f234c..f56837f69ca7 100644 --- a/arch/arm/configs/magician_defconfig +++ b/arch/arm/configs/magician_defconfig @@ -1183,7 +1183,11 @@ CONFIG_RTC_INTF_DEV=y CONFIG_RTC_DRV_SA1100=y # CONFIG_RTC_DRV_PXA is not set # CONFIG_DMADEVICES is not set -# CONFIG_REGULATOR is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +CONFIG_REGULATOR_BQ24022=y # CONFIG_UIO is not set # CONFIG_STAGING is not set diff --git a/arch/arm/include/asm/sizes.h b/arch/arm/include/asm/sizes.h index c10d1aa4b487..ada93a8fc2ef 100644 --- a/arch/arm/include/asm/sizes.h +++ b/arch/arm/include/asm/sizes.h @@ -32,6 +32,7 @@ #define SZ_4K 0x00001000 #define SZ_8K 0x00002000 #define SZ_16K 0x00004000 +#define SZ_32K 0x00008000 #define SZ_64K 0x00010000 #define SZ_128K 0x00020000 #define SZ_256K 0x00040000 diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h index 793fe7b25f36..e6afff849b85 100644 --- a/arch/arm/mach-at91/include/mach/board.h +++ b/arch/arm/mach-at91/include/mach/board.h @@ -87,7 +87,7 @@ extern void __init at91_add_device_eth(struct at91_eth_data *data); /* USB Host */ struct at91_usbh_data { u8 ports; /* number of ports on root hub */ - u8 vbus_pin[]; /* port power-control pin */ + u8 vbus_pin[2]; /* port power-control pin */ }; extern void __init at91_add_device_usbh(struct at91_usbh_data *data); diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c index dafe4f71d15f..336e51dc6127 100644 --- a/arch/arm/mach-omap1/clock.c +++ b/arch/arm/mach-omap1/clock.c @@ -590,27 +590,28 @@ static void omap1_init_ext_clk(struct clk * clk) static int omap1_clk_enable(struct clk *clk) { int ret = 0; + if (clk->usecount++ == 0) { - if (likely(clk->parent)) { + if (clk->parent) { ret = omap1_clk_enable(clk->parent); - - if (unlikely(ret != 0)) { - clk->usecount--; - return ret; - } + if (ret) + goto err; if (clk->flags & CLOCK_NO_IDLE_PARENT) omap1_clk_deny_idle(clk->parent); } ret = clk->ops->enable(clk); - - if (unlikely(ret != 0) && clk->parent) { - omap1_clk_disable(clk->parent); - clk->usecount--; + if (ret) { + if (clk->parent) + omap1_clk_disable(clk->parent); + goto err; } } + return ret; +err: + clk->usecount--; return ret; } diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index 96a2006cb597..3e66d9099eab 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -343,6 +343,15 @@ config ARCH_PXA_PALM bool "PXA based Palm PDAs" select HAVE_PWM +config MACH_PALMTE2 + bool "Palm Tungsten|E2" + default y + depends on ARCH_PXA_PALM + select PXA25x + help + Say Y here if you intend to run this kernel on a Palm Tungsten|E2 + handheld computer. + config MACH_PALMT5 bool "Palm Tungsten|T5" default y diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index c80e1bac4945..682dbf4e14b0 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -57,6 +57,7 @@ obj-$(CONFIG_MACH_E740) += e740.o obj-$(CONFIG_MACH_E750) += e750.o obj-$(CONFIG_MACH_E400) += e400.o obj-$(CONFIG_MACH_E800) += e800.o +obj-$(CONFIG_MACH_PALMTE2) += palmte2.o obj-$(CONFIG_MACH_PALMT5) += palmt5.o obj-$(CONFIG_MACH_PALMTX) += palmtx.o obj-$(CONFIG_MACH_PALMLD) += palmld.o diff --git a/arch/arm/mach-pxa/cm-x2xx.c b/arch/arm/mach-pxa/cm-x2xx.c index 117b5435f8d5..b50ef39eabfc 100644 --- a/arch/arm/mach-pxa/cm-x2xx.c +++ b/arch/arm/mach-pxa/cm-x2xx.c @@ -121,7 +121,7 @@ static inline void cmx2xx_init_dm9000(void) {} /* UCB1400 touchscreen controller */ #if defined(CONFIG_TOUCHSCREEN_UCB1400) || defined(CONFIG_TOUCHSCREEN_UCB1400_MODULE) static struct platform_device cmx2xx_ts_device = { - .name = "ucb1400_ts", + .name = "ucb1400_core", .id = -1, }; diff --git a/arch/arm/mach-pxa/colibri-pxa300.c b/arch/arm/mach-pxa/colibri-pxa300.c index 10c2eaf93230..7c9c34c19ae2 100644 --- a/arch/arm/mach-pxa/colibri-pxa300.c +++ b/arch/arm/mach-pxa/colibri-pxa300.c @@ -15,7 +15,7 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/gpio.h> -#include <net/ax88796.h> +#include <linux/interrupt.h> #include <asm/mach-types.h> #include <asm/sizes.h> @@ -32,12 +32,13 @@ #if defined(CONFIG_AX88796) #define COLIBRI_ETH_IRQ_GPIO mfp_to_gpio(GPIO26_GPIO) + /* * Asix AX88796 Ethernet */ static struct ax_plat_data colibri_asix_platdata = { - .flags = AXFLG_MAC_FROMDEV, - .wordlength = 2 + .flags = 0, /* defined later */ + .wordlength = 2, }; static struct resource colibri_asix_resource[] = { @@ -49,7 +50,7 @@ static struct resource colibri_asix_resource[] = { [1] = { .start = gpio_to_irq(COLIBRI_ETH_IRQ_GPIO), .end = gpio_to_irq(COLIBRI_ETH_IRQ_GPIO), - .flags = IORESOURCE_IRQ + .flags = IORESOURCE_IRQ | IRQF_TRIGGER_FALLING, } }; @@ -70,8 +71,8 @@ static mfp_cfg_t colibri_pxa300_eth_pin_config[] __initdata = { static void __init colibri_pxa300_init_eth(void) { + colibri_pxa3xx_init_eth(&colibri_asix_platdata); pxa3xx_mfp_config(ARRAY_AND_SIZE(colibri_pxa300_eth_pin_config)); - set_irq_type(gpio_to_irq(COLIBRI_ETH_IRQ_GPIO), IRQ_TYPE_EDGE_FALLING); platform_device_register(&asix_device); } #else diff --git a/arch/arm/mach-pxa/colibri-pxa320.c b/arch/arm/mach-pxa/colibri-pxa320.c index 55b74a7a6151..a18d37b3c5e6 100644 --- a/arch/arm/mach-pxa/colibri-pxa320.c +++ b/arch/arm/mach-pxa/colibri-pxa320.c @@ -15,7 +15,7 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/gpio.h> -#include <net/ax88796.h> +#include <linux/interrupt.h> #include <asm/mach-types.h> #include <asm/sizes.h> @@ -38,8 +38,8 @@ * Asix AX88796 Ethernet */ static struct ax_plat_data colibri_asix_platdata = { - .flags = AXFLG_MAC_FROMDEV, - .wordlength = 2 + .flags = 0, /* defined later */ + .wordlength = 2, }; static struct resource colibri_asix_resource[] = { @@ -51,7 +51,7 @@ static struct resource colibri_asix_resource[] = { [1] = { .start = gpio_to_irq(COLIBRI_ETH_IRQ_GPIO), .end = gpio_to_irq(COLIBRI_ETH_IRQ_GPIO), - .flags = IORESOURCE_IRQ + .flags = IORESOURCE_IRQ | IRQF_TRIGGER_FALLING, } }; @@ -72,8 +72,8 @@ static mfp_cfg_t colibri_pxa320_eth_pin_config[] __initdata = { static void __init colibri_pxa320_init_eth(void) { + colibri_pxa3xx_init_eth(&colibri_asix_platdata); pxa3xx_mfp_config(ARRAY_AND_SIZE(colibri_pxa320_eth_pin_config)); - set_irq_type(gpio_to_irq(COLIBRI_ETH_IRQ_GPIO), IRQ_TYPE_EDGE_FALLING); platform_device_register(&asix_device); } #else diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c index 12d0afc54aa5..ea34e34f8cd8 100644 --- a/arch/arm/mach-pxa/colibri-pxa3xx.c +++ b/arch/arm/mach-pxa/colibri-pxa3xx.c @@ -14,6 +14,7 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/gpio.h> +#include <linux/etherdevice.h> #include <asm/mach-types.h> #include <mach/hardware.h> #include <asm/sizes.h> @@ -28,6 +29,40 @@ #include "generic.h" #include "devices.h" +#if defined(CONFIG_AX88796) +#define ETHER_ADDR_LEN 6 +static u8 ether_mac_addr[ETHER_ADDR_LEN]; + +void __init colibri_pxa3xx_init_eth(struct ax_plat_data *plat_data) +{ + int i; + u64 serial = ((u64) system_serial_high << 32) | system_serial_low; + + /* + * If the bootloader passed in a serial boot tag, which contains a + * valid ethernet MAC, pass it to the interface. Toradex ships the + * modules with their own bootloader which provides a valid MAC + * this way. + */ + + for (i = 0; i < ETHER_ADDR_LEN; i++) { + ether_mac_addr[i] = serial & 0xff; + serial >>= 8; + } + + if (is_valid_ether_addr(ether_mac_addr)) { + plat_data->flags |= AXFLG_MAC_FROMPLATFORM; + plat_data->mac_addr = ether_mac_addr; + printk(KERN_INFO "%s(): taking MAC from serial boot tag\n", + __func__); + } else { + plat_data->flags |= AXFLG_MAC_FROMDEV; + printk(KERN_INFO "%s(): no valid serial boot tag found, " + "taking MAC from device\n", __func__); + } +} +#endif + #if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE) static int mmc_detect_pin; diff --git a/arch/arm/mach-pxa/csb701.c b/arch/arm/mach-pxa/csb701.c index 4a2a2952c374..5a221a49ea4d 100644 --- a/arch/arm/mach-pxa/csb701.c +++ b/arch/arm/mach-pxa/csb701.c @@ -5,6 +5,8 @@ #include <linux/input.h> #include <linux/leds.h> +#include <asm/mach-types.h> + static struct gpio_keys_button csb701_buttons[] = { { .code = 0x7, @@ -54,6 +56,9 @@ static struct platform_device *devices[] __initdata = { static int __init csb701_init(void) { + if (!machine_is_csb726()) + return -ENODEV; + return platform_add_devices(devices, ARRAY_SIZE(devices)); } diff --git a/arch/arm/mach-pxa/e740.c b/arch/arm/mach-pxa/e740.c index 07500a04fd8c..a36fc17f671d 100644 --- a/arch/arm/mach-pxa/e740.c +++ b/arch/arm/mach-pxa/e740.c @@ -29,6 +29,7 @@ #include <mach/udc.h> #include <mach/irda.h> #include <mach/irqs.h> +#include <mach/audio.h> #include "generic.h" #include "eseries.h" @@ -197,6 +198,7 @@ static void __init e740_init(void) eseries_get_tmio_gpios(); platform_add_devices(devices, ARRAY_SIZE(devices)); pxa_set_udc_info(&e7xx_udc_mach_info); + pxa_set_ac97_info(NULL); e7xx_irda_init(); pxa_set_ficp_info(&e7xx_ficp_platform_data); } diff --git a/arch/arm/mach-pxa/e750.c b/arch/arm/mach-pxa/e750.c index 6126c04e02bc..1d00110590e5 100644 --- a/arch/arm/mach-pxa/e750.c +++ b/arch/arm/mach-pxa/e750.c @@ -28,6 +28,7 @@ #include <mach/udc.h> #include <mach/irda.h> #include <mach/irqs.h> +#include <mach/audio.h> #include "generic.h" #include "eseries.h" @@ -198,6 +199,7 @@ static void __init e750_init(void) eseries_get_tmio_gpios(); platform_add_devices(devices, ARRAY_SIZE(devices)); pxa_set_udc_info(&e7xx_udc_mach_info); + pxa_set_ac97_info(NULL); e7xx_irda_init(); pxa_set_ficp_info(&e7xx_ficp_platform_data); } diff --git a/arch/arm/mach-pxa/e800.c b/arch/arm/mach-pxa/e800.c index 74ab09812a72..9866c7b9e784 100644 --- a/arch/arm/mach-pxa/e800.c +++ b/arch/arm/mach-pxa/e800.c @@ -27,6 +27,7 @@ #include <mach/eseries-gpio.h> #include <mach/udc.h> #include <mach/irqs.h> +#include <mach/audio.h> #include "generic.h" #include "eseries.h" @@ -199,6 +200,7 @@ static void __init e800_init(void) eseries_get_tmio_gpios(); platform_add_devices(devices, ARRAY_SIZE(devices)); pxa_set_udc_info(&e800_udc_mach_info); + pxa_set_ac97_info(NULL); } MACHINE_START(E800, "Toshiba e800") diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c index 920dfb8d36da..67611dadb44e 100644 --- a/arch/arm/mach-pxa/em-x270.c +++ b/arch/arm/mach-pxa/em-x270.c @@ -25,8 +25,10 @@ #include <linux/regulator/machine.h> #include <linux/spi/spi.h> #include <linux/spi/tdo24m.h> +#include <linux/spi/libertas_spi.h> #include <linux/power_supply.h> #include <linux/apm-emulation.h> +#include <linux/delay.h> #include <media/soc_camera.h> @@ -62,6 +64,8 @@ #define GPIO93_CAM_RESET (93) #define GPIO41_ETHIRQ (41) #define EM_X270_ETHIRQ IRQ_GPIO(GPIO41_ETHIRQ) +#define GPIO115_WLAN_PWEN (115) +#define GPIO19_WLAN_STRAP (19) static int mmc_cd; static int nand_rb; @@ -159,8 +163,8 @@ static unsigned long common_pin_config[] = { GPIO57_SSP1_TXD, /* SSP2 */ - GPIO19_SSP2_SCLK, - GPIO14_SSP2_SFRM, + GPIO19_GPIO, /* SSP2 clock is used as GPIO for Libertas pin-strap */ + GPIO14_GPIO, GPIO89_SSP2_TXD, GPIO88_SSP2_RXD, @@ -648,20 +652,86 @@ static struct tdo24m_platform_data em_x270_tdo24m_pdata = { .model = TDO35S, }; +static struct pxa2xx_spi_master em_x270_spi_2_info = { + .num_chipselect = 1, + .enable_dma = 1, +}; + +static struct pxa2xx_spi_chip em_x270_libertas_chip = { + .rx_threshold = 1, + .tx_threshold = 1, + .timeout = 1000, +}; + +static unsigned long em_x270_libertas_pin_config[] = { + /* SSP2 */ + GPIO19_SSP2_SCLK, + GPIO14_GPIO, + GPIO89_SSP2_TXD, + GPIO88_SSP2_RXD, +}; + +static int em_x270_libertas_setup(struct spi_device *spi) +{ + int err = gpio_request(GPIO115_WLAN_PWEN, "WLAN PWEN"); + if (err) + return err; + + gpio_direction_output(GPIO19_WLAN_STRAP, 1); + mdelay(100); + + pxa2xx_mfp_config(ARRAY_AND_SIZE(em_x270_libertas_pin_config)); + + gpio_direction_output(GPIO115_WLAN_PWEN, 0); + mdelay(100); + gpio_set_value(GPIO115_WLAN_PWEN, 1); + mdelay(100); + + spi->bits_per_word = 16; + spi_setup(spi); + + return 0; +} + +static int em_x270_libertas_teardown(struct spi_device *spi) +{ + gpio_set_value(GPIO115_WLAN_PWEN, 0); + gpio_free(GPIO115_WLAN_PWEN); + + return 0; +} + +struct libertas_spi_platform_data em_x270_libertas_pdata = { + .use_dummy_writes = 1, + .gpio_cs = 14, + .setup = em_x270_libertas_setup, + .teardown = em_x270_libertas_teardown, +}; + static struct spi_board_info em_x270_spi_devices[] __initdata = { { - .modalias = "tdo24m", - .max_speed_hz = 1000000, - .bus_num = 1, - .chip_select = 0, - .controller_data = &em_x270_tdo24m_chip, - .platform_data = &em_x270_tdo24m_pdata, + .modalias = "tdo24m", + .max_speed_hz = 1000000, + .bus_num = 1, + .chip_select = 0, + .controller_data = &em_x270_tdo24m_chip, + .platform_data = &em_x270_tdo24m_pdata, + }, + { + .modalias = "libertas_spi", + .max_speed_hz = 13000000, + .bus_num = 2, + .irq = IRQ_GPIO(116), + .chip_select = 0, + .controller_data = &em_x270_libertas_chip, + .platform_data = &em_x270_libertas_pdata, }, }; static void __init em_x270_init_spi(void) { pxa2xx_set_spi_info(1, &em_x270_spi_info); + pxa2xx_set_spi_info(2, &em_x270_spi_2_info); spi_register_board_info(ARRAY_AND_SIZE(em_x270_spi_devices)); } #else diff --git a/arch/arm/mach-pxa/include/mach/colibri.h b/arch/arm/mach-pxa/include/mach/colibri.h index 3f2a01d6a03c..90230c6f9925 100644 --- a/arch/arm/mach-pxa/include/mach/colibri.h +++ b/arch/arm/mach-pxa/include/mach/colibri.h @@ -1,5 +1,8 @@ #ifndef _COLIBRI_H_ #define _COLIBRI_H_ + +#include <net/ax88796.h> + /* * common settings for all modules */ @@ -16,6 +19,10 @@ extern void colibri_pxa3xx_init_lcd(int bl_pin); static inline void colibri_pxa3xx_init_lcd(int) {} #endif +#if defined(CONFIG_AX88796) +extern void colibri_pxa3xx_init_eth(struct ax_plat_data *plat_data); +#endif + /* physical memory regions */ #define COLIBRI_SDRAM_BASE 0xa0000000 /* SDRAM region */ diff --git a/arch/arm/mach-pxa/include/mach/magician.h b/arch/arm/mach-pxa/include/mach/magician.h index 82a399f3f9f2..20ef37d4a9a7 100644 --- a/arch/arm/mach-pxa/include/mach/magician.h +++ b/arch/arm/mach-pxa/include/mach/magician.h @@ -27,7 +27,7 @@ #define GPIO22_MAGICIAN_VIBRA_EN 22 #define GPIO26_MAGICIAN_GSM_POWER 26 #define GPIO27_MAGICIAN_USBC_PUEN 27 -#define GPIO30_MAGICIAN_nCHARGE_EN 30 +#define GPIO30_MAGICIAN_BQ24022_nCHARGE_EN 30 #define GPIO37_MAGICIAN_KEY_HANGUP 37 #define GPIO38_MAGICIAN_KEY_CONTACTS 38 #define GPIO40_MAGICIAN_GSM_OUT2 40 @@ -98,7 +98,7 @@ #define EGPIO_MAGICIAN_UNKNOWN_WAVEDEV_DLL MAGICIAN_EGPIO(2, 2) #define EGPIO_MAGICIAN_FLASH_VPP MAGICIAN_EGPIO(2, 3) #define EGPIO_MAGICIAN_BL_POWER2 MAGICIAN_EGPIO(2, 4) -#define EGPIO_MAGICIAN_CHARGE_EN MAGICIAN_EGPIO(2, 5) +#define EGPIO_MAGICIAN_BQ24022_ISET2 MAGICIAN_EGPIO(2, 5) #define EGPIO_MAGICIAN_GSM_POWER MAGICIAN_EGPIO(2, 7) /* input */ diff --git a/arch/arm/mach-pxa/include/mach/palmld.h b/arch/arm/mach-pxa/include/mach/palmld.h index 7c295a48d784..fb13c82ad6dc 100644 --- a/arch/arm/mach-pxa/include/mach/palmld.h +++ b/arch/arm/mach-pxa/include/mach/palmld.h @@ -87,6 +87,7 @@ #define PALMLD_IDE_SIZE 0x00100000 #define PALMLD_PHYS_IO_START 0x40000000 +#define PALMLD_STR_BASE 0xa0200000 /* BATTERY */ #define PALMLD_BAT_MAX_VOLTAGE 4000 /* 4.00V maximum voltage */ diff --git a/arch/arm/mach-pxa/include/mach/palmt5.h b/arch/arm/mach-pxa/include/mach/palmt5.h index 94db2881f048..052bfe788ada 100644 --- a/arch/arm/mach-pxa/include/mach/palmt5.h +++ b/arch/arm/mach-pxa/include/mach/palmt5.h @@ -59,6 +59,7 @@ /* Various addresses */ #define PALMT5_PHYS_RAM_START 0xa0000000 #define PALMT5_PHYS_IO_START 0x40000000 +#define PALMT5_STR_BASE 0xa0200000 /* TOUCHSCREEN */ #define AC97_LINK_FRAME 21 diff --git a/arch/arm/mach-pxa/include/mach/palmte2.h b/arch/arm/mach-pxa/include/mach/palmte2.h new file mode 100644 index 000000000000..12361341f9d8 --- /dev/null +++ b/arch/arm/mach-pxa/include/mach/palmte2.h @@ -0,0 +1,68 @@ +/* + * GPIOs and interrupts for Palm Tungsten|E2 Handheld Computer + * + * Author: + * Carlos Eduardo Medaglia Dyonisio <cadu@nerdfeliz.com> + * + * 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. + * + */ + +#ifndef _INCLUDE_PALMTE2_H_ +#define _INCLUDE_PALMTE2_H_ + +/** HERE ARE GPIOs **/ + +/* GPIOs */ +#define GPIO_NR_PALMTE2_POWER_DETECT 9 +#define GPIO_NR_PALMTE2_HOTSYNC_BUTTON_N 4 +#define GPIO_NR_PALMTE2_EARPHONE_DETECT 15 + +/* SD/MMC */ +#define GPIO_NR_PALMTE2_SD_DETECT_N 10 +#define GPIO_NR_PALMTE2_SD_POWER 55 +#define GPIO_NR_PALMTE2_SD_READONLY 51 + +/* IRDA - disable GPIO connected to SD pin of tranceiver (TFBS4710?) ? */ +#define GPIO_NR_PALMTE2_IR_DISABLE 48 + +/* USB */ +#define GPIO_NR_PALMTE2_USB_DETECT_N 35 +#define GPIO_NR_PALMTE2_USB_PULLUP 53 + +/* LCD/BACKLIGHT */ +#define GPIO_NR_PALMTE2_BL_POWER 56 +#define GPIO_NR_PALMTE2_LCD_POWER 37 + +/* KEYS */ +#define GPIO_NR_PALMTE2_KEY_NOTES 5 +#define GPIO_NR_PALMTE2_KEY_TASKS 7 +#define GPIO_NR_PALMTE2_KEY_CALENDAR 11 +#define GPIO_NR_PALMTE2_KEY_CONTACTS 13 +#define GPIO_NR_PALMTE2_KEY_CENTER 14 +#define GPIO_NR_PALMTE2_KEY_LEFT 19 +#define GPIO_NR_PALMTE2_KEY_RIGHT 20 +#define GPIO_NR_PALMTE2_KEY_DOWN 21 +#define GPIO_NR_PALMTE2_KEY_UP 22 + +/** HERE ARE INIT VALUES **/ + +/* BACKLIGHT */ +#define PALMTE2_MAX_INTENSITY 0xFE +#define PALMTE2_DEFAULT_INTENSITY 0x7E +#define PALMTE2_LIMIT_MASK 0x7F +#define PALMTE2_PRESCALER 0x3F +#define PALMTE2_PERIOD_NS 3500 + +/* BATTERY */ +#define PALMTE2_BAT_MAX_VOLTAGE 4000 /* 4.00v current voltage */ +#define PALMTE2_BAT_MIN_VOLTAGE 3550 /* 3.55v critical voltage */ +#define PALMTE2_BAT_MAX_CURRENT 0 /* unknokn */ +#define PALMTE2_BAT_MIN_CURRENT 0 /* unknown */ +#define PALMTE2_BAT_MAX_CHARGE 1 /* unknown */ +#define PALMTE2_BAT_MIN_CHARGE 1 /* unknown */ +#define PALMTE2_MAX_LIFE_MINS 360 /* on-life in minutes */ + +#endif diff --git a/arch/arm/mach-pxa/include/mach/palmtx.h b/arch/arm/mach-pxa/include/mach/palmtx.h index 1e8bccbda510..9f7d62fb4cbb 100644 --- a/arch/arm/mach-pxa/include/mach/palmtx.h +++ b/arch/arm/mach-pxa/include/mach/palmtx.h @@ -78,6 +78,8 @@ #define PALMTX_PHYS_RAM_START 0xa0000000 #define PALMTX_PHYS_IO_START 0x40000000 +#define PALMTX_STR_BASE 0xa0200000 + #define PALMTX_PHYS_FLASH_START PXA_CS0_PHYS /* ChipSelect 0 */ #define PALMTX_PHYS_NAND_START PXA_CS1_PHYS /* ChipSelect 1 */ diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c index deeea1c2782b..c899bbd94dc0 100644 --- a/arch/arm/mach-pxa/magician.c +++ b/arch/arm/mach-pxa/magician.c @@ -25,6 +25,8 @@ #include <linux/mtd/physmap.h> #include <linux/pda_power.h> #include <linux/pwm_backlight.h> +#include <linux/regulator/bq24022.h> +#include <linux/regulator/machine.h> #include <linux/usb/gpio_vbus.h> #include <mach/hardware.h> @@ -552,33 +554,7 @@ static struct platform_device gpio_vbus = { static int power_supply_init(struct device *dev) { - int ret; - - ret = gpio_request(EGPIO_MAGICIAN_CABLE_STATE_AC, "CABLE_STATE_AC"); - if (ret) - goto err_cs_ac; - ret = gpio_request(EGPIO_MAGICIAN_CABLE_STATE_USB, "CABLE_STATE_USB"); - if (ret) - goto err_cs_usb; - ret = gpio_request(EGPIO_MAGICIAN_CHARGE_EN, "CHARGE_EN"); - if (ret) - goto err_chg_en; - ret = gpio_request(GPIO30_MAGICIAN_nCHARGE_EN, "nCHARGE_EN"); - if (!ret) - ret = gpio_direction_output(GPIO30_MAGICIAN_nCHARGE_EN, 0); - if (ret) - goto err_nchg_en; - - return 0; - -err_nchg_en: - gpio_free(EGPIO_MAGICIAN_CHARGE_EN); -err_chg_en: - gpio_free(EGPIO_MAGICIAN_CABLE_STATE_USB); -err_cs_usb: - gpio_free(EGPIO_MAGICIAN_CABLE_STATE_AC); -err_cs_ac: - return ret; + return gpio_request(EGPIO_MAGICIAN_CABLE_STATE_AC, "CABLE_STATE_AC"); } static int magician_is_ac_online(void) @@ -586,22 +562,8 @@ static int magician_is_ac_online(void) return gpio_get_value(EGPIO_MAGICIAN_CABLE_STATE_AC); } -static int magician_is_usb_online(void) -{ - return gpio_get_value(EGPIO_MAGICIAN_CABLE_STATE_USB); -} - -static void magician_set_charge(int flags) -{ - gpio_set_value(GPIO30_MAGICIAN_nCHARGE_EN, !flags); - gpio_set_value(EGPIO_MAGICIAN_CHARGE_EN, flags); -} - static void power_supply_exit(struct device *dev) { - gpio_free(GPIO30_MAGICIAN_nCHARGE_EN); - gpio_free(EGPIO_MAGICIAN_CHARGE_EN); - gpio_free(EGPIO_MAGICIAN_CABLE_STATE_USB); gpio_free(EGPIO_MAGICIAN_CABLE_STATE_AC); } @@ -612,8 +574,6 @@ static char *magician_supplicants[] = { static struct pda_power_pdata power_supply_info = { .init = power_supply_init, .is_ac_online = magician_is_ac_online, - .is_usb_online = magician_is_usb_online, - .set_charge = magician_set_charge, .exit = power_supply_exit, .supplied_to = magician_supplicants, .num_supplicants = ARRAY_SIZE(magician_supplicants), @@ -646,6 +606,43 @@ static struct platform_device power_supply = { .num_resources = ARRAY_SIZE(power_supply_resources), }; +/* + * Battery charger + */ + +static struct regulator_consumer_supply bq24022_consumers[] = { + { + .dev = &gpio_vbus.dev, + .supply = "vbus_draw", + }, + { + .dev = &power_supply.dev, + .supply = "ac_draw", + }, +}; + +static struct regulator_init_data bq24022_init_data = { + .constraints = { + .max_uA = 500000, + .valid_ops_mask = REGULATOR_CHANGE_CURRENT, + }, + .num_consumer_supplies = ARRAY_SIZE(bq24022_consumers), + .consumer_supplies = bq24022_consumers, +}; + +static struct bq24022_mach_info bq24022_info = { + .gpio_nce = GPIO30_MAGICIAN_BQ24022_nCHARGE_EN, + .gpio_iset2 = EGPIO_MAGICIAN_BQ24022_ISET2, + .init_data = &bq24022_init_data, +}; + +static struct platform_device bq24022 = { + .name = "bq24022", + .id = -1, + .dev = { + .platform_data = &bq24022_info, + }, +}; /* * MMC/SD @@ -756,6 +753,7 @@ static struct platform_device *devices[] __initdata = { &egpio, &backlight, &pasic3, + &bq24022, &gpio_vbus, &power_supply, &strataflash, diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c index 97c93a7a285c..9203b069b35c 100644 --- a/arch/arm/mach-pxa/mioa701.c +++ b/arch/arm/mach-pxa/mioa701.c @@ -50,6 +50,7 @@ #include <mach/pxa27x-udc.h> #include <mach/i2c.h> #include <mach/camera.h> +#include <mach/audio.h> #include <media/soc_camera.h> #include <mach/mioa701.h> @@ -763,8 +764,6 @@ MIO_PARENT_DEV(mioa701_backlight, "pwm-backlight", &pxa27x_device_pwm0.dev, &mioa701_backlight_data); MIO_SIMPLE_DEV(mioa701_led, "leds-gpio", &gpio_led_info) MIO_SIMPLE_DEV(pxa2xx_pcm, "pxa2xx-pcm", NULL) -MIO_SIMPLE_DEV(pxa2xx_ac97, "pxa2xx-ac97", NULL) -MIO_PARENT_DEV(mio_wm9713_codec, "wm9713-codec", &pxa2xx_ac97.dev, NULL) MIO_SIMPLE_DEV(mioa701_sound, "mioa701-wm9713", NULL) MIO_SIMPLE_DEV(mioa701_board, "mioa701-board", NULL) MIO_SIMPLE_DEV(gpio_vbus, "gpio-vbus", &gpio_vbus_data); @@ -774,8 +773,6 @@ static struct platform_device *devices[] __initdata = { &mioa701_backlight, &mioa701_led, &pxa2xx_pcm, - &pxa2xx_ac97, - &mio_wm9713_codec, &mioa701_sound, &power_dev, &strataflash, @@ -818,6 +815,7 @@ static void __init mioa701_machine_init(void) pxa_set_keypad_info(&mioa701_keypad_info); wm97xx_bat_set_pdata(&mioa701_battery_data); pxa_set_udc_info(&mioa701_udc_info); + pxa_set_ac97_info(NULL); pm_power_off = mioa701_poweroff; arm_pm_restart = mioa701_restart; platform_add_devices(devices, ARRAY_SIZE(devices)); diff --git a/arch/arm/mach-pxa/palmld.c b/arch/arm/mach-pxa/palmld.c index 8587477a9bb7..ecf5910e39d7 100644 --- a/arch/arm/mach-pxa/palmld.c +++ b/arch/arm/mach-pxa/palmld.c @@ -24,6 +24,7 @@ #include <linux/gpio.h> #include <linux/wm97xx_batt.h> #include <linux/power_supply.h> +#include <linux/sysdev.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> @@ -68,10 +69,10 @@ static unsigned long palmld_pin_config[] __initdata = { GPIO47_FICP_TXD, /* MATRIX KEYPAD */ - GPIO100_KP_MKIN_0, - GPIO101_KP_MKIN_1, - GPIO102_KP_MKIN_2, - GPIO97_KP_MKIN_3, + GPIO100_KP_MKIN_0 | WAKEUP_ON_LEVEL_HIGH, + GPIO101_KP_MKIN_1 | WAKEUP_ON_LEVEL_HIGH, + GPIO102_KP_MKIN_2 | WAKEUP_ON_LEVEL_HIGH, + GPIO97_KP_MKIN_3 | WAKEUP_ON_LEVEL_HIGH, GPIO103_KP_MKOUT_0, GPIO104_KP_MKOUT_1, GPIO105_KP_MKOUT_2, @@ -507,6 +508,33 @@ static struct pxafb_mach_info palmld_lcd_screen = { }; /****************************************************************************** + * Power management - standby + ******************************************************************************/ +#ifdef CONFIG_PM +static u32 *addr __initdata; +static u32 resume[3] __initdata = { + 0xe3a00101, /* mov r0, #0x40000000 */ + 0xe380060f, /* orr r0, r0, #0x00f00000 */ + 0xe590f008, /* ldr pc, [r0, #0x08] */ +}; + +static int __init palmld_pm_init(void) +{ + int i; + + /* this is where the bootloader jumps */ + addr = phys_to_virt(PALMLD_STR_BASE); + + for (i = 0; i < 3; i++) + addr[i] = resume[i]; + + return 0; +} + +device_initcall(palmld_pm_init); +#endif + +/****************************************************************************** * Machine init ******************************************************************************/ static struct platform_device *devices[] __initdata = { diff --git a/arch/arm/mach-pxa/palmt5.c b/arch/arm/mach-pxa/palmt5.c index 9521c7b33492..0680f1a575a3 100644 --- a/arch/arm/mach-pxa/palmt5.c +++ b/arch/arm/mach-pxa/palmt5.c @@ -75,10 +75,10 @@ static unsigned long palmt5_pin_config[] __initdata = { GPIO95_GPIO, /* usb power */ /* MATRIX KEYPAD */ - GPIO100_KP_MKIN_0, - GPIO101_KP_MKIN_1, - GPIO102_KP_MKIN_2, - GPIO97_KP_MKIN_3, + GPIO100_KP_MKIN_0 | WAKEUP_ON_LEVEL_HIGH, + GPIO101_KP_MKIN_1 | WAKEUP_ON_LEVEL_HIGH, + GPIO102_KP_MKIN_2 | WAKEUP_ON_LEVEL_HIGH, + GPIO97_KP_MKIN_3 | WAKEUP_ON_LEVEL_HIGH, GPIO103_KP_MKOUT_0, GPIO104_KP_MKOUT_1, GPIO105_KP_MKOUT_2, @@ -450,6 +450,33 @@ static struct pxafb_mach_info palmt5_lcd_screen = { }; /****************************************************************************** + * Power management - standby + ******************************************************************************/ +#ifdef CONFIG_PM +static u32 *addr __initdata; +static u32 resume[3] __initdata = { + 0xe3a00101, /* mov r0, #0x40000000 */ + 0xe380060f, /* orr r0, r0, #0x00f00000 */ + 0xe590f008, /* ldr pc, [r0, #0x08] */ +}; + +static int __init palmt5_pm_init(void) +{ + int i; + + /* this is where the bootloader jumps */ + addr = phys_to_virt(PALMT5_STR_BASE); + + for (i = 0; i < 3; i++) + addr[i] = resume[i]; + + return 0; +} + +device_initcall(palmt5_pm_init); +#endif + +/****************************************************************************** * Machine init ******************************************************************************/ static struct platform_device *devices[] __initdata = { diff --git a/arch/arm/mach-pxa/palmte2.c b/arch/arm/mach-pxa/palmte2.c new file mode 100644 index 000000000000..43fcf2e86887 --- /dev/null +++ b/arch/arm/mach-pxa/palmte2.c @@ -0,0 +1,466 @@ +/* + * Hardware definitions for Palm Tungsten|E2 + * + * Author: + * Carlos Eduardo Medaglia Dyonisio <cadu@nerdfeliz.com> + * + * Rewrite for mainline: + * Marek Vasut <marek.vasut@gmail.com> + * + * 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. + * + * (find more info at www.hackndev.com) + * + */ + +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/gpio_keys.h> +#include <linux/input.h> +#include <linux/pda_power.h> +#include <linux/pwm_backlight.h> +#include <linux/gpio.h> +#include <linux/wm97xx_batt.h> +#include <linux/power_supply.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <mach/audio.h> +#include <mach/palmte2.h> +#include <mach/mmc.h> +#include <mach/pxafb.h> +#include <mach/mfp-pxa25x.h> +#include <mach/irda.h> +#include <mach/udc.h> + +#include "generic.h" +#include "devices.h" + +/****************************************************************************** + * Pin configuration + ******************************************************************************/ +static unsigned long palmte2_pin_config[] __initdata = { + /* MMC */ + GPIO6_MMC_CLK, + GPIO8_MMC_CS0, + GPIO10_GPIO, /* SD detect */ + GPIO55_GPIO, /* SD power */ + GPIO51_GPIO, /* SD r/o switch */ + + /* AC97 */ + GPIO28_AC97_BITCLK, + GPIO29_AC97_SDATA_IN_0, + GPIO30_AC97_SDATA_OUT, + GPIO31_AC97_SYNC, + + /* PWM */ + GPIO16_PWM0_OUT, + + /* USB */ + GPIO15_GPIO, /* usb detect */ + GPIO53_GPIO, /* usb power */ + + /* IrDA */ + GPIO48_GPIO, /* ir disable */ + GPIO46_FICP_RXD, + GPIO47_FICP_TXD, + + /* LCD */ + GPIO58_LCD_LDD_0, + GPIO59_LCD_LDD_1, + GPIO60_LCD_LDD_2, + GPIO61_LCD_LDD_3, + GPIO62_LCD_LDD_4, + GPIO63_LCD_LDD_5, + GPIO64_LCD_LDD_6, + GPIO65_LCD_LDD_7, + GPIO66_LCD_LDD_8, + GPIO67_LCD_LDD_9, + GPIO68_LCD_LDD_10, + GPIO69_LCD_LDD_11, + GPIO70_LCD_LDD_12, + GPIO71_LCD_LDD_13, + GPIO72_LCD_LDD_14, + GPIO73_LCD_LDD_15, + GPIO74_LCD_FCLK, + GPIO75_LCD_LCLK, + GPIO76_LCD_PCLK, + GPIO77_LCD_BIAS, + + /* GPIO KEYS */ + GPIO5_GPIO, /* notes */ + GPIO7_GPIO, /* tasks */ + GPIO11_GPIO, /* calendar */ + GPIO13_GPIO, /* contacts */ + GPIO14_GPIO, /* center */ + GPIO19_GPIO, /* left */ + GPIO20_GPIO, /* right */ + GPIO21_GPIO, /* down */ + GPIO22_GPIO, /* up */ + + /* MISC */ + GPIO1_RST, /* reset */ + GPIO4_GPIO, /* Hotsync button */ + GPIO9_GPIO, /* power detect */ + GPIO37_GPIO, /* LCD power */ + GPIO56_GPIO, /* Backlight power */ +}; + +/****************************************************************************** + * SD/MMC card controller + ******************************************************************************/ +static int palmte2_mci_init(struct device *dev, + irq_handler_t palmte2_detect_int, void *data) +{ + int err = 0; + + /* Setup an interrupt for detecting card insert/remove events */ + err = gpio_request(GPIO_NR_PALMTE2_SD_DETECT_N, "SD IRQ"); + if (err) + goto err; + err = gpio_direction_input(GPIO_NR_PALMTE2_SD_DETECT_N); + if (err) + goto err2; + err = request_irq(gpio_to_irq(GPIO_NR_PALMTE2_SD_DETECT_N), + palmte2_detect_int, IRQF_DISABLED | IRQF_SAMPLE_RANDOM | + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "SD/MMC card detect", data); + if (err) { + printk(KERN_ERR "%s: cannot request SD/MMC card detect IRQ\n", + __func__); + goto err2; + } + + err = gpio_request(GPIO_NR_PALMTE2_SD_POWER, "SD_POWER"); + if (err) + goto err3; + err = gpio_direction_output(GPIO_NR_PALMTE2_SD_POWER, 0); + if (err) + goto err4; + + err = gpio_request(GPIO_NR_PALMTE2_SD_READONLY, "SD_READONLY"); + if (err) + goto err4; + err = gpio_direction_input(GPIO_NR_PALMTE2_SD_READONLY); + if (err) + goto err5; + + printk(KERN_DEBUG "%s: irq registered\n", __func__); + + return 0; + +err5: + gpio_free(GPIO_NR_PALMTE2_SD_READONLY); +err4: + gpio_free(GPIO_NR_PALMTE2_SD_POWER); +err3: + free_irq(gpio_to_irq(GPIO_NR_PALMTE2_SD_DETECT_N), data); +err2: + gpio_free(GPIO_NR_PALMTE2_SD_DETECT_N); +err: + return err; +} + +static void palmte2_mci_exit(struct device *dev, void *data) +{ + gpio_free(GPIO_NR_PALMTE2_SD_READONLY); + gpio_free(GPIO_NR_PALMTE2_SD_POWER); + free_irq(gpio_to_irq(GPIO_NR_PALMTE2_SD_DETECT_N), data); + gpio_free(GPIO_NR_PALMTE2_SD_DETECT_N); +} + +static void palmte2_mci_power(struct device *dev, unsigned int vdd) +{ + struct pxamci_platform_data *p_d = dev->platform_data; + gpio_set_value(GPIO_NR_PALMTE2_SD_POWER, p_d->ocr_mask & (1 << vdd)); +} + +static int palmte2_mci_get_ro(struct device *dev) +{ + return gpio_get_value(GPIO_NR_PALMTE2_SD_READONLY); +} + +static struct pxamci_platform_data palmte2_mci_platform_data = { + .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, + .setpower = palmte2_mci_power, + .get_ro = palmte2_mci_get_ro, + .init = palmte2_mci_init, + .exit = palmte2_mci_exit, +}; + +/****************************************************************************** + * GPIO keys + ******************************************************************************/ +static struct gpio_keys_button palmte2_pxa_buttons[] = { + {KEY_F1, GPIO_NR_PALMTE2_KEY_CONTACTS, 1, "Contacts" }, + {KEY_F2, GPIO_NR_PALMTE2_KEY_CALENDAR, 1, "Calendar" }, + {KEY_F3, GPIO_NR_PALMTE2_KEY_TASKS, 1, "Tasks" }, + {KEY_F4, GPIO_NR_PALMTE2_KEY_NOTES, 1, "Notes" }, + {KEY_ENTER, GPIO_NR_PALMTE2_KEY_CENTER, 1, "Center" }, + {KEY_LEFT, GPIO_NR_PALMTE2_KEY_LEFT, 1, "Left" }, + {KEY_RIGHT, GPIO_NR_PALMTE2_KEY_RIGHT, 1, "Right" }, + {KEY_DOWN, GPIO_NR_PALMTE2_KEY_DOWN, 1, "Down" }, + {KEY_UP, GPIO_NR_PALMTE2_KEY_UP, 1, "Up" }, +}; + +static struct gpio_keys_platform_data palmte2_pxa_keys_data = { + .buttons = palmte2_pxa_buttons, + .nbuttons = ARRAY_SIZE(palmte2_pxa_buttons), +}; + +static struct platform_device palmte2_pxa_keys = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &palmte2_pxa_keys_data, + }, +}; + +/****************************************************************************** + * Backlight + ******************************************************************************/ +static int palmte2_backlight_init(struct device *dev) +{ + int ret; + + ret = gpio_request(GPIO_NR_PALMTE2_BL_POWER, "BL POWER"); + if (ret) + goto err; + ret = gpio_direction_output(GPIO_NR_PALMTE2_BL_POWER, 0); + if (ret) + goto err2; + ret = gpio_request(GPIO_NR_PALMTE2_LCD_POWER, "LCD POWER"); + if (ret) + goto err2; + ret = gpio_direction_output(GPIO_NR_PALMTE2_LCD_POWER, 0); + if (ret) + goto err3; + + return 0; +err3: + gpio_free(GPIO_NR_PALMTE2_LCD_POWER); +err2: + gpio_free(GPIO_NR_PALMTE2_BL_POWER); +err: + return ret; +} + +static int palmte2_backlight_notify(int brightness) +{ + gpio_set_value(GPIO_NR_PALMTE2_BL_POWER, brightness); + gpio_set_value(GPIO_NR_PALMTE2_LCD_POWER, brightness); + return brightness; +} + +static void palmte2_backlight_exit(struct device *dev) +{ + gpio_free(GPIO_NR_PALMTE2_BL_POWER); + gpio_free(GPIO_NR_PALMTE2_LCD_POWER); +} + +static struct platform_pwm_backlight_data palmte2_backlight_data = { + .pwm_id = 0, + .max_brightness = PALMTE2_MAX_INTENSITY, + .dft_brightness = PALMTE2_MAX_INTENSITY, + .pwm_period_ns = PALMTE2_PERIOD_NS, + .init = palmte2_backlight_init, + .notify = palmte2_backlight_notify, + .exit = palmte2_backlight_exit, +}; + +static struct platform_device palmte2_backlight = { + .name = "pwm-backlight", + .dev = { + .parent = &pxa25x_device_pwm0.dev, + .platform_data = &palmte2_backlight_data, + }, +}; + +/****************************************************************************** + * IrDA + ******************************************************************************/ +static int palmte2_irda_startup(struct device *dev) +{ + int err; + err = gpio_request(GPIO_NR_PALMTE2_IR_DISABLE, "IR DISABLE"); + if (err) + goto err; + err = gpio_direction_output(GPIO_NR_PALMTE2_IR_DISABLE, 1); + if (err) + gpio_free(GPIO_NR_PALMTE2_IR_DISABLE); +err: + return err; +} + +static void palmte2_irda_shutdown(struct device *dev) +{ + gpio_free(GPIO_NR_PALMTE2_IR_DISABLE); +} + +static void palmte2_irda_transceiver_mode(struct device *dev, int mode) +{ + gpio_set_value(GPIO_NR_PALMTE2_IR_DISABLE, mode & IR_OFF); + pxa2xx_transceiver_mode(dev, mode); +} + +static struct pxaficp_platform_data palmte2_ficp_platform_data = { + .startup = palmte2_irda_startup, + .shutdown = palmte2_irda_shutdown, + .transceiver_cap = IR_SIRMODE | IR_FIRMODE | IR_OFF, + .transceiver_mode = palmte2_irda_transceiver_mode, +}; + +/****************************************************************************** + * UDC + ******************************************************************************/ +static struct pxa2xx_udc_mach_info palmte2_udc_info __initdata = { + .gpio_vbus = GPIO_NR_PALMTE2_USB_DETECT_N, + .gpio_vbus_inverted = 1, + .gpio_pullup = GPIO_NR_PALMTE2_USB_PULLUP, + .gpio_pullup_inverted = 0, +}; + +/****************************************************************************** + * Power supply + ******************************************************************************/ +static int power_supply_init(struct device *dev) +{ + int ret; + + ret = gpio_request(GPIO_NR_PALMTE2_POWER_DETECT, "CABLE_STATE_AC"); + if (ret) + goto err1; + ret = gpio_direction_input(GPIO_NR_PALMTE2_POWER_DETECT); + if (ret) + goto err2; + + return 0; + +err2: + gpio_free(GPIO_NR_PALMTE2_POWER_DETECT); +err1: + return ret; +} + +static int palmte2_is_ac_online(void) +{ + return gpio_get_value(GPIO_NR_PALMTE2_POWER_DETECT); +} + +static void power_supply_exit(struct device *dev) +{ + gpio_free(GPIO_NR_PALMTE2_POWER_DETECT); +} + +static char *palmte2_supplicants[] = { + "main-battery", +}; + +static struct pda_power_pdata power_supply_info = { + .init = power_supply_init, + .is_ac_online = palmte2_is_ac_online, + .exit = power_supply_exit, + .supplied_to = palmte2_supplicants, + .num_supplicants = ARRAY_SIZE(palmte2_supplicants), +}; + +static struct platform_device power_supply = { + .name = "pda-power", + .id = -1, + .dev = { + .platform_data = &power_supply_info, + }, +}; + +/****************************************************************************** + * WM97xx battery + ******************************************************************************/ +static struct wm97xx_batt_info wm97xx_batt_pdata = { + .batt_aux = WM97XX_AUX_ID3, + .temp_aux = WM97XX_AUX_ID2, + .charge_gpio = -1, + .max_voltage = PALMTE2_BAT_MAX_VOLTAGE, + .min_voltage = PALMTE2_BAT_MIN_VOLTAGE, + .batt_mult = 1000, + .batt_div = 414, + .temp_mult = 1, + .temp_div = 1, + .batt_tech = POWER_SUPPLY_TECHNOLOGY_LIPO, + .batt_name = "main-batt", +}; + +/****************************************************************************** + * Framebuffer + ******************************************************************************/ +static struct pxafb_mode_info palmte2_lcd_modes[] = { +{ + .pixclock = 77757, + .xres = 320, + .yres = 320, + .bpp = 16, + + .left_margin = 28, + .right_margin = 7, + .upper_margin = 7, + .lower_margin = 5, + + .hsync_len = 4, + .vsync_len = 1, +}, +}; + +static struct pxafb_mach_info palmte2_lcd_screen = { + .modes = palmte2_lcd_modes, + .num_modes = ARRAY_SIZE(palmte2_lcd_modes), + .lcd_conn = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL, +}; + +/****************************************************************************** + * Machine init + ******************************************************************************/ +static struct platform_device *devices[] __initdata = { +#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) + &palmte2_pxa_keys, +#endif + &palmte2_backlight, + &power_supply, +}; + +/* setup udc GPIOs initial state */ +static void __init palmte2_udc_init(void) +{ + if (!gpio_request(GPIO_NR_PALMTE2_USB_PULLUP, "UDC Vbus")) { + gpio_direction_output(GPIO_NR_PALMTE2_USB_PULLUP, 1); + gpio_free(GPIO_NR_PALMTE2_USB_PULLUP); + } +} + +static void __init palmte2_init(void) +{ + pxa2xx_mfp_config(ARRAY_AND_SIZE(palmte2_pin_config)); + + set_pxa_fb_info(&palmte2_lcd_screen); + pxa_set_mci_info(&palmte2_mci_platform_data); + palmte2_udc_init(); + pxa_set_udc_info(&palmte2_udc_info); + pxa_set_ac97_info(NULL); + pxa_set_ficp_info(&palmte2_ficp_platform_data); + wm97xx_bat_set_pdata(&wm97xx_batt_pdata); + + platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +MACHINE_START(PALMTE2, "Palm Tungsten|E2") + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .boot_params = 0xa0000100, + .map_io = pxa_map_io, + .init_irq = pxa25x_init_irq, + .timer = &pxa_timer, + .init_machine = palmte2_init +MACHINE_END diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c index b490c0924619..59d0c1cba556 100644 --- a/arch/arm/mach-pxa/palmtx.c +++ b/arch/arm/mach-pxa/palmtx.c @@ -93,10 +93,10 @@ static unsigned long palmtx_pin_config[] __initdata = { GPIO116_GPIO, /* wifi ready */ /* MATRIX KEYPAD */ - GPIO100_KP_MKIN_0, - GPIO101_KP_MKIN_1, - GPIO102_KP_MKIN_2, - GPIO97_KP_MKIN_3, + GPIO100_KP_MKIN_0 | WAKEUP_ON_LEVEL_HIGH, + GPIO101_KP_MKIN_1 | WAKEUP_ON_LEVEL_HIGH, + GPIO102_KP_MKIN_2 | WAKEUP_ON_LEVEL_HIGH, + GPIO97_KP_MKIN_3 | WAKEUP_ON_LEVEL_HIGH, GPIO103_KP_MKOUT_0, GPIO104_KP_MKOUT_1, GPIO105_KP_MKOUT_2, @@ -459,6 +459,33 @@ static struct pxafb_mach_info palmtx_lcd_screen = { }; /****************************************************************************** + * Power management - standby + ******************************************************************************/ +#ifdef CONFIG_PM +static u32 *addr __initdata; +static u32 resume[3] __initdata = { + 0xe3a00101, /* mov r0, #0x40000000 */ + 0xe380060f, /* orr r0, r0, #0x00f00000 */ + 0xe590f008, /* ldr pc, [r0, #0x08] */ +}; + +static int __init palmtx_pm_init(void) +{ + int i; + + /* this is where the bootloader jumps */ + addr = phys_to_virt(PALMTX_STR_BASE); + + for (i = 0; i < 3; i++) + addr[i] = resume[i]; + + return 0; +} + +device_initcall(palmtx_pm_init); +#endif + +/****************************************************************************** * Machine init ******************************************************************************/ static struct platform_device *devices[] __initdata = { diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 6e8ade6ae339..afac5b6d3d78 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -45,6 +45,7 @@ #include <mach/udc.h> #include <mach/tosa_bt.h> #include <mach/pxa2xx_spi.h> +#include <mach/audio.h> #include <asm/mach/arch.h> #include <mach/tosa.h> @@ -914,6 +915,7 @@ static void __init tosa_init(void) pxa_set_udc_info(&udc_info); pxa_set_ficp_info(&tosa_ficp_platform_data); pxa_set_i2c_info(NULL); + pxa_set_ac97_info(NULL); platform_scoop_config = &tosa_pcmcia_config; pxa2xx_set_spi_info(2, &pxa_ssp_master_info); diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index b438fc4fb77b..e6344ece00ce 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -828,6 +828,17 @@ void __init reserve_node_zero(pg_data_t *pgdat) BOOTMEM_DEFAULT); } + if (machine_is_palmld() || machine_is_palmtx()) { + reserve_bootmem_node(pgdat, 0xa0000000, 0x1000, + BOOTMEM_EXCLUSIVE); + reserve_bootmem_node(pgdat, 0xa0200000, 0x1000, + BOOTMEM_EXCLUSIVE); + } + + if (machine_is_palmt5()) + reserve_bootmem_node(pgdat, 0xa0200000, 0x1000, + BOOTMEM_EXCLUSIVE); + #ifdef CONFIG_SA1111 /* * Because of the SA1111 DMA bug, we want to preserve our diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index c232d11a7ed4..06084dbf1277 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -208,7 +208,7 @@ static int mmc_read_ext_csd(struct mmc_card *card) } ext_csd_struct = ext_csd[EXT_CSD_REV]; - if (ext_csd_struct > 2) { + if (ext_csd_struct > 3) { printk(KERN_ERR "%s: unrecognised EXT_CSD structure " "version %d\n", mmc_hostname(card->host), ext_csd_struct); diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 26fc098d77cd..cd81c395e164 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -363,15 +363,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, goto err; /* - * For SPI, enable CRC as appropriate. - */ - if (mmc_host_is_spi(host)) { - err = mmc_spi_set_crc(host, use_spi_crc); - if (err) - goto err; - } - - /* * Fetch CID from card. */ if (mmc_host_is_spi(host)) @@ -458,6 +449,18 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, } /* + * For SPI, enable CRC as appropriate. + * This CRC enable is located AFTER the reading of the + * card registers because some SDHC cards are not able + * to provide valid CRCs for non-512-byte blocks. + */ + if (mmc_host_is_spi(host)) { + err = mmc_spi_set_crc(host, use_spi_crc); + if (err) + goto free_card; + } + + /* * Attempt to change to high-speed (if supported) */ err = mmc_switch_hs(card); diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index eb29b1d933ac..e0be21a4a696 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c @@ -307,13 +307,6 @@ static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data) wmb(); - if (host->actual_bus_width == MMC_BUS_WIDTH_4) - BLR(host->dma) = 0; /* burst 64 byte read / 64 bytes write */ - else - BLR(host->dma) = 16; /* burst 16 byte read / 16 bytes write */ - - RSSR(host->dma) = DMA_REQ_SDHC; - set_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events); clear_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events); @@ -818,9 +811,11 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (ios->bus_width == MMC_BUS_WIDTH_4) { host->actual_bus_width = MMC_BUS_WIDTH_4; imx_gpio_mode(PB11_PF_SD_DAT3); + BLR(host->dma) = 0; /* burst 64 byte read/write */ } else { host->actual_bus_width = MMC_BUS_WIDTH_1; imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11); + BLR(host->dma) = 16; /* burst 16 byte read/write */ } if (host->power_mode != ios->power_mode) { @@ -938,7 +933,7 @@ static void imxmci_check_status(unsigned long data) mod_timer(&host->timer, jiffies + (HZ>>1)); } -static int imxmci_probe(struct platform_device *pdev) +static int __init imxmci_probe(struct platform_device *pdev) { struct mmc_host *mmc; struct imxmci_host *host = NULL; @@ -1034,6 +1029,7 @@ static int imxmci_probe(struct platform_device *pdev) } host->dma_allocated = 1; imx_dma_setup_handlers(host->dma, imxmci_dma_irq, NULL, host); + RSSR(host->dma) = DMA_REQ_SDHC; tasklet_init(&host->tasklet, imxmci_tasklet_fnc, (unsigned long)host); host->status_reg=0; @@ -1079,7 +1075,7 @@ out: return ret; } -static int imxmci_remove(struct platform_device *pdev) +static int __exit imxmci_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); @@ -1145,8 +1141,7 @@ static int imxmci_resume(struct platform_device *dev) #endif /* CONFIG_PM */ static struct platform_driver imxmci_driver = { - .probe = imxmci_probe, - .remove = imxmci_remove, + .remove = __exit_p(imxmci_remove), .suspend = imxmci_suspend, .resume = imxmci_resume, .driver = { @@ -1157,7 +1152,7 @@ static struct platform_driver imxmci_driver = { static int __init imxmci_init(void) { - return platform_driver_register(&imxmci_driver); + return platform_driver_probe(&imxmci_driver, imxmci_probe); } static void __exit imxmci_exit(void) diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 72f8bde4877a..f48349d18c92 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -24,7 +24,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/hrtimer.h> +#include <linux/sched.h> #include <linux/delay.h> #include <linux/bio.h> #include <linux/dma-mapping.h> @@ -95,7 +95,7 @@ * reads which takes nowhere near that long. Older cards may be able to use * shorter timeouts ... but why bother? */ -#define r1b_timeout ktime_set(3, 0) +#define r1b_timeout (HZ * 3) /****************************************************************************/ @@ -183,12 +183,11 @@ mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len) return status; } -static int -mmc_spi_skip(struct mmc_spi_host *host, ktime_t timeout, unsigned n, u8 byte) +static int mmc_spi_skip(struct mmc_spi_host *host, unsigned long timeout, + unsigned n, u8 byte) { u8 *cp = host->data->status; - - timeout = ktime_add(timeout, ktime_get()); + unsigned long start = jiffies; while (1) { int status; @@ -203,22 +202,26 @@ mmc_spi_skip(struct mmc_spi_host *host, ktime_t timeout, unsigned n, u8 byte) return cp[i]; } - /* REVISIT investigate msleep() to avoid busy-wait I/O - * in at least some cases. - */ - if (ktime_to_ns(ktime_sub(ktime_get(), timeout)) > 0) + if (time_is_before_jiffies(start + timeout)) break; + + /* If we need long timeouts, we may release the CPU. + * We use jiffies here because we want to have a relation + * between elapsed time and the blocking of the scheduler. + */ + if (time_is_before_jiffies(start+1)) + schedule(); } return -ETIMEDOUT; } static inline int -mmc_spi_wait_unbusy(struct mmc_spi_host *host, ktime_t timeout) +mmc_spi_wait_unbusy(struct mmc_spi_host *host, unsigned long timeout) { return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0); } -static int mmc_spi_readtoken(struct mmc_spi_host *host, ktime_t timeout) +static int mmc_spi_readtoken(struct mmc_spi_host *host, unsigned long timeout) { return mmc_spi_skip(host, timeout, 1, 0xff); } @@ -251,6 +254,10 @@ static int mmc_spi_response_get(struct mmc_spi_host *host, u8 *cp = host->data->status; u8 *end = cp + host->t.len; int value = 0; + int bitshift; + u8 leftover = 0; + unsigned short rotator; + int i; char tag[32]; snprintf(tag, sizeof(tag), " ... CMD%d response SPI_%s", @@ -268,9 +275,8 @@ static int mmc_spi_response_get(struct mmc_spi_host *host, /* Data block reads (R1 response types) may need more data... */ if (cp == end) { - unsigned i; - cp = host->data->status; + end = cp+1; /* Card sends N(CR) (== 1..8) bytes of all-ones then one * status byte ... and we already scanned 2 bytes. @@ -295,20 +301,34 @@ static int mmc_spi_response_get(struct mmc_spi_host *host, } checkstatus: - if (*cp & 0x80) { - dev_dbg(&host->spi->dev, "%s: INVALID RESPONSE, %02x\n", - tag, *cp); - value = -EBADR; - goto done; + bitshift = 0; + if (*cp & 0x80) { + /* Houston, we have an ugly card with a bit-shifted response */ + rotator = *cp++ << 8; + /* read the next byte */ + if (cp == end) { + value = mmc_spi_readbytes(host, 1); + if (value < 0) + goto done; + cp = host->data->status; + end = cp+1; + } + rotator |= *cp++; + while (rotator & 0x8000) { + bitshift++; + rotator <<= 1; + } + cmd->resp[0] = rotator >> 8; + leftover = rotator; + } else { + cmd->resp[0] = *cp++; } - - cmd->resp[0] = *cp++; cmd->error = 0; /* Status byte: the entire seven-bit R1 response. */ if (cmd->resp[0] != 0) { if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS - | R1_SPI_ILLEGAL_COMMAND) + | R1_SPI_ILLEGAL_COMMAND) & cmd->resp[0]) value = -EINVAL; else if (R1_SPI_COM_CRC & cmd->resp[0]) @@ -336,12 +356,45 @@ checkstatus: * SPI R5 == R1 + data byte; IO_RW_DIRECT */ case MMC_RSP_SPI_R2: - cmd->resp[0] |= *cp << 8; + /* read the next byte */ + if (cp == end) { + value = mmc_spi_readbytes(host, 1); + if (value < 0) + goto done; + cp = host->data->status; + end = cp+1; + } + if (bitshift) { + rotator = leftover << 8; + rotator |= *cp << bitshift; + cmd->resp[0] |= (rotator & 0xFF00); + } else { + cmd->resp[0] |= *cp << 8; + } break; /* SPI R3, R4, or R7 == R1 + 4 bytes */ case MMC_RSP_SPI_R3: - cmd->resp[1] = get_unaligned_be32(cp); + rotator = leftover << 8; + cmd->resp[1] = 0; + for (i = 0; i < 4; i++) { + cmd->resp[1] <<= 8; + /* read the next byte */ + if (cp == end) { + value = mmc_spi_readbytes(host, 1); + if (value < 0) + goto done; + cp = host->data->status; + end = cp+1; + } + if (bitshift) { + rotator |= *cp++ << bitshift; + cmd->resp[1] |= (rotator >> 8); + rotator <<= 8; + } else { + cmd->resp[1] |= *cp++; + } + } break; /* SPI R1 == just one status byte */ @@ -607,7 +660,7 @@ mmc_spi_setup_data_message( */ static int mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t, - ktime_t timeout) + unsigned long timeout) { struct spi_device *spi = host->spi; int status, i; @@ -717,11 +770,13 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t, */ static int mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t, - ktime_t timeout) + unsigned long timeout) { struct spi_device *spi = host->spi; int status; struct scratch *scratch = host->data; + unsigned int bitshift; + u8 leftover; /* At least one SD card sends an all-zeroes byte when N(CX) * applies, before the all-ones bytes ... just cope with that. @@ -733,38 +788,60 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t, if (status == 0xff || status == 0) status = mmc_spi_readtoken(host, timeout); - if (status == SPI_TOKEN_SINGLE) { - if (host->dma_dev) { - dma_sync_single_for_device(host->dma_dev, - host->data_dma, sizeof(*scratch), - DMA_BIDIRECTIONAL); - dma_sync_single_for_device(host->dma_dev, - t->rx_dma, t->len, - DMA_FROM_DEVICE); - } + if (status < 0) { + dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status); + return status; + } - status = spi_sync(spi, &host->m); + /* The token may be bit-shifted... + * the first 0-bit precedes the data stream. + */ + bitshift = 7; + while (status & 0x80) { + status <<= 1; + bitshift--; + } + leftover = status << 1; - if (host->dma_dev) { - dma_sync_single_for_cpu(host->dma_dev, - host->data_dma, sizeof(*scratch), - DMA_BIDIRECTIONAL); - dma_sync_single_for_cpu(host->dma_dev, - t->rx_dma, t->len, - DMA_FROM_DEVICE); - } + if (host->dma_dev) { + dma_sync_single_for_device(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + dma_sync_single_for_device(host->dma_dev, + t->rx_dma, t->len, + DMA_FROM_DEVICE); + } - } else { - dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status); + status = spi_sync(spi, &host->m); - /* we've read extra garbage, timed out, etc */ - if (status < 0) - return status; + if (host->dma_dev) { + dma_sync_single_for_cpu(host->dma_dev, + host->data_dma, sizeof(*scratch), + DMA_BIDIRECTIONAL); + dma_sync_single_for_cpu(host->dma_dev, + t->rx_dma, t->len, + DMA_FROM_DEVICE); + } - /* low four bits are an R2 subset, fifth seems to be - * vendor specific ... map them all to generic error.. + if (bitshift) { + /* Walk through the data and the crc and do + * all the magic to get byte-aligned data. */ - return -EIO; + u8 *cp = t->rx_buf; + unsigned int len; + unsigned int bitright = 8 - bitshift; + u8 temp; + for (len = t->len; len; len--) { + temp = *cp; + *cp++ = leftover | (temp >> bitshift); + leftover = temp << bitright; + } + cp = (u8 *) &scratch->crc_val; + temp = *cp; + *cp++ = leftover | (temp >> bitshift); + leftover = temp << bitright; + temp = *cp; + *cp = leftover | (temp >> bitshift); } if (host->mmc->use_spi_crc) { @@ -803,7 +880,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, unsigned n_sg; int multiple = (data->blocks > 1); u32 clock_rate; - ktime_t timeout; + unsigned long timeout; if (data->flags & MMC_DATA_READ) direction = DMA_FROM_DEVICE; @@ -817,8 +894,9 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, else clock_rate = spi->max_speed_hz; - timeout = ktime_add_ns(ktime_set(0, 0), data->timeout_ns + - data->timeout_clks * 1000000 / clock_rate); + timeout = data->timeout_ns + + data->timeout_clks * 1000000 / clock_rate; + timeout = usecs_to_jiffies((unsigned int)(timeout / 1000)) + 1; /* Handle scatterlist segments one at a time, with synch for * each 512-byte block diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index d183be6f2a5f..e62a22a7f00c 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -298,7 +298,6 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) struct mmc_request *mrq = host->mrq; host->mrq = NULL; - mmc_omap_fclk_lazy_disable(host); mmc_request_done(host->mmc, mrq); return; } @@ -434,6 +433,8 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) if (host->mrq == NULL) { OMAP_HSMMC_WRITE(host->base, STAT, OMAP_HSMMC_READ(host->base, STAT)); + /* Flush posted write */ + OMAP_HSMMC_READ(host->base, STAT); return IRQ_HANDLED; } @@ -489,8 +490,10 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) } OMAP_HSMMC_WRITE(host->base, STAT, status); + /* Flush posted write */ + OMAP_HSMMC_READ(host->base, STAT); - if (end_cmd || (status & CC)) + if (end_cmd || ((status & CC) && host->cmd)) mmc_omap_cmd_done(host, host->cmd); if (end_trans || (status & TC)) mmc_omap_xfer_done(host, data); diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index c5b316e22371..cd37962ec44f 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -729,6 +729,6 @@ static void __exit sdhci_drv_exit(void) module_init(sdhci_drv_init); module_exit(sdhci_drv_exit); -MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>"); +MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>"); MODULE_DESCRIPTION("Secure Digital Host Controller Interface PCI driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 30d8e3d4e6fd..9234be2226e7 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1935,7 +1935,7 @@ module_exit(sdhci_drv_exit); module_param(debug_quirks, uint, 0444); -MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>"); +MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>"); MODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index adda37952032..89bf8cd25cac 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -2036,7 +2036,7 @@ module_param_named(irq, param_irq, uint, 0444); module_param_named(dma, param_dma, int, 0444); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>"); +MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>"); MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver"); #ifdef CONFIG_PNP diff --git a/drivers/serial/max3100.c b/drivers/serial/max3100.c new file mode 100644 index 000000000000..9fd33e5622bd --- /dev/null +++ b/drivers/serial/max3100.c @@ -0,0 +1,927 @@ +/* + * + * Copyright (C) 2008 Christian Pellegrin <chripell@evolware.org> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * + * Notes: the MAX3100 doesn't provide an interrupt on CTS so we have + * to use polling for flow control. TX empty IRQ is unusable, since + * writing conf clears FIFO buffer and we cannot have this interrupt + * always asking us for attention. + * + * Example platform data: + + static struct plat_max3100 max3100_plat_data = { + .loopback = 0, + .crystal = 0, + .poll_time = 100, + }; + + static struct spi_board_info spi_board_info[] = { + { + .modalias = "max3100", + .platform_data = &max3100_plat_data, + .irq = IRQ_EINT12, + .max_speed_hz = 5*1000*1000, + .chip_select = 0, + }, + }; + + * The initial minor number is 209 in the low-density serial port: + * mknod /dev/ttyMAX0 c 204 209 + */ + +#define MAX3100_MAJOR 204 +#define MAX3100_MINOR 209 +/* 4 MAX3100s should be enough for everyone */ +#define MAX_MAX3100 4 + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/serial_core.h> +#include <linux/serial.h> +#include <linux/spi/spi.h> +#include <linux/freezer.h> + +#include <linux/serial_max3100.h> + +#define MAX3100_C (1<<14) +#define MAX3100_D (0<<14) +#define MAX3100_W (1<<15) +#define MAX3100_RX (0<<15) + +#define MAX3100_WC (MAX3100_W | MAX3100_C) +#define MAX3100_RC (MAX3100_RX | MAX3100_C) +#define MAX3100_WD (MAX3100_W | MAX3100_D) +#define MAX3100_RD (MAX3100_RX | MAX3100_D) +#define MAX3100_CMD (3 << 14) + +#define MAX3100_T (1<<14) +#define MAX3100_R (1<<15) + +#define MAX3100_FEN (1<<13) +#define MAX3100_SHDN (1<<12) +#define MAX3100_TM (1<<11) +#define MAX3100_RM (1<<10) +#define MAX3100_PM (1<<9) +#define MAX3100_RAM (1<<8) +#define MAX3100_IR (1<<7) +#define MAX3100_ST (1<<6) +#define MAX3100_PE (1<<5) +#define MAX3100_L (1<<4) +#define MAX3100_BAUD (0xf) + +#define MAX3100_TE (1<<10) +#define MAX3100_RAFE (1<<10) +#define MAX3100_RTS (1<<9) +#define MAX3100_CTS (1<<9) +#define MAX3100_PT (1<<8) +#define MAX3100_DATA (0xff) + +#define MAX3100_RT (MAX3100_R | MAX3100_T) +#define MAX3100_RTC (MAX3100_RT | MAX3100_CTS | MAX3100_RAFE) + +/* the following simulate a status reg for ignore_status_mask */ +#define MAX3100_STATUS_PE 1 +#define MAX3100_STATUS_FE 2 +#define MAX3100_STATUS_OE 4 + +struct max3100_port { + struct uart_port port; + struct spi_device *spi; + + int cts; /* last CTS received for flow ctrl */ + int tx_empty; /* last TX empty bit */ + + spinlock_t conf_lock; /* shared data */ + int conf_commit; /* need to make changes */ + int conf; /* configuration for the MAX31000 + * (bits 0-7, bits 8-11 are irqs) */ + int rts_commit; /* need to change rts */ + int rts; /* rts status */ + int baud; /* current baud rate */ + + int parity; /* keeps track if we should send parity */ +#define MAX3100_PARITY_ON 1 +#define MAX3100_PARITY_ODD 2 +#define MAX3100_7BIT 4 + int rx_enabled; /* if we should rx chars */ + + int irq; /* irq assigned to the max3100 */ + + int minor; /* minor number */ + int crystal; /* 1 if 3.6864Mhz crystal 0 for 1.8432 */ + int loopback; /* 1 if we are in loopback mode */ + + /* for handling irqs: need workqueue since we do spi_sync */ + struct workqueue_struct *workqueue; + struct work_struct work; + /* set to 1 to make the workhandler exit as soon as possible */ + int force_end_work; + /* need to know we are suspending to avoid deadlock on workqueue */ + int suspending; + + /* hook for suspending MAX3100 via dedicated pin */ + void (*max3100_hw_suspend) (int suspend); + + /* poll time (in ms) for ctrl lines */ + int poll_time; + /* and its timer */ + struct timer_list timer; +}; + +static struct max3100_port *max3100s[MAX_MAX3100]; /* the chips */ +static DEFINE_MUTEX(max3100s_lock); /* race on probe */ + +static int max3100_do_parity(struct max3100_port *s, u16 c) +{ + int parity; + + if (s->parity & MAX3100_PARITY_ODD) + parity = 1; + else + parity = 0; + + if (s->parity & MAX3100_7BIT) + c &= 0x7f; + else + c &= 0xff; + + parity = parity ^ (hweight8(c) & 1); + return parity; +} + +static int max3100_check_parity(struct max3100_port *s, u16 c) +{ + return max3100_do_parity(s, c) == ((c >> 8) & 1); +} + +static void max3100_calc_parity(struct max3100_port *s, u16 *c) +{ + if (s->parity & MAX3100_7BIT) + *c &= 0x7f; + else + *c &= 0xff; + + if (s->parity & MAX3100_PARITY_ON) + *c |= max3100_do_parity(s, *c) << 8; +} + +static void max3100_work(struct work_struct *w); + +static void max3100_dowork(struct max3100_port *s) +{ + if (!s->force_end_work && !work_pending(&s->work) && + !freezing(current) && !s->suspending) + queue_work(s->workqueue, &s->work); +} + +static void max3100_timeout(unsigned long data) +{ + struct max3100_port *s = (struct max3100_port *)data; + + if (s->port.info) { + max3100_dowork(s); + mod_timer(&s->timer, jiffies + s->poll_time); + } +} + +static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx) +{ + struct spi_message message; + u16 etx, erx; + int status; + struct spi_transfer tran = { + .tx_buf = &etx, + .rx_buf = &erx, + .len = 2, + }; + + etx = cpu_to_be16(tx); + spi_message_init(&message); + spi_message_add_tail(&tran, &message); + status = spi_sync(s->spi, &message); + if (status) { + dev_warn(&s->spi->dev, "error while calling spi_sync\n"); + return -EIO; + } + *rx = be16_to_cpu(erx); + s->tx_empty = (*rx & MAX3100_T) > 0; + dev_dbg(&s->spi->dev, "%04x - %04x\n", tx, *rx); + return 0; +} + +static int max3100_handlerx(struct max3100_port *s, u16 rx) +{ + unsigned int ch, flg, status = 0; + int ret = 0, cts; + + if (rx & MAX3100_R && s->rx_enabled) { + dev_dbg(&s->spi->dev, "%s\n", __func__); + ch = rx & (s->parity & MAX3100_7BIT ? 0x7f : 0xff); + if (rx & MAX3100_RAFE) { + s->port.icount.frame++; + flg = TTY_FRAME; + status |= MAX3100_STATUS_FE; + } else { + if (s->parity & MAX3100_PARITY_ON) { + if (max3100_check_parity(s, rx)) { + s->port.icount.rx++; + flg = TTY_NORMAL; + } else { + s->port.icount.parity++; + flg = TTY_PARITY; + status |= MAX3100_STATUS_PE; + } + } else { + s->port.icount.rx++; + flg = TTY_NORMAL; + } + } + uart_insert_char(&s->port, status, MAX3100_STATUS_OE, ch, flg); + ret = 1; + } + + cts = (rx & MAX3100_CTS) > 0; + if (s->cts != cts) { + s->cts = cts; + uart_handle_cts_change(&s->port, cts ? TIOCM_CTS : 0); + } + + return ret; +} + +static void max3100_work(struct work_struct *w) +{ + struct max3100_port *s = container_of(w, struct max3100_port, work); + int rxchars; + u16 tx, rx; + int conf, cconf, rts, crts; + struct circ_buf *xmit = &s->port.info->xmit; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + rxchars = 0; + do { + spin_lock(&s->conf_lock); + conf = s->conf; + cconf = s->conf_commit; + s->conf_commit = 0; + rts = s->rts; + crts = s->rts_commit; + s->rts_commit = 0; + spin_unlock(&s->conf_lock); + if (cconf) + max3100_sr(s, MAX3100_WC | conf, &rx); + if (crts) { + max3100_sr(s, MAX3100_WD | MAX3100_TE | + (s->rts ? MAX3100_RTS : 0), &rx); + rxchars += max3100_handlerx(s, rx); + } + + max3100_sr(s, MAX3100_RD, &rx); + rxchars += max3100_handlerx(s, rx); + + if (rx & MAX3100_T) { + tx = 0xffff; + if (s->port.x_char) { + tx = s->port.x_char; + s->port.icount.tx++; + s->port.x_char = 0; + } else if (!uart_circ_empty(xmit) && + !uart_tx_stopped(&s->port)) { + tx = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & + (UART_XMIT_SIZE - 1); + s->port.icount.tx++; + } + if (tx != 0xffff) { + max3100_calc_parity(s, &tx); + tx |= MAX3100_WD | (s->rts ? MAX3100_RTS : 0); + max3100_sr(s, tx, &rx); + rxchars += max3100_handlerx(s, rx); + } + } + + if (rxchars > 16 && s->port.info->port.tty != NULL) { + tty_flip_buffer_push(s->port.info->port.tty); + rxchars = 0; + } + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&s->port); + + } while (!s->force_end_work && + !freezing(current) && + ((rx & MAX3100_R) || + (!uart_circ_empty(xmit) && + !uart_tx_stopped(&s->port)))); + + if (rxchars > 0 && s->port.info->port.tty != NULL) + tty_flip_buffer_push(s->port.info->port.tty); +} + +static irqreturn_t max3100_irq(int irqno, void *dev_id) +{ + struct max3100_port *s = dev_id; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + max3100_dowork(s); + return IRQ_HANDLED; +} + +static void max3100_enable_ms(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + if (s->poll_time > 0) + mod_timer(&s->timer, jiffies); + dev_dbg(&s->spi->dev, "%s\n", __func__); +} + +static void max3100_start_tx(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + max3100_dowork(s); +} + +static void max3100_stop_rx(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + s->rx_enabled = 0; + spin_lock(&s->conf_lock); + s->conf &= ~MAX3100_RM; + s->conf_commit = 1; + spin_unlock(&s->conf_lock); + max3100_dowork(s); +} + +static unsigned int max3100_tx_empty(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + /* may not be truly up-to-date */ + max3100_dowork(s); + return s->tx_empty; +} + +static unsigned int max3100_get_mctrl(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + /* may not be truly up-to-date */ + max3100_dowork(s); + /* always assert DCD and DSR since these lines are not wired */ + return (s->cts ? TIOCM_CTS : 0) | TIOCM_DSR | TIOCM_CAR; +} + +static void max3100_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + int rts; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + rts = (mctrl & TIOCM_RTS) > 0; + + spin_lock(&s->conf_lock); + if (s->rts != rts) { + s->rts = rts; + s->rts_commit = 1; + max3100_dowork(s); + } + spin_unlock(&s->conf_lock); +} + +static void +max3100_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + int baud = 0; + unsigned cflag; + u32 param_new, param_mask, parity = 0; + struct tty_struct *tty = s->port.info->port.tty; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + if (!tty) + return; + + cflag = termios->c_cflag; + param_new = 0; + param_mask = 0; + + baud = tty_get_baud_rate(tty); + param_new = s->conf & MAX3100_BAUD; + switch (baud) { + case 300: + if (s->crystal) + baud = s->baud; + else + param_new = 15; + break; + case 600: + param_new = 14 + s->crystal; + break; + case 1200: + param_new = 13 + s->crystal; + break; + case 2400: + param_new = 12 + s->crystal; + break; + case 4800: + param_new = 11 + s->crystal; + break; + case 9600: + param_new = 10 + s->crystal; + break; + case 19200: + param_new = 9 + s->crystal; + break; + case 38400: + param_new = 8 + s->crystal; + break; + case 57600: + param_new = 1 + s->crystal; + break; + case 115200: + param_new = 0 + s->crystal; + break; + case 230400: + if (s->crystal) + param_new = 0; + else + baud = s->baud; + break; + default: + baud = s->baud; + } + tty_encode_baud_rate(tty, baud, baud); + s->baud = baud; + param_mask |= MAX3100_BAUD; + + if ((cflag & CSIZE) == CS8) { + param_new &= ~MAX3100_L; + parity &= ~MAX3100_7BIT; + } else { + param_new |= MAX3100_L; + parity |= MAX3100_7BIT; + cflag = (cflag & ~CSIZE) | CS7; + } + param_mask |= MAX3100_L; + + if (cflag & CSTOPB) + param_new |= MAX3100_ST; + else + param_new &= ~MAX3100_ST; + param_mask |= MAX3100_ST; + + if (cflag & PARENB) { + param_new |= MAX3100_PE; + parity |= MAX3100_PARITY_ON; + } else { + param_new &= ~MAX3100_PE; + parity &= ~MAX3100_PARITY_ON; + } + param_mask |= MAX3100_PE; + + if (cflag & PARODD) + parity |= MAX3100_PARITY_ODD; + else + parity &= ~MAX3100_PARITY_ODD; + + /* mask termios capabilities we don't support */ + cflag &= ~CMSPAR; + termios->c_cflag = cflag; + + s->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + s->port.ignore_status_mask |= + MAX3100_STATUS_PE | MAX3100_STATUS_FE | + MAX3100_STATUS_OE; + + /* we are sending char from a workqueue so enable */ + s->port.info->port.tty->low_latency = 1; + + if (s->poll_time > 0) + del_timer_sync(&s->timer); + + uart_update_timeout(port, termios->c_cflag, baud); + + spin_lock(&s->conf_lock); + s->conf = (s->conf & ~param_mask) | (param_new & param_mask); + s->conf_commit = 1; + s->parity = parity; + spin_unlock(&s->conf_lock); + max3100_dowork(s); + + if (UART_ENABLE_MS(&s->port, termios->c_cflag)) + max3100_enable_ms(&s->port); +} + +static void max3100_shutdown(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + if (s->suspending) + return; + + s->force_end_work = 1; + + if (s->poll_time > 0) + del_timer_sync(&s->timer); + + if (s->workqueue) { + flush_workqueue(s->workqueue); + destroy_workqueue(s->workqueue); + s->workqueue = NULL; + } + if (s->irq) + free_irq(s->irq, s); + + /* set shutdown mode to save power */ + if (s->max3100_hw_suspend) + s->max3100_hw_suspend(1); + else { + u16 tx, rx; + + tx = MAX3100_WC | MAX3100_SHDN; + max3100_sr(s, tx, &rx); + } +} + +static int max3100_startup(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + char b[12]; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + s->conf = MAX3100_RM; + s->baud = s->crystal ? 230400 : 115200; + s->rx_enabled = 1; + + if (s->suspending) + return 0; + + s->force_end_work = 0; + s->parity = 0; + s->rts = 0; + + sprintf(b, "max3100-%d", s->minor); + s->workqueue = create_freezeable_workqueue(b); + if (!s->workqueue) { + dev_warn(&s->spi->dev, "cannot create workqueue\n"); + return -EBUSY; + } + INIT_WORK(&s->work, max3100_work); + + if (request_irq(s->irq, max3100_irq, + IRQF_TRIGGER_FALLING, "max3100", s) < 0) { + dev_warn(&s->spi->dev, "cannot allocate irq %d\n", s->irq); + s->irq = 0; + destroy_workqueue(s->workqueue); + s->workqueue = NULL; + return -EBUSY; + } + + if (s->loopback) { + u16 tx, rx; + tx = 0x4001; + max3100_sr(s, tx, &rx); + } + + if (s->max3100_hw_suspend) + s->max3100_hw_suspend(0); + s->conf_commit = 1; + max3100_dowork(s); + /* wait for clock to settle */ + msleep(50); + + max3100_enable_ms(&s->port); + + return 0; +} + +static const char *max3100_type(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + return s->port.type == PORT_MAX3100 ? "MAX3100" : NULL; +} + +static void max3100_release_port(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); +} + +static void max3100_config_port(struct uart_port *port, int flags) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + if (flags & UART_CONFIG_TYPE) + s->port.type = PORT_MAX3100; +} + +static int max3100_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + int ret = -EINVAL; + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3100) + ret = 0; + return ret; +} + +static void max3100_stop_tx(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); +} + +static int max3100_request_port(struct uart_port *port) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + return 0; +} + +static void max3100_break_ctl(struct uart_port *port, int break_state) +{ + struct max3100_port *s = container_of(port, + struct max3100_port, + port); + + dev_dbg(&s->spi->dev, "%s\n", __func__); +} + +static struct uart_ops max3100_ops = { + .tx_empty = max3100_tx_empty, + .set_mctrl = max3100_set_mctrl, + .get_mctrl = max3100_get_mctrl, + .stop_tx = max3100_stop_tx, + .start_tx = max3100_start_tx, + .stop_rx = max3100_stop_rx, + .enable_ms = max3100_enable_ms, + .break_ctl = max3100_break_ctl, + .startup = max3100_startup, + .shutdown = max3100_shutdown, + .set_termios = max3100_set_termios, + .type = max3100_type, + .release_port = max3100_release_port, + .request_port = max3100_request_port, + .config_port = max3100_config_port, + .verify_port = max3100_verify_port, +}; + +static struct uart_driver max3100_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "ttyMAX", + .dev_name = "ttyMAX", + .major = MAX3100_MAJOR, + .minor = MAX3100_MINOR, + .nr = MAX_MAX3100, +}; +static int uart_driver_registered; + +static int __devinit max3100_probe(struct spi_device *spi) +{ + int i, retval; + struct plat_max3100 *pdata; + u16 tx, rx; + + mutex_lock(&max3100s_lock); + + if (!uart_driver_registered) { + uart_driver_registered = 1; + retval = uart_register_driver(&max3100_uart_driver); + if (retval) { + printk(KERN_ERR "Couldn't register max3100 uart driver\n"); + mutex_unlock(&max3100s_lock); + return retval; + } + } + + for (i = 0; i < MAX_MAX3100; i++) + if (!max3100s[i]) + break; + if (i == MAX_MAX3100) { + dev_warn(&spi->dev, "too many MAX3100 chips\n"); + mutex_unlock(&max3100s_lock); + return -ENOMEM; + } + + max3100s[i] = kzalloc(sizeof(struct max3100_port), GFP_KERNEL); + if (!max3100s[i]) { + dev_warn(&spi->dev, + "kmalloc for max3100 structure %d failed!\n", i); + mutex_unlock(&max3100s_lock); + return -ENOMEM; + } + max3100s[i]->spi = spi; + max3100s[i]->irq = spi->irq; + spin_lock_init(&max3100s[i]->conf_lock); + dev_set_drvdata(&spi->dev, max3100s[i]); + pdata = spi->dev.platform_data; + max3100s[i]->crystal = pdata->crystal; + max3100s[i]->loopback = pdata->loopback; + max3100s[i]->poll_time = pdata->poll_time * HZ / 1000; + if (pdata->poll_time > 0 && max3100s[i]->poll_time == 0) + max3100s[i]->poll_time = 1; + max3100s[i]->max3100_hw_suspend = pdata->max3100_hw_suspend; + max3100s[i]->minor = i; + init_timer(&max3100s[i]->timer); + max3100s[i]->timer.function = max3100_timeout; + max3100s[i]->timer.data = (unsigned long) max3100s[i]; + + dev_dbg(&spi->dev, "%s: adding port %d\n", __func__, i); + max3100s[i]->port.irq = max3100s[i]->irq; + max3100s[i]->port.uartclk = max3100s[i]->crystal ? 3686400 : 1843200; + max3100s[i]->port.fifosize = 16; + max3100s[i]->port.ops = &max3100_ops; + max3100s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; + max3100s[i]->port.line = i; + max3100s[i]->port.type = PORT_MAX3100; + max3100s[i]->port.dev = &spi->dev; + retval = uart_add_one_port(&max3100_uart_driver, &max3100s[i]->port); + if (retval < 0) + dev_warn(&spi->dev, + "uart_add_one_port failed for line %d with error %d\n", + i, retval); + + /* set shutdown mode to save power. Will be woken-up on open */ + if (max3100s[i]->max3100_hw_suspend) + max3100s[i]->max3100_hw_suspend(1); + else { + tx = MAX3100_WC | MAX3100_SHDN; + max3100_sr(max3100s[i], tx, &rx); + } + mutex_unlock(&max3100s_lock); + return 0; +} + +static int __devexit max3100_remove(struct spi_device *spi) +{ + struct max3100_port *s = dev_get_drvdata(&spi->dev); + int i; + + mutex_lock(&max3100s_lock); + + /* find out the index for the chip we are removing */ + for (i = 0; i < MAX_MAX3100; i++) + if (max3100s[i] == s) + break; + + dev_dbg(&spi->dev, "%s: removing port %d\n", __func__, i); + uart_remove_one_port(&max3100_uart_driver, &max3100s[i]->port); + kfree(max3100s[i]); + max3100s[i] = NULL; + + /* check if this is the last chip we have */ + for (i = 0; i < MAX_MAX3100; i++) + if (max3100s[i]) { + mutex_unlock(&max3100s_lock); + return 0; + } + pr_debug("removing max3100 driver\n"); + uart_unregister_driver(&max3100_uart_driver); + + mutex_unlock(&max3100s_lock); + return 0; +} + +#ifdef CONFIG_PM + +static int max3100_suspend(struct spi_device *spi, pm_message_t state) +{ + struct max3100_port *s = dev_get_drvdata(&spi->dev); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + disable_irq(s->irq); + + s->suspending = 1; + uart_suspend_port(&max3100_uart_driver, &s->port); + + if (s->max3100_hw_suspend) + s->max3100_hw_suspend(1); + else { + /* no HW suspend, so do SW one */ + u16 tx, rx; + + tx = MAX3100_WC | MAX3100_SHDN; + max3100_sr(s, tx, &rx); + } + return 0; +} + +static int max3100_resume(struct spi_device *spi) +{ + struct max3100_port *s = dev_get_drvdata(&spi->dev); + + dev_dbg(&s->spi->dev, "%s\n", __func__); + + if (s->max3100_hw_suspend) + s->max3100_hw_suspend(0); + uart_resume_port(&max3100_uart_driver, &s->port); + s->suspending = 0; + + enable_irq(s->irq); + + s->conf_commit = 1; + if (s->workqueue) + max3100_dowork(s); + + return 0; +} + +#else +#define max3100_suspend NULL +#define max3100_resume NULL +#endif + +static struct spi_driver max3100_driver = { + .driver = { + .name = "max3100", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = max3100_probe, + .remove = __devexit_p(max3100_remove), + .suspend = max3100_suspend, + .resume = max3100_resume, +}; + +static int __init max3100_init(void) +{ + return spi_register_driver(&max3100_driver); +} +module_init(max3100_init); + +static void __exit max3100_exit(void) +{ + spi_unregister_driver(&max3100_driver); +} +module_exit(max3100_exit); + +MODULE_DESCRIPTION("MAX3100 driver"); +MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 4ed228a89943..bb5e6f671578 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -280,7 +280,7 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) * are always powered while this driver is active, and use * active-low power switches. */ - for (i = 0; i < pdata->ports; i++) { + for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) { if (pdata->vbus_pin[i] <= 0) continue; gpio_request(pdata->vbus_pin[i], "ohci_vbus"); @@ -298,7 +298,7 @@ static int ohci_hcd_at91_drv_remove(struct platform_device *pdev) int i; if (pdata) { - for (i = 0; i < pdata->ports; i++) { + for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) { if (pdata->vbus_pin[i] <= 0) continue; gpio_direction_output(pdata->vbus_pin[i], 1); diff --git a/fs/befs/super.c b/fs/befs/super.c index 41f2b4d0093e..ca40f828f64d 100644 --- a/fs/befs/super.c +++ b/fs/befs/super.c @@ -8,6 +8,7 @@ */ #include <linux/fs.h> +#include <asm/page.h> /* for PAGE_SIZE */ #include "befs.h" #include "super.h" diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index 12c20377772d..64a72e2e7650 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c @@ -135,7 +135,7 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma) struct inode *inode = vma->vm_file->f_path.dentry->d_inode; dev = inode->i_sb->s_dev; ino = inode->i_ino; - pgoff = (loff_t)vma->pg_off << PAGE_SHIFT; + pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT; } seq_printf(m, diff --git a/include/linux/serial_max3100.h b/include/linux/serial_max3100.h new file mode 100644 index 000000000000..4976befb6aeb --- /dev/null +++ b/include/linux/serial_max3100.h @@ -0,0 +1,52 @@ +/* + * + * Copyright (C) 2007 Christian Pellegrin + * + * 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; either version 2 of the License, or + * (at your option) any later version. + */ + + +#ifndef _LINUX_SERIAL_MAX3100_H +#define _LINUX_SERIAL_MAX3100_H 1 + + +/** + * struct plat_max3100 - MAX3100 SPI UART platform data + * @loopback: force MAX3100 in loopback + * @crystal: 1 for 3.6864 Mhz, 0 for 1.8432 + * @max3100_hw_suspend: MAX3100 has a shutdown pin. This is a hook + * called on suspend and resume to activate it. + * @poll_time: poll time for CTS signal in ms, 0 disables (so no hw + * flow ctrl is possible but you have less CPU usage) + * + * You should use this structure in your machine description to specify + * how the MAX3100 is connected. Example: + * + * static struct plat_max3100 max3100_plat_data = { + * .loopback = 0, + * .crystal = 0, + * .poll_time = 100, + * }; + * + * static struct spi_board_info spi_board_info[] = { + * { + * .modalias = "max3100", + * .platform_data = &max3100_plat_data, + * .irq = IRQ_EINT12, + * .max_speed_hz = 5*1000*1000, + * .chip_select = 0, + * }, + * }; + * + **/ +struct plat_max3100 { + int loopback; + int crystal; + void (*max3100_hw_suspend) (int suspend); + int poll_time; +}; + +#endif diff --git a/kernel/ptrace.c b/kernel/ptrace.c index aaad0ec34194..64191fa09b7e 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -21,9 +21,7 @@ #include <linux/audit.h> #include <linux/pid_namespace.h> #include <linux/syscalls.h> - -#include <asm/pgtable.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> /* @@ -48,7 +46,7 @@ void __ptrace_link(struct task_struct *child, struct task_struct *new_parent) list_add(&child->ptrace_entry, &new_parent->ptraced); child->parent = new_parent; } - + /* * Turn a tracing stop into a normal stop now, since with no tracer there * would be no way to wake it up with SIGCONT or SIGKILL. If there was a @@ -173,7 +171,7 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode) task_lock(task); err = __ptrace_may_access(task, mode); task_unlock(task); - return (!err ? true : false); + return !err; } int ptrace_attach(struct task_struct *task) @@ -358,7 +356,7 @@ int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst copied += retval; src += retval; dst += retval; - len -= retval; + len -= retval; } return copied; } @@ -383,7 +381,7 @@ int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long ds copied += retval; src += retval; dst += retval; - len -= retval; + len -= retval; } return copied; } @@ -496,9 +494,9 @@ static int ptrace_resume(struct task_struct *child, long request, long data) if (unlikely(!arch_has_single_step())) return -EIO; user_enable_single_step(child); - } - else + } else { user_disable_single_step(child); + } child->exit_code = data; wake_up_process(child); |