2005-09-13 12:25:34 +04:00
|
|
|
/*
|
|
|
|
* Support for Sharp SL-Cxx00 Series of PDAs
|
|
|
|
* Models: SL-C3000 (Spitz), SL-C1000 (Akita) and SL-C3100 (Borzoi)
|
|
|
|
*
|
|
|
|
* Copyright (c) 2005 Richard Purdie
|
|
|
|
*
|
|
|
|
* Based on Sharp's 2.4 kernel patches/lubbock.c
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/init.h>
|
2005-10-29 22:07:23 +04:00
|
|
|
#include <linux/platform_device.h>
|
2005-09-13 12:25:34 +04:00
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/major.h>
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/interrupt.h>
|
2008-09-02 13:34:33 +04:00
|
|
|
#include <linux/gpio.h>
|
2005-09-13 12:25:34 +04:00
|
|
|
#include <linux/mmc/host.h>
|
2006-06-19 22:57:12 +04:00
|
|
|
#include <linux/pm.h>
|
2007-09-03 03:27:00 +04:00
|
|
|
#include <linux/backlight.h>
|
2005-09-13 12:25:34 +04:00
|
|
|
|
|
|
|
#include <asm/setup.h>
|
|
|
|
#include <asm/memory.h>
|
|
|
|
#include <asm/mach-types.h>
|
2008-08-05 19:14:15 +04:00
|
|
|
#include <mach/hardware.h>
|
2005-09-13 12:25:34 +04:00
|
|
|
#include <asm/irq.h>
|
|
|
|
#include <asm/io.h>
|
2006-06-19 22:57:12 +04:00
|
|
|
#include <asm/system.h>
|
2005-09-13 12:25:34 +04:00
|
|
|
|
|
|
|
#include <asm/mach/arch.h>
|
|
|
|
#include <asm/mach/map.h>
|
|
|
|
#include <asm/mach/irq.h>
|
|
|
|
|
2008-08-05 19:14:15 +04:00
|
|
|
#include <mach/pxa-regs.h>
|
|
|
|
#include <mach/pxa2xx-regs.h>
|
2008-09-03 05:47:42 +04:00
|
|
|
#include <mach/mfp-pxa27x.h>
|
2008-08-05 19:14:15 +04:00
|
|
|
#include <mach/pxa27x-udc.h>
|
2008-08-07 14:05:25 +04:00
|
|
|
#include <mach/reset.h>
|
2008-08-26 16:30:03 +04:00
|
|
|
#include <mach/i2c.h>
|
2008-08-05 19:14:15 +04:00
|
|
|
#include <mach/irda.h>
|
|
|
|
#include <mach/mmc.h>
|
|
|
|
#include <mach/ohci.h>
|
|
|
|
#include <mach/udc.h>
|
|
|
|
#include <mach/pxafb.h>
|
|
|
|
#include <mach/akita.h>
|
|
|
|
#include <mach/spitz.h>
|
|
|
|
#include <mach/sharpsl.h>
|
2005-09-13 12:25:34 +04:00
|
|
|
|
|
|
|
#include <asm/mach/sharpsl_param.h>
|
|
|
|
#include <asm/hardware/scoop.h>
|
|
|
|
|
|
|
|
#include "generic.h"
|
2007-05-15 18:39:36 +04:00
|
|
|
#include "devices.h"
|
2005-09-13 12:25:34 +04:00
|
|
|
#include "sharpsl.h"
|
|
|
|
|
2008-09-03 05:47:42 +04:00
|
|
|
static unsigned long spitz_pin_config[] __initdata = {
|
|
|
|
/* Chip Selects */
|
|
|
|
GPIO78_nCS_2, /* SCOOP #2 */
|
|
|
|
GPIO80_nCS_4, /* SCOOP #1 */
|
|
|
|
|
|
|
|
/* LCD - 16bpp Active TFT */
|
|
|
|
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,
|
|
|
|
|
|
|
|
/* PC Card */
|
|
|
|
GPIO48_nPOE,
|
|
|
|
GPIO49_nPWE,
|
|
|
|
GPIO50_nPIOR,
|
|
|
|
GPIO51_nPIOW,
|
|
|
|
GPIO85_nPCE_1,
|
|
|
|
GPIO54_nPCE_2,
|
|
|
|
GPIO79_PSKTSEL,
|
|
|
|
GPIO55_nPREG,
|
|
|
|
GPIO56_nPWAIT,
|
|
|
|
GPIO57_nIOIS16,
|
|
|
|
|
|
|
|
/* MMC */
|
|
|
|
GPIO32_MMC_CLK,
|
|
|
|
GPIO112_MMC_CMD,
|
|
|
|
GPIO92_MMC_DAT_0,
|
|
|
|
GPIO109_MMC_DAT_1,
|
|
|
|
GPIO110_MMC_DAT_2,
|
|
|
|
GPIO111_MMC_DAT_3,
|
|
|
|
|
|
|
|
/* GPIOs */
|
|
|
|
GPIO9_GPIO, /* SPITZ_GPIO_nSD_DETECT */
|
|
|
|
GPIO81_GPIO, /* SPITZ_GPIO_nSD_WP */
|
|
|
|
GPIO41_GPIO, /* SPITZ_GPIO_USB_CONNECT */
|
|
|
|
GPIO37_GPIO, /* SPITZ_GPIO_USB_HOST */
|
|
|
|
GPIO35_GPIO, /* SPITZ_GPIO_USB_DEVICE */
|
|
|
|
GPIO22_GPIO, /* SPITZ_GPIO_HSYNC */
|
|
|
|
GPIO94_GPIO, /* SPITZ_GPIO_CF_CD */
|
|
|
|
GPIO105_GPIO, /* SPITZ_GPIO_CF_IRQ */
|
|
|
|
GPIO106_GPIO, /* SPITZ_GPIO_CF2_IRQ */
|
|
|
|
|
|
|
|
GPIO1_GPIO | WAKEUP_ON_EDGE_RISE,
|
|
|
|
};
|
|
|
|
|
2005-09-13 12:25:34 +04:00
|
|
|
/*
|
|
|
|
* Spitz SCOOP Device #1
|
|
|
|
*/
|
|
|
|
static struct resource spitz_scoop_resources[] = {
|
|
|
|
[0] = {
|
|
|
|
.start = 0x10800000,
|
|
|
|
.end = 0x10800fff,
|
|
|
|
.flags = IORESOURCE_MEM,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct scoop_config spitz_scoop_setup = {
|
|
|
|
.io_dir = SPITZ_SCP_IO_DIR,
|
|
|
|
.io_out = SPITZ_SCP_IO_OUT,
|
|
|
|
.suspend_clr = SPITZ_SCP_SUS_CLR,
|
|
|
|
.suspend_set = SPITZ_SCP_SUS_SET,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct platform_device spitzscoop_device = {
|
|
|
|
.name = "sharp-scoop",
|
|
|
|
.id = 0,
|
|
|
|
.dev = {
|
|
|
|
.platform_data = &spitz_scoop_setup,
|
|
|
|
},
|
|
|
|
.num_resources = ARRAY_SIZE(spitz_scoop_resources),
|
|
|
|
.resource = spitz_scoop_resources,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Spitz SCOOP Device #2
|
|
|
|
*/
|
|
|
|
static struct resource spitz_scoop2_resources[] = {
|
|
|
|
[0] = {
|
|
|
|
.start = 0x08800040,
|
|
|
|
.end = 0x08800fff,
|
|
|
|
.flags = IORESOURCE_MEM,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct scoop_config spitz_scoop2_setup = {
|
|
|
|
.io_dir = SPITZ_SCP2_IO_DIR,
|
|
|
|
.io_out = SPITZ_SCP2_IO_OUT,
|
|
|
|
.suspend_clr = SPITZ_SCP2_SUS_CLR,
|
|
|
|
.suspend_set = SPITZ_SCP2_SUS_SET,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct platform_device spitzscoop2_device = {
|
|
|
|
.name = "sharp-scoop",
|
|
|
|
.id = 1,
|
|
|
|
.dev = {
|
|
|
|
.platform_data = &spitz_scoop2_setup,
|
|
|
|
},
|
|
|
|
.num_resources = ARRAY_SIZE(spitz_scoop2_resources),
|
|
|
|
.resource = spitz_scoop2_resources,
|
|
|
|
};
|
|
|
|
|
2005-11-08 22:15:43 +03:00
|
|
|
#define SPITZ_PWR_SD 0x01
|
|
|
|
#define SPITZ_PWR_CF 0x02
|
|
|
|
|
|
|
|
/* Power control is shared with between one of the CF slots and SD */
|
|
|
|
static void spitz_card_pwr_ctrl(int device, unsigned short new_cpr)
|
|
|
|
{
|
|
|
|
unsigned short cpr = read_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR);
|
|
|
|
|
|
|
|
if (new_cpr & 0x0007) {
|
|
|
|
set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
|
|
|
|
if (!(cpr & 0x0002) && !(cpr & 0x0004))
|
|
|
|
mdelay(5);
|
|
|
|
if (device == SPITZ_PWR_CF)
|
|
|
|
cpr |= 0x0002;
|
|
|
|
if (device == SPITZ_PWR_SD)
|
|
|
|
cpr |= 0x0004;
|
|
|
|
write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | new_cpr);
|
|
|
|
} else {
|
|
|
|
if (device == SPITZ_PWR_CF)
|
|
|
|
cpr &= ~0x0002;
|
|
|
|
if (device == SPITZ_PWR_SD)
|
|
|
|
cpr &= ~0x0004;
|
|
|
|
if (!(cpr & 0x0002) && !(cpr & 0x0004)) {
|
2006-01-05 23:44:57 +03:00
|
|
|
write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, 0x0000);
|
2005-11-08 22:15:43 +03:00
|
|
|
mdelay(1);
|
|
|
|
reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER);
|
2006-01-05 23:44:57 +03:00
|
|
|
} else {
|
|
|
|
write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | new_cpr);
|
2005-11-08 22:15:43 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void spitz_pcmcia_pwr(struct device *scoop, unsigned short cpr, int nr)
|
|
|
|
{
|
|
|
|
/* Only need to override behaviour for slot 0 */
|
|
|
|
if (nr == 0)
|
|
|
|
spitz_card_pwr_ctrl(SPITZ_PWR_CF, cpr);
|
|
|
|
else
|
|
|
|
write_scoop_reg(scoop, SCOOP_CPR, cpr);
|
|
|
|
}
|
|
|
|
|
2005-09-13 12:25:34 +04:00
|
|
|
static struct scoop_pcmcia_dev spitz_pcmcia_scoop[] = {
|
|
|
|
{
|
|
|
|
.dev = &spitzscoop_device.dev,
|
|
|
|
.irq = SPITZ_IRQ_GPIO_CF_IRQ,
|
|
|
|
.cd_irq = SPITZ_IRQ_GPIO_CF_CD,
|
|
|
|
.cd_irq_str = "PCMCIA0 CD",
|
|
|
|
},{
|
|
|
|
.dev = &spitzscoop2_device.dev,
|
|
|
|
.irq = SPITZ_IRQ_GPIO_CF2_IRQ,
|
|
|
|
.cd_irq = -1,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2005-11-08 22:15:43 +03:00
|
|
|
static struct scoop_pcmcia_config spitz_pcmcia_config = {
|
|
|
|
.devs = &spitz_pcmcia_scoop[0],
|
|
|
|
.num_devs = 2,
|
|
|
|
.power_ctrl = spitz_pcmcia_pwr,
|
|
|
|
};
|
|
|
|
|
|
|
|
EXPORT_SYMBOL(spitzscoop_device);
|
|
|
|
EXPORT_SYMBOL(spitzscoop2_device);
|
|
|
|
|
2005-09-13 12:25:34 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Spitz SSP Device
|
|
|
|
*
|
|
|
|
* Set the parent as the scoop device because a lot of SSP devices
|
|
|
|
* also use scoop functions and this makes the power up/down order
|
|
|
|
* work correctly.
|
|
|
|
*/
|
|
|
|
struct platform_device spitzssp_device = {
|
|
|
|
.name = "corgi-ssp",
|
|
|
|
.dev = {
|
|
|
|
.parent = &spitzscoop_device.dev,
|
|
|
|
},
|
|
|
|
.id = -1,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct corgissp_machinfo spitz_ssp_machinfo = {
|
|
|
|
.port = 2,
|
|
|
|
.cs_lcdcon = SPITZ_GPIO_LCDCON_CS,
|
|
|
|
.cs_ads7846 = SPITZ_GPIO_ADS7846_CS,
|
|
|
|
.cs_max1111 = SPITZ_GPIO_MAX1111_CS,
|
|
|
|
.clk_lcdcon = 520,
|
|
|
|
.clk_ads7846 = 14,
|
|
|
|
.clk_max1111 = 56,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Spitz Backlight Device
|
|
|
|
*/
|
2007-09-03 03:27:00 +04:00
|
|
|
static void spitz_bl_kick_battery(void)
|
|
|
|
{
|
|
|
|
void (*kick_batt)(void);
|
|
|
|
|
|
|
|
kick_batt = symbol_get(sharpsl_battery_kick);
|
|
|
|
if (kick_batt) {
|
|
|
|
kick_batt();
|
|
|
|
symbol_put(sharpsl_battery_kick);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct generic_bl_info spitz_bl_machinfo = {
|
|
|
|
.name = "corgi-bl",
|
2006-03-31 14:31:51 +04:00
|
|
|
.default_intensity = 0x1f,
|
|
|
|
.limit_mask = 0x0b,
|
2005-09-13 12:25:34 +04:00
|
|
|
.max_intensity = 0x2f,
|
2007-09-03 03:27:00 +04:00
|
|
|
.kick_battery = spitz_bl_kick_battery,
|
2005-09-13 12:25:34 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct platform_device spitzbl_device = {
|
2007-09-03 03:27:00 +04:00
|
|
|
.name = "generic-bl",
|
2005-09-13 12:25:34 +04:00
|
|
|
.dev = {
|
|
|
|
.platform_data = &spitz_bl_machinfo,
|
|
|
|
},
|
|
|
|
.id = -1,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Spitz Keyboard Device
|
|
|
|
*/
|
|
|
|
static struct platform_device spitzkbd_device = {
|
|
|
|
.name = "spitz-keyboard",
|
|
|
|
.id = -1,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2006-03-31 14:31:09 +04:00
|
|
|
/*
|
|
|
|
* Spitz LEDs
|
|
|
|
*/
|
|
|
|
static struct platform_device spitzled_device = {
|
|
|
|
.name = "spitz-led",
|
|
|
|
.id = -1,
|
|
|
|
};
|
|
|
|
|
2005-09-13 12:25:34 +04:00
|
|
|
/*
|
|
|
|
* Spitz Touch Screen Device
|
|
|
|
*/
|
2008-01-02 03:09:54 +03:00
|
|
|
|
|
|
|
static unsigned long (*get_hsync_invperiod)(struct device *dev);
|
|
|
|
|
|
|
|
static void inline sharpsl_wait_sync(int gpio)
|
|
|
|
{
|
|
|
|
while((GPLR(gpio) & GPIO_bit(gpio)) == 0);
|
|
|
|
while((GPLR(gpio) & GPIO_bit(gpio)) != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct device *spitz_pxafb_dev;
|
|
|
|
|
|
|
|
static int is_pxafb_device(struct device * dev, void * data)
|
|
|
|
{
|
|
|
|
struct platform_device *pdev = container_of(dev, struct platform_device, dev);
|
|
|
|
|
|
|
|
return (strncmp(pdev->name, "pxa2xx-fb", 9) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned long spitz_get_hsync_invperiod(void)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_FB_PXA
|
|
|
|
if (!spitz_pxafb_dev) {
|
|
|
|
spitz_pxafb_dev = bus_find_device(&platform_bus_type, NULL, NULL, is_pxafb_device);
|
|
|
|
if (!spitz_pxafb_dev)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!get_hsync_invperiod)
|
|
|
|
get_hsync_invperiod = symbol_get(pxafb_get_hsync_time);
|
|
|
|
if (!get_hsync_invperiod)
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return get_hsync_invperiod(spitz_pxafb_dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void spitz_put_hsync(void)
|
|
|
|
{
|
|
|
|
put_device(spitz_pxafb_dev);
|
|
|
|
if (get_hsync_invperiod)
|
|
|
|
symbol_put(pxafb_get_hsync_time);
|
|
|
|
spitz_pxafb_dev = NULL;
|
|
|
|
get_hsync_invperiod = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void spitz_wait_hsync(void)
|
|
|
|
{
|
|
|
|
sharpsl_wait_sync(SPITZ_GPIO_HSYNC);
|
|
|
|
}
|
|
|
|
|
2005-09-13 12:25:34 +04:00
|
|
|
static struct resource spitzts_resources[] = {
|
|
|
|
[0] = {
|
|
|
|
.start = SPITZ_IRQ_GPIO_TP_INT,
|
|
|
|
.end = SPITZ_IRQ_GPIO_TP_INT,
|
|
|
|
.flags = IORESOURCE_IRQ,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct corgits_machinfo spitz_ts_machinfo = {
|
2008-01-02 03:09:54 +03:00
|
|
|
.get_hsync_invperiod = spitz_get_hsync_invperiod,
|
|
|
|
.put_hsync = spitz_put_hsync,
|
|
|
|
.wait_hsync = spitz_wait_hsync,
|
2005-09-13 12:25:34 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct platform_device spitzts_device = {
|
|
|
|
.name = "corgi-ts",
|
|
|
|
.dev = {
|
|
|
|
.parent = &spitzssp_device.dev,
|
|
|
|
.platform_data = &spitz_ts_machinfo,
|
|
|
|
},
|
|
|
|
.id = -1,
|
|
|
|
.num_resources = ARRAY_SIZE(spitzts_resources),
|
|
|
|
.resource = spitzts_resources,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* MMC/SD Device
|
|
|
|
*
|
|
|
|
* The card detect interrupt isn't debounced so we delay it by 250ms
|
|
|
|
* to give the card a chance to fully insert/eject.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static struct pxamci_platform_data spitz_mci_platform_data;
|
|
|
|
|
2006-10-09 15:19:47 +04:00
|
|
|
static int spitz_mci_init(struct device *dev, irq_handler_t spitz_detect_int, void *data)
|
2005-09-13 12:25:34 +04:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2008-09-02 13:34:33 +04:00
|
|
|
err = gpio_request(SPITZ_GPIO_nSD_DETECT, "nSD_DETECT");
|
|
|
|
if (err)
|
|
|
|
goto err_out;
|
|
|
|
|
|
|
|
err = gpio_request(SPITZ_GPIO_nSD_WP, "nSD_WP");
|
|
|
|
if (err)
|
|
|
|
goto err_free_1;
|
|
|
|
|
|
|
|
gpio_direction_input(SPITZ_GPIO_nSD_DETECT);
|
|
|
|
gpio_direction_input(SPITZ_GPIO_nSD_WP);
|
2005-09-13 12:25:34 +04:00
|
|
|
|
|
|
|
spitz_mci_platform_data.detect_delay = msecs_to_jiffies(250);
|
|
|
|
|
[PATCH] IRQ type flags
Some ARM platforms have the ability to program the interrupt controller to
detect various interrupt edges and/or levels. For some platforms, this is
critical to setup correctly, particularly those which the setting is dependent
on the device.
Currently, ARM drivers do (eg) the following:
err = request_irq(irq, ...);
set_irq_type(irq, IRQT_RISING);
However, if the interrupt has previously been programmed to be level sensitive
(for whatever reason) then this will cause an interrupt storm.
Hence, if we combine set_irq_type() with request_irq(), we can then safely set
the type prior to unmasking the interrupt. The unfortunate problem is that in
order to support this, these flags need to be visible outside of the ARM
architecture - drivers such as smc91x need these flags and they're
cross-architecture.
Finally, the SA_TRIGGER_* flag passed to request_irq() should reflect the
property that the device would like. The IRQ controller code should do its
best to select the most appropriate supported mode.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-08 12:02:07 +03:00
|
|
|
err = request_irq(SPITZ_IRQ_GPIO_nSD_DETECT, spitz_detect_int,
|
2008-09-02 13:34:33 +04:00
|
|
|
IRQF_DISABLED | IRQF_TRIGGER_RISING |
|
|
|
|
IRQF_TRIGGER_FALLING,
|
[PATCH] IRQ type flags
Some ARM platforms have the ability to program the interrupt controller to
detect various interrupt edges and/or levels. For some platforms, this is
critical to setup correctly, particularly those which the setting is dependent
on the device.
Currently, ARM drivers do (eg) the following:
err = request_irq(irq, ...);
set_irq_type(irq, IRQT_RISING);
However, if the interrupt has previously been programmed to be level sensitive
(for whatever reason) then this will cause an interrupt storm.
Hence, if we combine set_irq_type() with request_irq(), we can then safely set
the type prior to unmasking the interrupt. The unfortunate problem is that in
order to support this, these flags need to be visible outside of the ARM
architecture - drivers such as smc91x need these flags and they're
cross-architecture.
Finally, the SA_TRIGGER_* flag passed to request_irq() should reflect the
property that the device would like. The IRQ controller code should do its
best to select the most appropriate supported mode.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-01-08 12:02:07 +03:00
|
|
|
"MMC card detect", data);
|
2008-09-02 13:34:33 +04:00
|
|
|
if (err) {
|
|
|
|
pr_err("%s: MMC/SD: can't request MMC card detect IRQ\n",
|
|
|
|
__func__);
|
|
|
|
goto err_free_2;
|
|
|
|
}
|
|
|
|
return 0;
|
2005-09-13 12:25:34 +04:00
|
|
|
|
2008-09-02 13:34:33 +04:00
|
|
|
err_free_2:
|
|
|
|
gpio_free(SPITZ_GPIO_nSD_WP);
|
|
|
|
err_free_1:
|
|
|
|
gpio_free(SPITZ_GPIO_nSD_DETECT);
|
|
|
|
err_out:
|
2008-01-23 17:05:58 +03:00
|
|
|
return err;
|
2005-09-13 12:25:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void spitz_mci_setpower(struct device *dev, unsigned int vdd)
|
|
|
|
{
|
|
|
|
struct pxamci_platform_data* p_d = dev->platform_data;
|
|
|
|
|
2005-11-08 22:15:43 +03:00
|
|
|
if (( 1 << vdd) & p_d->ocr_mask)
|
|
|
|
spitz_card_pwr_ctrl(SPITZ_PWR_SD, 0x0004);
|
|
|
|
else
|
|
|
|
spitz_card_pwr_ctrl(SPITZ_PWR_SD, 0x0000);
|
2005-09-13 12:25:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int spitz_mci_get_ro(struct device *dev)
|
|
|
|
{
|
2008-09-02 13:34:33 +04:00
|
|
|
return gpio_get_value(SPITZ_GPIO_nSD_WP);
|
2005-09-13 12:25:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void spitz_mci_exit(struct device *dev, void *data)
|
|
|
|
{
|
|
|
|
free_irq(SPITZ_IRQ_GPIO_nSD_DETECT, data);
|
2008-09-02 13:34:33 +04:00
|
|
|
gpio_free(SPITZ_GPIO_nSD_WP);
|
|
|
|
gpio_free(SPITZ_GPIO_nSD_DETECT);
|
2005-09-13 12:25:34 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct pxamci_platform_data spitz_mci_platform_data = {
|
|
|
|
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
|
|
|
|
.init = spitz_mci_init,
|
|
|
|
.get_ro = spitz_mci_get_ro,
|
|
|
|
.setpower = spitz_mci_setpower,
|
|
|
|
.exit = spitz_mci_exit,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2006-01-05 23:44:52 +03:00
|
|
|
/*
|
|
|
|
* USB Host (OHCI)
|
|
|
|
*/
|
|
|
|
static int spitz_ohci_init(struct device *dev)
|
|
|
|
{
|
2008-09-02 13:34:33 +04:00
|
|
|
int err;
|
|
|
|
|
|
|
|
err = gpio_request(SPITZ_GPIO_USB_HOST, "USB_HOST");
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2008-09-03 05:47:42 +04:00
|
|
|
/* Only Port 2 is connected
|
|
|
|
* Setup USB Port 2 Output Control Register
|
|
|
|
*/
|
2006-01-05 23:44:52 +03:00
|
|
|
UP2OCR = UP2OCR_HXS | UP2OCR_HXOE | UP2OCR_DPPDE | UP2OCR_DMPDE;
|
|
|
|
|
2008-09-02 13:34:33 +04:00
|
|
|
gpio_direction_output(SPITZ_GPIO_USB_HOST, 1);
|
2006-01-05 23:44:52 +03:00
|
|
|
|
|
|
|
UHCHR = (UHCHR) &
|
|
|
|
~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE);
|
|
|
|
|
|
|
|
UHCRHDA |= UHCRHDA_NOCP;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct pxaohci_platform_data spitz_ohci_platform_data = {
|
|
|
|
.port_mode = PMM_NPS_MODE,
|
|
|
|
.init = spitz_ohci_init,
|
2006-06-09 01:44:07 +04:00
|
|
|
.power_budget = 150,
|
2006-01-05 23:44:52 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2005-10-30 17:50:25 +03:00
|
|
|
/*
|
|
|
|
* Irda
|
|
|
|
*/
|
|
|
|
static void spitz_irda_transceiver_mode(struct device *dev, int mode)
|
|
|
|
{
|
|
|
|
if (mode & IR_OFF)
|
|
|
|
set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_IR_ON);
|
|
|
|
else
|
|
|
|
reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_IR_ON);
|
2008-07-02 16:54:46 +04:00
|
|
|
pxa2xx_transceiver_mode(dev, mode);
|
2005-10-30 17:50:25 +03:00
|
|
|
}
|
|
|
|
|
2005-11-12 21:53:48 +03:00
|
|
|
#ifdef CONFIG_MACH_AKITA
|
|
|
|
static void akita_irda_transceiver_mode(struct device *dev, int mode)
|
|
|
|
{
|
|
|
|
if (mode & IR_OFF)
|
|
|
|
akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_IR_ON);
|
|
|
|
else
|
|
|
|
akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_IR_ON);
|
2008-07-02 16:54:46 +04:00
|
|
|
pxa2xx_transceiver_mode(dev, mode);
|
2005-11-12 21:53:48 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-10-30 17:50:25 +03:00
|
|
|
static struct pxaficp_platform_data spitz_ficp_platform_data = {
|
|
|
|
.transceiver_cap = IR_SIRMODE | IR_OFF,
|
|
|
|
.transceiver_mode = spitz_irda_transceiver_mode,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2005-09-13 12:25:34 +04:00
|
|
|
/*
|
|
|
|
* Spitz PXA Framebuffer
|
|
|
|
*/
|
2006-09-21 01:54:21 +04:00
|
|
|
|
2008-01-02 03:09:54 +03:00
|
|
|
static void spitz_lcd_power(int on, struct fb_var_screeninfo *var)
|
|
|
|
{
|
|
|
|
if (on)
|
|
|
|
corgi_lcdtg_hw_init(var->xres);
|
|
|
|
else
|
|
|
|
corgi_lcdtg_suspend();
|
|
|
|
}
|
|
|
|
|
2006-09-21 01:54:21 +04:00
|
|
|
static struct pxafb_mode_info spitz_pxafb_modes[] = {
|
|
|
|
{
|
|
|
|
.pixclock = 19231,
|
|
|
|
.xres = 480,
|
|
|
|
.yres = 640,
|
|
|
|
.bpp = 16,
|
|
|
|
.hsync_len = 40,
|
|
|
|
.left_margin = 46,
|
|
|
|
.right_margin = 125,
|
|
|
|
.vsync_len = 3,
|
|
|
|
.upper_margin = 1,
|
|
|
|
.lower_margin = 0,
|
|
|
|
.sync = 0,
|
|
|
|
},{
|
|
|
|
.pixclock = 134617,
|
|
|
|
.xres = 240,
|
|
|
|
.yres = 320,
|
|
|
|
.bpp = 16,
|
|
|
|
.hsync_len = 20,
|
|
|
|
.left_margin = 20,
|
|
|
|
.right_margin = 46,
|
|
|
|
.vsync_len = 2,
|
|
|
|
.upper_margin = 1,
|
|
|
|
.lower_margin = 0,
|
|
|
|
.sync = 0,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct pxafb_mach_info spitz_pxafb_info = {
|
|
|
|
.modes = &spitz_pxafb_modes[0],
|
|
|
|
.num_modes = 2,
|
|
|
|
.fixed_modes = 1,
|
2008-09-03 06:00:38 +04:00
|
|
|
.lcd_conn = LCD_COLOR_TFT_16BPP | LCD_ALTERNATE_MAPPING,
|
2006-09-21 01:54:21 +04:00
|
|
|
.pxafb_lcd_power = spitz_lcd_power,
|
2005-09-13 12:25:34 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static struct platform_device *devices[] __initdata = {
|
|
|
|
&spitzscoop_device,
|
|
|
|
&spitzssp_device,
|
|
|
|
&spitzkbd_device,
|
|
|
|
&spitzts_device,
|
|
|
|
&spitzbl_device,
|
2006-03-31 14:31:09 +04:00
|
|
|
&spitzled_device,
|
2005-09-13 12:25:34 +04:00
|
|
|
};
|
|
|
|
|
2006-06-19 22:57:12 +04:00
|
|
|
static void spitz_poweroff(void)
|
|
|
|
{
|
2008-05-22 19:21:48 +04:00
|
|
|
arm_machine_restart('g');
|
2006-06-19 22:57:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void spitz_restart(char mode)
|
|
|
|
{
|
|
|
|
/* Bootloader magic for a reboot */
|
|
|
|
if((MSC0 & 0xffff0000) == 0x7ff00000)
|
|
|
|
MSC0 = (MSC0 & 0xffff) | 0x7ee00000;
|
|
|
|
|
|
|
|
spitz_poweroff();
|
|
|
|
}
|
|
|
|
|
2005-09-13 12:25:34 +04:00
|
|
|
static void __init common_init(void)
|
|
|
|
{
|
2008-05-22 19:21:48 +04:00
|
|
|
init_gpio_reset(SPITZ_GPIO_ON_RESET);
|
2006-06-19 22:57:12 +04:00
|
|
|
pm_power_off = spitz_poweroff;
|
|
|
|
arm_pm_restart = spitz_restart;
|
|
|
|
|
2005-09-13 12:25:34 +04:00
|
|
|
PMCR = 0x00;
|
|
|
|
|
|
|
|
/* Stop 3.6MHz and drive HIGH to PCMCIA and CS */
|
|
|
|
PCFR |= PCFR_OPDE;
|
|
|
|
|
2008-09-03 05:47:42 +04:00
|
|
|
pxa2xx_mfp_config(ARRAY_AND_SIZE(spitz_pin_config));
|
2005-09-13 12:25:34 +04:00
|
|
|
|
2008-09-03 05:47:42 +04:00
|
|
|
corgi_ssp_set_machinfo(&spitz_ssp_machinfo);
|
2005-09-13 12:25:34 +04:00
|
|
|
|
|
|
|
platform_add_devices(devices, ARRAY_SIZE(devices));
|
|
|
|
pxa_set_mci_info(&spitz_mci_platform_data);
|
2006-01-05 23:44:52 +03:00
|
|
|
pxa_set_ohci_info(&spitz_ohci_platform_data);
|
2005-10-30 17:50:25 +03:00
|
|
|
pxa_set_ficp_info(&spitz_ficp_platform_data);
|
2005-10-14 19:07:25 +04:00
|
|
|
set_pxa_fb_parent(&spitzssp_device.dev);
|
2005-09-13 12:25:34 +04:00
|
|
|
set_pxa_fb_info(&spitz_pxafb_info);
|
2008-08-26 16:30:03 +04:00
|
|
|
pxa_set_i2c_info(NULL);
|
2005-09-13 12:25:34 +04:00
|
|
|
}
|
|
|
|
|
2008-01-02 03:09:54 +03:00
|
|
|
#if defined(CONFIG_MACH_SPITZ) || defined(CONFIG_MACH_BORZOI)
|
|
|
|
static void spitz_bl_set_intensity(int intensity)
|
|
|
|
{
|
|
|
|
if (intensity > 0x10)
|
|
|
|
intensity += 0x10;
|
|
|
|
|
|
|
|
/* Bits 0-4 are accessed via the SSP interface */
|
|
|
|
corgi_ssp_blduty_set(intensity & 0x1f);
|
|
|
|
|
|
|
|
/* Bit 5 is via SCOOP */
|
|
|
|
if (intensity & 0x0020)
|
|
|
|
reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_CONT);
|
|
|
|
else
|
|
|
|
set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_CONT);
|
|
|
|
|
|
|
|
if (intensity)
|
|
|
|
set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_ON);
|
|
|
|
else
|
|
|
|
reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_ON);
|
|
|
|
}
|
|
|
|
|
2005-09-13 12:25:34 +04:00
|
|
|
static void __init spitz_init(void)
|
|
|
|
{
|
2005-11-08 22:15:43 +03:00
|
|
|
platform_scoop_config = &spitz_pcmcia_config;
|
|
|
|
|
2005-09-13 12:25:34 +04:00
|
|
|
spitz_bl_machinfo.set_bl_intensity = spitz_bl_set_intensity;
|
|
|
|
|
|
|
|
common_init();
|
|
|
|
|
|
|
|
platform_device_register(&spitzscoop2_device);
|
|
|
|
}
|
2008-01-02 03:09:54 +03:00
|
|
|
#endif
|
2005-09-13 12:25:34 +04:00
|
|
|
|
2005-11-12 21:53:48 +03:00
|
|
|
#ifdef CONFIG_MACH_AKITA
|
|
|
|
/*
|
|
|
|
* Akita IO Expander
|
|
|
|
*/
|
|
|
|
struct platform_device akitaioexp_device = {
|
|
|
|
.name = "akita-ioexp",
|
|
|
|
.id = -1,
|
|
|
|
};
|
|
|
|
|
2006-03-27 00:40:27 +04:00
|
|
|
EXPORT_SYMBOL_GPL(akitaioexp_device);
|
|
|
|
|
2008-01-02 03:09:54 +03:00
|
|
|
static void akita_bl_set_intensity(int intensity)
|
|
|
|
{
|
|
|
|
if (intensity > 0x10)
|
|
|
|
intensity += 0x10;
|
|
|
|
|
|
|
|
/* Bits 0-4 are accessed via the SSP interface */
|
|
|
|
corgi_ssp_blduty_set(intensity & 0x1f);
|
|
|
|
|
|
|
|
/* Bit 5 is via IO-Expander */
|
|
|
|
if (intensity & 0x0020)
|
|
|
|
akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_CONT);
|
|
|
|
else
|
|
|
|
akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_CONT);
|
|
|
|
|
|
|
|
if (intensity)
|
|
|
|
akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_ON);
|
|
|
|
else
|
|
|
|
akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_ON);
|
|
|
|
}
|
|
|
|
|
2005-11-12 21:53:48 +03:00
|
|
|
static void __init akita_init(void)
|
|
|
|
{
|
|
|
|
spitz_ficp_platform_data.transceiver_mode = akita_irda_transceiver_mode;
|
|
|
|
|
|
|
|
/* We just pretend the second element of the array doesn't exist */
|
|
|
|
spitz_pcmcia_config.num_devs = 1;
|
|
|
|
platform_scoop_config = &spitz_pcmcia_config;
|
|
|
|
spitz_bl_machinfo.set_bl_intensity = akita_bl_set_intensity;
|
|
|
|
|
|
|
|
platform_device_register(&akitaioexp_device);
|
|
|
|
|
|
|
|
spitzscoop_device.dev.parent = &akitaioexp_device.dev;
|
|
|
|
common_init();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-09-13 12:25:34 +04:00
|
|
|
static void __init fixup_spitz(struct machine_desc *desc,
|
|
|
|
struct tag *tags, char **cmdline, struct meminfo *mi)
|
|
|
|
{
|
|
|
|
sharpsl_save_param();
|
|
|
|
mi->nr_banks = 1;
|
|
|
|
mi->bank[0].start = 0xa0000000;
|
|
|
|
mi->bank[0].node = 0;
|
|
|
|
mi->bank[0].size = (64*1024*1024);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_MACH_SPITZ
|
|
|
|
MACHINE_START(SPITZ, "SHARP Spitz")
|
|
|
|
.phys_io = 0x40000000,
|
|
|
|
.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
|
|
|
|
.fixup = fixup_spitz,
|
|
|
|
.map_io = pxa_map_io,
|
2007-06-22 07:14:09 +04:00
|
|
|
.init_irq = pxa27x_init_irq,
|
2005-09-13 12:25:34 +04:00
|
|
|
.init_machine = spitz_init,
|
|
|
|
.timer = &pxa_timer,
|
|
|
|
MACHINE_END
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_MACH_BORZOI
|
|
|
|
MACHINE_START(BORZOI, "SHARP Borzoi")
|
|
|
|
.phys_io = 0x40000000,
|
|
|
|
.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
|
|
|
|
.fixup = fixup_spitz,
|
|
|
|
.map_io = pxa_map_io,
|
2007-06-22 07:14:09 +04:00
|
|
|
.init_irq = pxa27x_init_irq,
|
2005-09-13 12:25:34 +04:00
|
|
|
.init_machine = spitz_init,
|
|
|
|
.timer = &pxa_timer,
|
|
|
|
MACHINE_END
|
|
|
|
#endif
|
2005-11-12 21:53:48 +03:00
|
|
|
|
|
|
|
#ifdef CONFIG_MACH_AKITA
|
|
|
|
MACHINE_START(AKITA, "SHARP Akita")
|
|
|
|
.phys_io = 0x40000000,
|
|
|
|
.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
|
|
|
|
.fixup = fixup_spitz,
|
|
|
|
.map_io = pxa_map_io,
|
2007-06-22 07:14:09 +04:00
|
|
|
.init_irq = pxa27x_init_irq,
|
2005-11-12 21:53:48 +03:00
|
|
|
.init_machine = akita_init,
|
|
|
|
.timer = &pxa_timer,
|
|
|
|
MACHINE_END
|
|
|
|
#endif
|