提交 7fecc34e 编写于 作者: R Russell King 提交者: Russell King

Merge branch 'pxa-tosa' into pxa

Conflicts:

	arch/arm/mach-pxa/Kconfig
	arch/arm/mach-pxa/tosa.c
	arch/arm/mach-pxa/spitz.c
......@@ -584,6 +584,8 @@ L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
S: Maintained
ARM/TOSA MACHINE SUPPORT
P: Dmitry Baryshkov
M: dbaryshkov@gmail.com
P: Dirk Opfer
M: dirk@opfer-online.de
S: Maintained
......
......@@ -310,4 +310,13 @@ config PXA_PWM
default BACKLIGHT_PWM
help
Enable support for PXA2xx/PXA3xx PWM controllers
config TOSA_BT
tristate "Control the state of built-in bluetooth chip on Sharp SL-6000"
depends on MACH_TOSA
select RFKILL
help
This is a simple driver that is able to control
the state of built in bluetooth chip on tosa.
endif
......@@ -4,7 +4,7 @@
# Common support (must be linked before board specific support)
obj-y += clock.o devices.o generic.o irq.o dma.o \
time.o gpio.o
time.o gpio.o reset.o
obj-$(CONFIG_PM) += pm.o sleep.o standby.o
obj-$(CONFIG_CPU_FREQ) += cpu-pxa.o
......@@ -61,3 +61,5 @@ obj-$(CONFIG_LEDS) += $(led-y)
ifeq ($(CONFIG_PCI),y)
obj-$(CONFIG_MACH_ARMCORE) += cm-x270-pci.o
endif
obj-$(CONFIG_TOSA_BT) += tosa-bt.o
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <asm/io.h>
#include <asm/proc-fns.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/pxa2xx-regs.h>
static void do_hw_reset(void);
static int reset_gpio = -1;
int init_gpio_reset(int gpio)
{
int rc;
rc = gpio_request(gpio, "reset generator");
if (rc) {
printk(KERN_ERR "Can't request reset_gpio\n");
goto out;
}
rc = gpio_direction_input(gpio);
if (rc) {
printk(KERN_ERR "Can't configure reset_gpio for input\n");
gpio_free(gpio);
goto out;
}
out:
if (!rc)
reset_gpio = gpio;
return rc;
}
/*
* Trigger GPIO reset.
* This covers various types of logic connecting gpio pin
* to RESET pins (nRESET or GPIO_RESET):
*/
static void do_gpio_reset(void)
{
BUG_ON(reset_gpio == -1);
/* drive it low */
gpio_direction_output(reset_gpio, 0);
mdelay(2);
/* rising edge or drive high */
gpio_set_value(reset_gpio, 1);
mdelay(2);
/* falling edge */
gpio_set_value(reset_gpio, 0);
/* give it some time */
mdelay(10);
WARN_ON(1);
/* fallback */
do_hw_reset();
}
static void do_hw_reset(void)
{
/* Initialize the watchdog and let it fire */
OWER = OWER_WME;
OSSR = OSSR_M3;
OSMR3 = OSCR + 368640; /* ... in 100 ms */
}
void arch_reset(char mode)
{
if (cpu_is_pxa2xx())
RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR;
switch (mode) {
case 's':
/* Jump into ROM at address 0 */
cpu_reset(0);
break;
case 'h':
do_hw_reset();
break;
case 'g':
do_gpio_reset();
break;
}
}
......@@ -38,6 +38,7 @@
#include <asm/arch/pxa-regs.h>
#include <asm/arch/pxa2xx-regs.h>
#include <asm/arch/pxa2xx-gpio.h>
#include <asm/arch/pxa27x-udc.h>
#include <asm/arch/irda.h>
#include <asm/arch/mmc.h>
#include <asm/arch/ohci.h>
......@@ -529,11 +530,7 @@ static struct platform_device *devices[] __initdata = {
static void spitz_poweroff(void)
{
pxa_gpio_mode(SPITZ_GPIO_ON_RESET | GPIO_OUT);
GPSR(SPITZ_GPIO_ON_RESET) = GPIO_bit(SPITZ_GPIO_ON_RESET);
mdelay(1000);
arm_machine_restart('h');
arm_machine_restart('g');
}
static void spitz_restart(char mode)
......@@ -547,6 +544,7 @@ static void spitz_restart(char mode)
static void __init common_init(void)
{
init_gpio_reset(SPITZ_GPIO_ON_RESET);
pm_power_off = spitz_poweroff;
arm_pm_restart = spitz_restart;
......
/*
* Bluetooth built-in chip control
*
* Copyright (c) 2008 Dmitry Baryshkov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/rfkill.h>
#include <asm/arch/tosa_bt.h>
static void tosa_bt_on(struct tosa_bt_data *data)
{
gpio_set_value(data->gpio_reset, 0);
gpio_set_value(data->gpio_pwr, 1);
gpio_set_value(data->gpio_reset, 1);
mdelay(20);
gpio_set_value(data->gpio_reset, 0);
}
static void tosa_bt_off(struct tosa_bt_data *data)
{
gpio_set_value(data->gpio_reset, 1);
mdelay(10);
gpio_set_value(data->gpio_pwr, 0);
gpio_set_value(data->gpio_reset, 0);
}
static int tosa_bt_toggle_radio(void *data, enum rfkill_state state)
{
pr_info("BT_RADIO going: %s\n",
state == RFKILL_STATE_ON ? "on" : "off");
if (state == RFKILL_STATE_ON) {
pr_info("TOSA_BT: going ON\n");
tosa_bt_on(data);
} else {
pr_info("TOSA_BT: going OFF\n");
tosa_bt_off(data);
}
return 0;
}
static int tosa_bt_probe(struct platform_device *dev)
{
int rc;
struct rfkill *rfk;
struct tosa_bt_data *data = dev->dev.platform_data;
rc = gpio_request(data->gpio_reset, "Bluetooth reset");
if (rc)
goto err_reset;
rc = gpio_direction_output(data->gpio_reset, 0);
if (rc)
goto err_reset_dir;
rc = gpio_request(data->gpio_pwr, "Bluetooth power");
if (rc)
goto err_pwr;
rc = gpio_direction_output(data->gpio_pwr, 0);
if (rc)
goto err_pwr_dir;
rfk = rfkill_allocate(&dev->dev, RFKILL_TYPE_BLUETOOTH);
if (!rfk) {
rc = -ENOMEM;
goto err_rfk_alloc;
}
rfk->name = "tosa-bt";
rfk->toggle_radio = tosa_bt_toggle_radio;
rfk->data = data;
#ifdef CONFIG_RFKILL_LEDS
rfk->led_trigger.name = "tosa-bt";
#endif
rc = rfkill_register(rfk);
if (rc)
goto err_rfkill;
platform_set_drvdata(dev, rfk);
return 0;
err_rfkill:
if (rfk)
rfkill_free(rfk);
rfk = NULL;
err_rfk_alloc:
tosa_bt_off(data);
err_pwr_dir:
gpio_free(data->gpio_pwr);
err_pwr:
err_reset_dir:
gpio_free(data->gpio_reset);
err_reset:
return rc;
}
static int __devexit tosa_bt_remove(struct platform_device *dev)
{
struct tosa_bt_data *data = dev->dev.platform_data;
struct rfkill *rfk = platform_get_drvdata(dev);
platform_set_drvdata(dev, NULL);
if (rfk)
rfkill_unregister(rfk);
rfk = NULL;
tosa_bt_off(data);
gpio_free(data->gpio_pwr);
gpio_free(data->gpio_reset);
return 0;
}
static struct platform_driver tosa_bt_driver = {
.probe = tosa_bt_probe,
.remove = __devexit_p(tosa_bt_remove),
.driver = {
.name = "tosa-bt",
.owner = THIS_MODULE,
},
};
static int __init tosa_bt_init(void)
{
return platform_driver_register(&tosa_bt_driver);
}
static void __exit tosa_bt_exit(void)
{
platform_driver_unregister(&tosa_bt_driver);
}
module_init(tosa_bt_init);
module_exit(tosa_bt_exit);
......@@ -18,30 +18,31 @@
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/mmc/host.h>
#include <linux/mfd/tc6393xb.h>
#include <linux/mfd/tmio.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/pm.h>
#include <linux/delay.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/pda_power.h>
#include <linux/rfkill.h>
#include <asm/setup.h>
#include <asm/memory.h>
#include <asm/mach-types.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/pxa2xx-regs.h>
#include <asm/arch/mfp-pxa25x.h>
#include <asm/arch/irda.h>
#include <asm/arch/i2c.h>
#include <asm/arch/mmc.h>
#include <asm/arch/udc.h>
#include <asm/arch/tosa_bt.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
#include <asm/arch/tosa.h>
#include <asm/hardware/scoop.h>
......@@ -86,7 +87,7 @@ static unsigned long tosa_pin_config[] = {
GPIO6_MMC_CLK,
GPIO8_MMC_CS0,
GPIO9_GPIO, /* Detect */
// GPIO10 nSD_INT
GPIO10_GPIO, /* nSD_INT */
/* CF */
GPIO13_GPIO, /* CD_IRQ */
......@@ -124,29 +125,25 @@ static unsigned long tosa_pin_config[] = {
GPIO44_BTUART_CTS,
GPIO45_BTUART_RTS,
/* IrDA */
GPIO46_STUART_RXD,
GPIO47_STUART_TXD,
/* Keybd */
GPIO58_GPIO,
GPIO59_GPIO,
GPIO60_GPIO,
GPIO61_GPIO,
GPIO62_GPIO,
GPIO63_GPIO,
GPIO64_GPIO,
GPIO65_GPIO,
GPIO66_GPIO,
GPIO67_GPIO,
GPIO68_GPIO,
GPIO69_GPIO,
GPIO70_GPIO,
GPIO71_GPIO,
GPIO72_GPIO,
GPIO73_GPIO,
GPIO74_GPIO,
GPIO75_GPIO,
GPIO58_GPIO | MFP_LPM_DRIVE_LOW,
GPIO59_GPIO | MFP_LPM_DRIVE_LOW,
GPIO60_GPIO | MFP_LPM_DRIVE_LOW,
GPIO61_GPIO | MFP_LPM_DRIVE_LOW,
GPIO62_GPIO | MFP_LPM_DRIVE_LOW,
GPIO63_GPIO | MFP_LPM_DRIVE_LOW,
GPIO64_GPIO | MFP_LPM_DRIVE_LOW,
GPIO65_GPIO | MFP_LPM_DRIVE_LOW,
GPIO66_GPIO | MFP_LPM_DRIVE_LOW,
GPIO67_GPIO | MFP_LPM_DRIVE_LOW,
GPIO68_GPIO | MFP_LPM_DRIVE_LOW,
GPIO69_GPIO | MFP_LPM_DRIVE_LOW,
GPIO70_GPIO | MFP_LPM_DRIVE_LOW,
GPIO71_GPIO | MFP_LPM_DRIVE_LOW,
GPIO72_GPIO | MFP_LPM_DRIVE_LOW,
GPIO73_GPIO | MFP_LPM_DRIVE_LOW,
GPIO74_GPIO | MFP_LPM_DRIVE_LOW,
GPIO75_GPIO | MFP_LPM_DRIVE_LOW,
/* SPI */
GPIO81_SSP2_CLK_OUT,
......@@ -154,6 +151,17 @@ static unsigned long tosa_pin_config[] = {
GPIO83_SSP2_TXD,
};
static unsigned long tosa_pin_irda_off[] = {
GPIO46_STUART_RXD,
GPIO47_GPIO | MFP_LPM_DRIVE_LOW,
};
static unsigned long tosa_pin_irda_on[] = {
GPIO46_STUART_RXD,
GPIO47_STUART_TXD,
};
/*
* SCOOP Device
*/
......@@ -249,6 +257,15 @@ static int tosa_mci_init(struct device *dev, irq_handler_t tosa_detect_int, void
tosa_mci_platform_data.detect_delay = msecs_to_jiffies(250);
err = gpio_request(TOSA_GPIO_nSD_DETECT, "MMC/SD card detect");
if (err) {
printk(KERN_ERR "tosa_mci_init: can't request nSD_DETECT gpio\n");
goto err_gpio_detect;
}
err = gpio_direction_input(TOSA_GPIO_nSD_DETECT);
if (err)
goto err_gpio_detect_dir;
err = request_irq(TOSA_IRQ_GPIO_nSD_DETECT, tosa_detect_int,
IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"MMC/SD card detect", data);
......@@ -257,7 +274,7 @@ static int tosa_mci_init(struct device *dev, irq_handler_t tosa_detect_int, void
goto err_irq;
}
err = gpio_request(TOSA_GPIO_SD_WP, "sd_wp");
err = gpio_request(TOSA_GPIO_SD_WP, "SD Write Protect");
if (err) {
printk(KERN_ERR "tosa_mci_init: can't request SD_WP gpio\n");
goto err_gpio_wp;
......@@ -266,7 +283,7 @@ static int tosa_mci_init(struct device *dev, irq_handler_t tosa_detect_int, void
if (err)
goto err_gpio_wp_dir;
err = gpio_request(TOSA_GPIO_PWR_ON, "sd_pwr");
err = gpio_request(TOSA_GPIO_PWR_ON, "SD Power");
if (err) {
printk(KERN_ERR "tosa_mci_init: can't request SD_PWR gpio\n");
goto err_gpio_pwr;
......@@ -275,8 +292,20 @@ static int tosa_mci_init(struct device *dev, irq_handler_t tosa_detect_int, void
if (err)
goto err_gpio_pwr_dir;
err = gpio_request(TOSA_GPIO_nSD_INT, "SD Int");
if (err) {
printk(KERN_ERR "tosa_mci_init: can't request SD_PWR gpio\n");
goto err_gpio_int;
}
err = gpio_direction_input(TOSA_GPIO_nSD_INT);
if (err)
goto err_gpio_int_dir;
return 0;
err_gpio_int_dir:
gpio_free(TOSA_GPIO_nSD_INT);
err_gpio_int:
err_gpio_pwr_dir:
gpio_free(TOSA_GPIO_PWR_ON);
err_gpio_pwr:
......@@ -285,6 +314,9 @@ static int tosa_mci_init(struct device *dev, irq_handler_t tosa_detect_int, void
err_gpio_wp:
free_irq(TOSA_IRQ_GPIO_nSD_DETECT, data);
err_irq:
err_gpio_detect_dir:
gpio_free(TOSA_GPIO_nSD_DETECT);
err_gpio_detect:
return err;
}
......@@ -306,9 +338,11 @@ static int tosa_mci_get_ro(struct device *dev)
static void tosa_mci_exit(struct device *dev, void *data)
{
gpio_free(TOSA_GPIO_nSD_INT);
gpio_free(TOSA_GPIO_PWR_ON);
gpio_free(TOSA_GPIO_SD_WP);
free_irq(TOSA_IRQ_GPIO_nSD_DETECT, data);
gpio_free(TOSA_GPIO_nSD_DETECT);
}
static struct pxamci_platform_data tosa_mci_platform_data = {
......@@ -322,29 +356,55 @@ static struct pxamci_platform_data tosa_mci_platform_data = {
/*
* Irda
*/
static void tosa_irda_transceiver_mode(struct device *dev, int mode)
{
if (mode & IR_OFF) {
gpio_set_value(TOSA_GPIO_IR_POWERDWN, 0);
pxa2xx_mfp_config(ARRAY_AND_SIZE(tosa_pin_irda_off));
gpio_direction_output(TOSA_GPIO_IRDA_TX, 0);
} else {
pxa2xx_mfp_config(ARRAY_AND_SIZE(tosa_pin_irda_on));
gpio_set_value(TOSA_GPIO_IR_POWERDWN, 1);
}
}
static int tosa_irda_startup(struct device *dev)
{
int ret;
ret = gpio_request(TOSA_GPIO_IRDA_TX, "IrDA TX");
if (ret)
goto err_tx;
ret = gpio_direction_output(TOSA_GPIO_IRDA_TX, 0);
if (ret)
goto err_tx_dir;
ret = gpio_request(TOSA_GPIO_IR_POWERDWN, "IrDA powerdown");
if (ret)
return ret;
goto err_pwr;
ret = gpio_direction_output(TOSA_GPIO_IR_POWERDWN, 0);
if (ret)
gpio_free(TOSA_GPIO_IR_POWERDWN);
goto err_pwr_dir;
return ret;
}
tosa_irda_transceiver_mode(dev, IR_SIRMODE | IR_OFF);
static void tosa_irda_shutdown(struct device *dev)
{
return 0;
err_pwr_dir:
gpio_free(TOSA_GPIO_IR_POWERDWN);
err_pwr:
err_tx_dir:
gpio_free(TOSA_GPIO_IRDA_TX);
err_tx:
return ret;
}
static void tosa_irda_transceiver_mode(struct device *dev, int mode)
static void tosa_irda_shutdown(struct device *dev)
{
gpio_set_value(TOSA_GPIO_IR_POWERDWN, !(mode & IR_OFF));
tosa_irda_transceiver_mode(dev, IR_SIRMODE | IR_OFF);
gpio_free(TOSA_GPIO_IR_POWERDWN);
gpio_free(TOSA_GPIO_IRDA_TX);
}
static struct pxaficp_platform_data tosa_ficp_platform_data = {
......@@ -354,6 +414,70 @@ static struct pxaficp_platform_data tosa_ficp_platform_data = {
.shutdown = tosa_irda_shutdown,
};
/*
* Tosa AC IN
*/
static int tosa_power_init(struct device *dev)
{
int ret = gpio_request(TOSA_GPIO_AC_IN, "ac in");
if (ret)
goto err_gpio_req;
ret = gpio_direction_input(TOSA_GPIO_AC_IN);
if (ret)
goto err_gpio_in;
return 0;
err_gpio_in:
gpio_free(TOSA_GPIO_AC_IN);
err_gpio_req:
return ret;
}
static void tosa_power_exit(struct device *dev)
{
gpio_free(TOSA_GPIO_AC_IN);
}
static int tosa_power_ac_online(void)
{
return gpio_get_value(TOSA_GPIO_AC_IN) == 0;
}
static char *tosa_ac_supplied_to[] = {
"main-battery",
"backup-battery",
"jacket-battery",
};
static struct pda_power_pdata tosa_power_data = {
.init = tosa_power_init,
.is_ac_online = tosa_power_ac_online,
.exit = tosa_power_exit,
.supplied_to = tosa_ac_supplied_to,
.num_supplicants = ARRAY_SIZE(tosa_ac_supplied_to),
};
static struct resource tosa_power_resource[] = {
{
.name = "ac",
.start = gpio_to_irq(TOSA_GPIO_AC_IN),
.end = gpio_to_irq(TOSA_GPIO_AC_IN),
.flags = IORESOURCE_IRQ |
IORESOURCE_IRQ_HIGHEDGE |
IORESOURCE_IRQ_LOWEDGE,
},
};
static struct platform_device tosa_power_device = {
.name = "pda-power",
.id = -1,
.dev.platform_data = &tosa_power_data,
.resource = tosa_power_resource,
.num_resources = ARRAY_SIZE(tosa_power_resource),
};
/*
* Tosa Keyboard
*/
......@@ -439,7 +563,7 @@ static struct gpio_led tosa_gpio_leds[] = {
},
{
.name = "tosa:blue:bluetooth",
.default_trigger = "none",
.default_trigger = "tosa-bt",
.gpio = TOSA_GPIO_BT_LED,
},
};
......@@ -457,21 +581,184 @@ static struct platform_device tosaled_device = {
},
};
/*
* Toshiba Mobile IO Controller
*/
static struct resource tc6393xb_resources[] = {
[0] = {
.start = TOSA_LCDC_PHYS,
.end = TOSA_LCDC_PHYS + 0x3ffffff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = TOSA_IRQ_GPIO_TC6393XB_INT,
.end = TOSA_IRQ_GPIO_TC6393XB_INT,
.flags = IORESOURCE_IRQ,
},
};
static int tosa_tc6393xb_enable(struct platform_device *dev)
{
int rc;
rc = gpio_request(TOSA_GPIO_TC6393XB_REST_IN, "tc6393xb #pclr");
if (rc)
goto err_req_pclr;
rc = gpio_request(TOSA_GPIO_TC6393XB_SUSPEND, "tc6393xb #suspend");
if (rc)
goto err_req_suspend;
rc = gpio_request(TOSA_GPIO_TC6393XB_L3V_ON, "l3v");
if (rc)
goto err_req_l3v;
rc = gpio_direction_output(TOSA_GPIO_TC6393XB_L3V_ON, 0);
if (rc)
goto err_dir_l3v;
rc = gpio_direction_output(TOSA_GPIO_TC6393XB_SUSPEND, 0);
if (rc)
goto err_dir_suspend;
rc = gpio_direction_output(TOSA_GPIO_TC6393XB_REST_IN, 0);
if (rc)
goto err_dir_pclr;
mdelay(1);
gpio_set_value(TOSA_GPIO_TC6393XB_SUSPEND, 1);
mdelay(10);
gpio_set_value(TOSA_GPIO_TC6393XB_REST_IN, 1);
gpio_set_value(TOSA_GPIO_TC6393XB_L3V_ON, 1);
return 0;
err_dir_pclr:
err_dir_suspend:
err_dir_l3v:
gpio_free(TOSA_GPIO_TC6393XB_L3V_ON);
err_req_l3v:
gpio_free(TOSA_GPIO_TC6393XB_SUSPEND);
err_req_suspend:
gpio_free(TOSA_GPIO_TC6393XB_REST_IN);
err_req_pclr:
return rc;
}
static int tosa_tc6393xb_disable(struct platform_device *dev)
{
gpio_free(TOSA_GPIO_TC6393XB_L3V_ON);
gpio_free(TOSA_GPIO_TC6393XB_SUSPEND);
gpio_free(TOSA_GPIO_TC6393XB_REST_IN);
return 0;
}
static int tosa_tc6393xb_resume(struct platform_device *dev)
{
gpio_set_value(TOSA_GPIO_TC6393XB_SUSPEND, 1);
mdelay(10);
gpio_set_value(TOSA_GPIO_TC6393XB_L3V_ON, 1);
mdelay(10);
return 0;
}
static int tosa_tc6393xb_suspend(struct platform_device *dev)
{
gpio_set_value(TOSA_GPIO_TC6393XB_L3V_ON, 0);
gpio_set_value(TOSA_GPIO_TC6393XB_SUSPEND, 0);
return 0;
}
static struct mtd_partition tosa_nand_partition[] = {
{
.name = "smf",
.offset = 0,
.size = 7 * 1024 * 1024,
},
{
.name = "root",
.offset = MTDPART_OFS_APPEND,
.size = 28 * 1024 * 1024,
},
{
.name = "home",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
},
};
static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
static struct nand_bbt_descr tosa_tc6393xb_nand_bbt = {
.options = 0,
.offs = 4,
.len = 2,
.pattern = scan_ff_pattern
};
static struct tmio_nand_data tosa_tc6393xb_nand_config = {
.num_partitions = ARRAY_SIZE(tosa_nand_partition),
.partition = tosa_nand_partition,
.badblock_pattern = &tosa_tc6393xb_nand_bbt,
};
static struct tc6393xb_platform_data tosa_tc6393xb_setup = {
.scr_pll2cr = 0x0cc1,
.scr_gper = 0x3300,
.scr_gpo_dsr =
TOSA_TC6393XB_GPIO_BIT(TOSA_GPIO_CARD_VCC_ON),
.scr_gpo_doecr =
TOSA_TC6393XB_GPIO_BIT(TOSA_GPIO_CARD_VCC_ON),
.irq_base = IRQ_BOARD_START,
.gpio_base = TOSA_TC6393XB_GPIO_BASE,
.enable = tosa_tc6393xb_enable,
.disable = tosa_tc6393xb_disable,
.suspend = tosa_tc6393xb_suspend,
.resume = tosa_tc6393xb_resume,
.nand_data = &tosa_tc6393xb_nand_config,
};
static struct platform_device tc6393xb_device = {
.name = "tc6393xb",
.id = -1,
.dev = {
.platform_data = &tosa_tc6393xb_setup,
},
.num_resources = ARRAY_SIZE(tc6393xb_resources),
.resource = tc6393xb_resources,
};
static struct tosa_bt_data tosa_bt_data = {
.gpio_pwr = TOSA_GPIO_BT_PWR_EN,
.gpio_reset = TOSA_GPIO_BT_RESET,
};
static struct platform_device tosa_bt_device = {
.name = "tosa-bt",
.id = -1,
.dev.platform_data = &tosa_bt_data,
};
static struct platform_device *devices[] __initdata = {
&tosascoop_device,
&tosascoop_jc_device,
&tc6393xb_device,
&tosa_power_device,
&tosakbd_device,
&tosa_gpio_keys_device,
&tosaled_device,
&tosa_bt_device,
};
static void tosa_poweroff(void)
{
gpio_direction_output(TOSA_GPIO_ON_RESET, 0);
gpio_set_value(TOSA_GPIO_ON_RESET, 1);
mdelay(1000);
arm_machine_restart('h');
arm_machine_restart('g');
}
static void tosa_restart(char mode)
......@@ -485,10 +772,15 @@ static void tosa_restart(char mode)
static void __init tosa_init(void)
{
int dummy;
pxa2xx_mfp_config(ARRAY_AND_SIZE(tosa_pin_config));
pxa2xx_mfp_config(ARRAY_AND_SIZE(tosa_pin_irda_off));
gpio_set_wake(MFP_PIN_GPIO1, 1);
/* We can't pass to gpio-keys since it will drop the Reset altfunc */
init_gpio_reset(TOSA_GPIO_ON_RESET);
pm_power_off = tosa_poweroff;
arm_pm_restart = tosa_restart;
......@@ -497,6 +789,10 @@ static void __init tosa_init(void)
/* enable batt_fault */
PMCR = 0x01;
dummy = gpiochip_reserve(TOSA_SCOOP_GPIO_BASE, 12);
dummy = gpiochip_reserve(TOSA_SCOOP_JC_GPIO_BASE, 12);
dummy = gpiochip_reserve(TOSA_TC6393XB_GPIO_BASE, 16);
pxa_set_mci_info(&tosa_mci_platform_data);
pxa_set_udc_info(&udc_info);
pxa_set_ficp_info(&tosa_ficp_platform_data);
......
......@@ -215,8 +215,6 @@ static int tosakbd_suspend(struct platform_device *dev, pm_message_t state)
unsigned long flags;
spin_lock_irqsave(&tosakbd->lock, flags);
PGSR1 = (PGSR1 & ~TOSA_GPIO_LOW_STROBE_BIT);
PGSR2 = (PGSR2 & ~TOSA_GPIO_HIGH_STROBE_BIT);
tosakbd->suspended = 1;
spin_unlock_irqrestore(&tosakbd->lock, flags);
......
......@@ -5,6 +5,10 @@
menu "Multifunction device drivers"
depends on HAS_IOMEM
config MFD_CORE
tristate
default n
config MFD_SM501
tristate "Support for Silicon Motion SM501"
---help---
......@@ -38,6 +42,13 @@ config HTC_PASIC3
HTC Magician devices, respectively. Actual functionality is
handled by the leds-pasic3 and ds1wm drivers.
config MFD_TC6393XB
bool "Support Toshiba TC6393XB"
depends on HAVE_GPIO_LIB
select MFD_CORE
help
Support for Toshiba Mobile IO Controller TC6393XB
endmenu
menu "Multimedia Capabilities Port drivers"
......
......@@ -8,6 +8,10 @@ obj-$(CONFIG_MFD_ASIC3) += asic3.o
obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o
obj-$(CONFIG_MFD_CORE) += mfd-core.o
obj-$(CONFIG_MCP) += mcp-core.o
obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o
obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o
......
/*
* drivers/mfd/mfd-core.c
*
* core MFD support
* Copyright (c) 2006 Ian Molton
* Copyright (c) 2007,2008 Dmitry Baryshkov
*
* 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/platform_device.h>
#include <linux/mfd/core.h>
static int mfd_add_device(struct platform_device *parent,
const struct mfd_cell *cell,
struct resource *mem_base,
int irq_base)
{
struct resource res[cell->num_resources];
struct platform_device *pdev;
int ret = -ENOMEM;
int r;
pdev = platform_device_alloc(cell->name, parent->id);
if (!pdev)
goto fail_alloc;
pdev->dev.parent = &parent->dev;
ret = platform_device_add_data(pdev,
cell, sizeof(struct mfd_cell));
if (ret)
goto fail_device;
memzero(res, sizeof(res));
for (r = 0; r < cell->num_resources; r++) {
res[r].name = cell->resources[r].name;
res[r].flags = cell->resources[r].flags;
/* Find out base to use */
if (cell->resources[r].flags & IORESOURCE_MEM) {
res[r].parent = mem_base;
res[r].start = mem_base->start +
cell->resources[r].start;
res[r].end = mem_base->start +
cell->resources[r].end;
} else if (cell->resources[r].flags & IORESOURCE_IRQ) {
res[r].start = irq_base +
cell->resources[r].start;
res[r].end = irq_base +
cell->resources[r].end;
} else {
res[r].parent = cell->resources[r].parent;
res[r].start = cell->resources[r].start;
res[r].end = cell->resources[r].end;
}
}
platform_device_add_resources(pdev, res, cell->num_resources);
ret = platform_device_add(pdev);
if (ret)
goto fail_device;
return 0;
/* platform_device_del(pdev); */
fail_device:
platform_device_put(pdev);
fail_alloc:
return ret;
}
int mfd_add_devices(
struct platform_device *parent,
const struct mfd_cell *cells, int n_devs,
struct resource *mem_base,
int irq_base)
{
int i;
int ret = 0;
for (i = 0; i < n_devs; i++) {
ret = mfd_add_device(parent, cells + i, mem_base, irq_base);
if (ret)
break;
}
if (ret)
mfd_remove_devices(parent);
return ret;
}
EXPORT_SYMBOL(mfd_add_devices);
static int mfd_remove_devices_fn(struct device *dev, void *unused)
{
platform_device_unregister(
container_of(dev, struct platform_device, dev));
return 0;
}
void mfd_remove_devices(struct platform_device *parent)
{
device_for_each_child(&parent->dev, NULL, mfd_remove_devices_fn);
}
EXPORT_SYMBOL(mfd_remove_devices);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov");
/*
* Toshiba TC6393XB SoC support
*
* Copyright(c) 2005-2006 Chris Humbert
* Copyright(c) 2005 Dirk Opfer
* Copyright(c) 2005 Ian Molton <spyro@f2s.com>
* Copyright(c) 2007 Dmitry Baryshkov
*
* Based on code written by Sharp/Lineo for 2.4 kernels
* Based on locomo.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/module.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/fb.h>
#include <linux/clk.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tmio.h>
#include <linux/mfd/tc6393xb.h>
#include <linux/gpio.h>
#define SCR_REVID 0x08 /* b Revision ID */
#define SCR_ISR 0x50 /* b Interrupt Status */
#define SCR_IMR 0x52 /* b Interrupt Mask */
#define SCR_IRR 0x54 /* b Interrupt Routing */
#define SCR_GPER 0x60 /* w GP Enable */
#define SCR_GPI_SR(i) (0x64 + (i)) /* b3 GPI Status */
#define SCR_GPI_IMR(i) (0x68 + (i)) /* b3 GPI INT Mask */
#define SCR_GPI_EDER(i) (0x6c + (i)) /* b3 GPI Edge Detect Enable */
#define SCR_GPI_LIR(i) (0x70 + (i)) /* b3 GPI Level Invert */
#define SCR_GPO_DSR(i) (0x78 + (i)) /* b3 GPO Data Set */
#define SCR_GPO_DOECR(i) (0x7c + (i)) /* b3 GPO Data OE Control */
#define SCR_GP_IARCR(i) (0x80 + (i)) /* b3 GP Internal Active Register Control */
#define SCR_GP_IARLCR(i) (0x84 + (i)) /* b3 GP INTERNAL Active Register Level Control */
#define SCR_GPI_BCR(i) (0x88 + (i)) /* b3 GPI Buffer Control */
#define SCR_GPA_IARCR 0x8c /* w GPa Internal Active Register Control */
#define SCR_GPA_IARLCR 0x90 /* w GPa Internal Active Register Level Control */
#define SCR_GPA_BCR 0x94 /* w GPa Buffer Control */
#define SCR_CCR 0x98 /* w Clock Control */
#define SCR_PLL2CR 0x9a /* w PLL2 Control */
#define SCR_PLL1CR 0x9c /* l PLL1 Control */
#define SCR_DIARCR 0xa0 /* b Device Internal Active Register Control */
#define SCR_DBOCR 0xa1 /* b Device Buffer Off Control */
#define SCR_FER 0xe0 /* b Function Enable */
#define SCR_MCR 0xe4 /* w Mode Control */
#define SCR_CONFIG 0xfc /* b Configuration Control */
#define SCR_DEBUG 0xff /* b Debug */
#define SCR_CCR_CK32K BIT(0)
#define SCR_CCR_USBCK BIT(1)
#define SCR_CCR_UNK1 BIT(4)
#define SCR_CCR_MCLK_MASK (7 << 8)
#define SCR_CCR_MCLK_OFF (0 << 8)
#define SCR_CCR_MCLK_12 (1 << 8)
#define SCR_CCR_MCLK_24 (2 << 8)
#define SCR_CCR_MCLK_48 (3 << 8)
#define SCR_CCR_HCLK_MASK (3 << 12)
#define SCR_CCR_HCLK_24 (0 << 12)
#define SCR_CCR_HCLK_48 (1 << 12)
#define SCR_FER_USBEN BIT(0) /* USB host enable */
#define SCR_FER_LCDCVEN BIT(1) /* polysilicon TFT enable */
#define SCR_FER_SLCDEN BIT(2) /* SLCD enable */
#define SCR_MCR_RDY_MASK (3 << 0)
#define SCR_MCR_RDY_OPENDRAIN (0 << 0)
#define SCR_MCR_RDY_TRISTATE (1 << 0)
#define SCR_MCR_RDY_PUSHPULL (2 << 0)
#define SCR_MCR_RDY_UNK BIT(2)
#define SCR_MCR_RDY_EN BIT(3)
#define SCR_MCR_INT_MASK (3 << 4)
#define SCR_MCR_INT_OPENDRAIN (0 << 4)
#define SCR_MCR_INT_TRISTATE (1 << 4)
#define SCR_MCR_INT_PUSHPULL (2 << 4)
#define SCR_MCR_INT_UNK BIT(6)
#define SCR_MCR_INT_EN BIT(7)
/* bits 8 - 16 are unknown */
#define TC_GPIO_BIT(i) (1 << (i & 0x7))
/*--------------------------------------------------------------------------*/
struct tc6393xb {
void __iomem *scr;
struct gpio_chip gpio;
struct clk *clk; /* 3,6 Mhz */
spinlock_t lock; /* protects RMW cycles */
struct {
u8 fer;
u16 ccr;
u8 gpi_bcr[3];
u8 gpo_dsr[3];
u8 gpo_doecr[3];
} suspend_state;
struct resource rscr;
struct resource *iomem;
int irq;
int irq_base;
};
enum {
TC6393XB_CELL_NAND,
};
/*--------------------------------------------------------------------------*/
static int tc6393xb_nand_enable(struct platform_device *nand)
{
struct platform_device *dev = to_platform_device(nand->dev.parent);
struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&tc6393xb->lock, flags);
/* SMD buffer on */
dev_dbg(&dev->dev, "SMD buffer on\n");
iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1));
spin_unlock_irqrestore(&tc6393xb->lock, flags);
return 0;
}
static struct resource __devinitdata tc6393xb_nand_resources[] = {
{
.name = TMIO_NAND_CONFIG,
.start = 0x0100,
.end = 0x01ff,
.flags = IORESOURCE_MEM,
},
{
.name = TMIO_NAND_CONTROL,
.start = 0x1000,
.end = 0x1007,
.flags = IORESOURCE_MEM,
},
{
.name = TMIO_NAND_IRQ,
.start = IRQ_TC6393_NAND,
.end = IRQ_TC6393_NAND,
.flags = IORESOURCE_IRQ,
},
};
static struct mfd_cell __devinitdata tc6393xb_cells[] = {
[TC6393XB_CELL_NAND] = {
.name = "tmio-nand",
.enable = tc6393xb_nand_enable,
.num_resources = ARRAY_SIZE(tc6393xb_nand_resources),
.resources = tc6393xb_nand_resources,
},
};
/*--------------------------------------------------------------------------*/
static int tc6393xb_gpio_get(struct gpio_chip *chip,
unsigned offset)
{
struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio);
/* XXX: does dsr also represent inputs? */
return ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8))
& TC_GPIO_BIT(offset);
}
static void __tc6393xb_gpio_set(struct gpio_chip *chip,
unsigned offset, int value)
{
struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio);
u8 dsr;
dsr = ioread8(tc6393xb->scr + SCR_GPO_DSR(offset / 8));
if (value)
dsr |= TC_GPIO_BIT(offset);
else
dsr &= ~TC_GPIO_BIT(offset);
iowrite8(dsr, tc6393xb->scr + SCR_GPO_DSR(offset / 8));
}
static void tc6393xb_gpio_set(struct gpio_chip *chip,
unsigned offset, int value)
{
struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio);
unsigned long flags;
spin_lock_irqsave(&tc6393xb->lock, flags);
__tc6393xb_gpio_set(chip, offset, value);
spin_unlock_irqrestore(&tc6393xb->lock, flags);
}
static int tc6393xb_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio);
unsigned long flags;
u8 doecr;
spin_lock_irqsave(&tc6393xb->lock, flags);
doecr = ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8));
doecr &= ~TC_GPIO_BIT(offset);
iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8));
spin_unlock_irqrestore(&tc6393xb->lock, flags);
return 0;
}
static int tc6393xb_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
struct tc6393xb *tc6393xb = container_of(chip, struct tc6393xb, gpio);
unsigned long flags;
u8 doecr;
spin_lock_irqsave(&tc6393xb->lock, flags);
__tc6393xb_gpio_set(chip, offset, value);
doecr = ioread8(tc6393xb->scr + SCR_GPO_DOECR(offset / 8));
doecr |= TC_GPIO_BIT(offset);
iowrite8(doecr, tc6393xb->scr + SCR_GPO_DOECR(offset / 8));
spin_unlock_irqrestore(&tc6393xb->lock, flags);
return 0;
}
static int tc6393xb_register_gpio(struct tc6393xb *tc6393xb, int gpio_base)
{
tc6393xb->gpio.label = "tc6393xb";
tc6393xb->gpio.base = gpio_base;
tc6393xb->gpio.ngpio = 16;
tc6393xb->gpio.set = tc6393xb_gpio_set;
tc6393xb->gpio.get = tc6393xb_gpio_get;
tc6393xb->gpio.direction_input = tc6393xb_gpio_direction_input;
tc6393xb->gpio.direction_output = tc6393xb_gpio_direction_output;
return gpiochip_add(&tc6393xb->gpio);
}
/*--------------------------------------------------------------------------*/
static void
tc6393xb_irq(unsigned int irq, struct irq_desc *desc)
{
struct tc6393xb *tc6393xb = get_irq_data(irq);
unsigned int isr;
unsigned int i, irq_base;
irq_base = tc6393xb->irq_base;
while ((isr = ioread8(tc6393xb->scr + SCR_ISR) &
~ioread8(tc6393xb->scr + SCR_IMR)))
for (i = 0; i < TC6393XB_NR_IRQS; i++) {
if (isr & (1 << i))
generic_handle_irq(irq_base + i);
}
}
static void tc6393xb_irq_ack(unsigned int irq)
{
}
static void tc6393xb_irq_mask(unsigned int irq)
{
struct tc6393xb *tc6393xb = get_irq_chip_data(irq);
unsigned long flags;
u8 imr;
spin_lock_irqsave(&tc6393xb->lock, flags);
imr = ioread8(tc6393xb->scr + SCR_IMR);
imr |= 1 << (irq - tc6393xb->irq_base);
iowrite8(imr, tc6393xb->scr + SCR_IMR);
spin_unlock_irqrestore(&tc6393xb->lock, flags);
}
static void tc6393xb_irq_unmask(unsigned int irq)
{
struct tc6393xb *tc6393xb = get_irq_chip_data(irq);
unsigned long flags;
u8 imr;
spin_lock_irqsave(&tc6393xb->lock, flags);
imr = ioread8(tc6393xb->scr + SCR_IMR);
imr &= ~(1 << (irq - tc6393xb->irq_base));
iowrite8(imr, tc6393xb->scr + SCR_IMR);
spin_unlock_irqrestore(&tc6393xb->lock, flags);
}
static struct irq_chip tc6393xb_chip = {
.name = "tc6393xb",
.ack = tc6393xb_irq_ack,
.mask = tc6393xb_irq_mask,
.unmask = tc6393xb_irq_unmask,
};
static void tc6393xb_attach_irq(struct platform_device *dev)
{
struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
unsigned int irq, irq_base;
irq_base = tc6393xb->irq_base;
for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) {
set_irq_chip(irq, &tc6393xb_chip);
set_irq_chip_data(irq, tc6393xb);
set_irq_handler(irq, handle_edge_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
set_irq_type(tc6393xb->irq, IRQT_FALLING);
set_irq_data(tc6393xb->irq, tc6393xb);
set_irq_chained_handler(tc6393xb->irq, tc6393xb_irq);
}
static void tc6393xb_detach_irq(struct platform_device *dev)
{
struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
unsigned int irq, irq_base;
set_irq_chained_handler(tc6393xb->irq, NULL);
set_irq_data(tc6393xb->irq, NULL);
irq_base = tc6393xb->irq_base;
for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) {
set_irq_flags(irq, 0);
set_irq_chip(irq, NULL);
set_irq_chip_data(irq, NULL);
}
}
/*--------------------------------------------------------------------------*/
static int tc6393xb_hw_init(struct platform_device *dev)
{
struct tc6393xb_platform_data *tcpd = dev->dev.platform_data;
struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
int i;
iowrite8(tc6393xb->suspend_state.fer, tc6393xb->scr + SCR_FER);
iowrite16(tcpd->scr_pll2cr, tc6393xb->scr + SCR_PLL2CR);
iowrite16(tc6393xb->suspend_state.ccr, tc6393xb->scr + SCR_CCR);
iowrite16(SCR_MCR_RDY_OPENDRAIN | SCR_MCR_RDY_UNK | SCR_MCR_RDY_EN |
SCR_MCR_INT_OPENDRAIN | SCR_MCR_INT_UNK | SCR_MCR_INT_EN |
BIT(15), tc6393xb->scr + SCR_MCR);
iowrite16(tcpd->scr_gper, tc6393xb->scr + SCR_GPER);
iowrite8(0, tc6393xb->scr + SCR_IRR);
iowrite8(0xbf, tc6393xb->scr + SCR_IMR);
for (i = 0; i < 3; i++) {
iowrite8(tc6393xb->suspend_state.gpo_dsr[i],
tc6393xb->scr + SCR_GPO_DSR(i));
iowrite8(tc6393xb->suspend_state.gpo_doecr[i],
tc6393xb->scr + SCR_GPO_DOECR(i));
iowrite8(tc6393xb->suspend_state.gpi_bcr[i],
tc6393xb->scr + SCR_GPI_BCR(i));
}
return 0;
}
static int __devinit tc6393xb_probe(struct platform_device *dev)
{
struct tc6393xb_platform_data *tcpd = dev->dev.platform_data;
struct tc6393xb *tc6393xb;
struct resource *iomem;
struct resource *rscr;
int retval, temp;
int i;
iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!iomem)
return -EINVAL;
tc6393xb = kzalloc(sizeof *tc6393xb, GFP_KERNEL);
if (!tc6393xb) {
retval = -ENOMEM;
goto err_kzalloc;
}
spin_lock_init(&tc6393xb->lock);
platform_set_drvdata(dev, tc6393xb);
tc6393xb->iomem = iomem;
tc6393xb->irq = platform_get_irq(dev, 0);
tc6393xb->irq_base = tcpd->irq_base;
tc6393xb->clk = clk_get(&dev->dev, "GPIO27_CLK" /* "CK3P6MI" */);
if (IS_ERR(tc6393xb->clk)) {
retval = PTR_ERR(tc6393xb->clk);
goto err_clk_get;
}
rscr = &tc6393xb->rscr;
rscr->name = "tc6393xb-core";
rscr->start = iomem->start;
rscr->end = iomem->start + 0xff;
rscr->flags = IORESOURCE_MEM;
retval = request_resource(iomem, rscr);
if (retval)
goto err_request_scr;
tc6393xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1);
if (!tc6393xb->scr) {
retval = -ENOMEM;
goto err_ioremap;
}
retval = clk_enable(tc6393xb->clk);
if (retval)
goto err_clk_enable;
retval = tcpd->enable(dev);
if (retval)
goto err_enable;
tc6393xb->suspend_state.fer = 0;
for (i = 0; i < 3; i++) {
tc6393xb->suspend_state.gpo_dsr[i] =
(tcpd->scr_gpo_dsr >> (8 * i)) & 0xff;
tc6393xb->suspend_state.gpo_doecr[i] =
(tcpd->scr_gpo_doecr >> (8 * i)) & 0xff;
}
/*
* It may be necessary to change this back to
* platform-dependant code
*/
tc6393xb->suspend_state.ccr = SCR_CCR_UNK1 |
SCR_CCR_HCLK_48;
retval = tc6393xb_hw_init(dev);
if (retval)
goto err_hw_init;
printk(KERN_INFO "Toshiba tc6393xb revision %d at 0x%08lx, irq %d\n",
ioread8(tc6393xb->scr + SCR_REVID),
(unsigned long) iomem->start, tc6393xb->irq);
tc6393xb->gpio.base = -1;
if (tcpd->gpio_base >= 0) {
retval = tc6393xb_register_gpio(tc6393xb, tcpd->gpio_base);
if (retval)
goto err_gpio_add;
}
if (tc6393xb->irq)
tc6393xb_attach_irq(dev);
tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data;
retval = mfd_add_devices(dev,
tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells),
iomem, tcpd->irq_base);
return 0;
if (tc6393xb->irq)
tc6393xb_detach_irq(dev);
err_gpio_add:
if (tc6393xb->gpio.base != -1)
temp = gpiochip_remove(&tc6393xb->gpio);
err_hw_init:
tcpd->disable(dev);
err_clk_enable:
clk_disable(tc6393xb->clk);
err_enable:
iounmap(tc6393xb->scr);
err_ioremap:
release_resource(&tc6393xb->rscr);
err_request_scr:
clk_put(tc6393xb->clk);
err_clk_get:
kfree(tc6393xb);
err_kzalloc:
return retval;
}
static int __devexit tc6393xb_remove(struct platform_device *dev)
{
struct tc6393xb_platform_data *tcpd = dev->dev.platform_data;
struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
int ret;
mfd_remove_devices(dev);
if (tc6393xb->irq)
tc6393xb_detach_irq(dev);
if (tc6393xb->gpio.base != -1) {
ret = gpiochip_remove(&tc6393xb->gpio);
if (ret) {
dev_err(&dev->dev, "Can't remove gpio chip: %d\n", ret);
return ret;
}
}
ret = tcpd->disable(dev);
clk_disable(tc6393xb->clk);
iounmap(tc6393xb->scr);
release_resource(&tc6393xb->rscr);
platform_set_drvdata(dev, NULL);
clk_put(tc6393xb->clk);
kfree(tc6393xb);
return ret;
}
#ifdef CONFIG_PM
static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state)
{
struct tc6393xb_platform_data *tcpd = dev->dev.platform_data;
struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
int i;
tc6393xb->suspend_state.ccr = ioread16(tc6393xb->scr + SCR_CCR);
tc6393xb->suspend_state.fer = ioread8(tc6393xb->scr + SCR_FER);
for (i = 0; i < 3; i++) {
tc6393xb->suspend_state.gpo_dsr[i] =
ioread8(tc6393xb->scr + SCR_GPO_DSR(i));
tc6393xb->suspend_state.gpo_doecr[i] =
ioread8(tc6393xb->scr + SCR_GPO_DOECR(i));
tc6393xb->suspend_state.gpi_bcr[i] =
ioread8(tc6393xb->scr + SCR_GPI_BCR(i));
}
return tcpd->suspend(dev);
}
static int tc6393xb_resume(struct platform_device *dev)
{
struct tc6393xb_platform_data *tcpd = dev->dev.platform_data;
int ret = tcpd->resume(dev);
if (ret)
return ret;
return tc6393xb_hw_init(dev);
}
#else
#define tc6393xb_suspend NULL
#define tc6393xb_resume NULL
#endif
static struct platform_driver tc6393xb_driver = {
.probe = tc6393xb_probe,
.remove = __devexit_p(tc6393xb_remove),
.suspend = tc6393xb_suspend,
.resume = tc6393xb_resume,
.driver = {
.name = "tc6393xb",
.owner = THIS_MODULE,
},
};
static int __init tc6393xb_init(void)
{
return platform_driver_register(&tc6393xb_driver);
}
static void __exit tc6393xb_exit(void)
{
platform_driver_unregister(&tc6393xb_driver);
}
subsys_initcall(tc6393xb_init);
module_exit(tc6393xb_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov and Dirk Opfer");
MODULE_DESCRIPTION("tc6393xb Toshiba Mobile IO Controller");
MODULE_ALIAS("platform:tc6393xb");
......@@ -208,6 +208,11 @@ extern void pxa_gpio_set_value(unsigned gpio, int value);
*/
extern unsigned int get_memclk_frequency_10khz(void);
/*
* register GPIO as reset generator
*/
extern int init_gpio_reset(int gpio);
#endif
#if defined(CONFIG_MACH_ARMCORE) && defined(CONFIG_PCI)
......
......@@ -180,6 +180,7 @@
#define NR_IRQS (IRQ_LOCOMO_SPI_TEND + 1)
#elif defined(CONFIG_ARCH_LUBBOCK) || \
defined(CONFIG_MACH_LOGICPD_PXA270) || \
defined(CONFIG_MACH_TOSA) || \
defined(CONFIG_MACH_MAINSTONE) || \
defined(CONFIG_MACH_PCM027) || \
defined(CONFIG_MACH_MAGICIAN)
......
......@@ -21,19 +21,4 @@ static inline void arch_idle(void)
}
static inline void arch_reset(char mode)
{
if (cpu_is_pxa2xx())
RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR;
if (mode == 's') {
/* Jump into ROM at address 0 */
cpu_reset(0);
} else {
/* Initialize the watchdog and let it fire */
OWER = OWER_WME;
OSSR = OSSR_M3;
OSMR3 = OSCR + 368640; /* ... in 100 ms */
}
}
void arch_reset(char mode);
......@@ -25,21 +25,18 @@
*/
#define TOSA_SCOOP_GPIO_BASE NR_BUILTIN_GPIO
#define TOSA_SCOOP_PXA_VCORE1 SCOOP_GPCR_PA11
#define TOSA_SCOOP_TC6393_REST_IN SCOOP_GPCR_PA12
#define TOSA_GPIO_TC6393XB_REST_IN (TOSA_SCOOP_GPIO_BASE + 1)
#define TOSA_GPIO_IR_POWERDWN (TOSA_SCOOP_GPIO_BASE + 2)
#define TOSA_GPIO_SD_WP (TOSA_SCOOP_GPIO_BASE + 3)
#define TOSA_GPIO_PWR_ON (TOSA_SCOOP_GPIO_BASE + 4)
#define TOSA_SCOOP_AUD_PWR_ON SCOOP_GPCR_PA16
#define TOSA_SCOOP_BT_RESET SCOOP_GPCR_PA17
#define TOSA_SCOOP_BT_PWR_EN SCOOP_GPCR_PA18
#define TOSA_GPIO_BT_RESET (TOSA_SCOOP_GPIO_BASE + 6)
#define TOSA_GPIO_BT_PWR_EN (TOSA_SCOOP_GPIO_BASE + 7)
#define TOSA_SCOOP_AC_IN_OL SCOOP_GPCR_PA19
/* GPIO Direction 1 : output mode / 0:input mode */
#define TOSA_SCOOP_IO_DIR ( TOSA_SCOOP_PXA_VCORE1 | TOSA_SCOOP_TC6393_REST_IN | \
TOSA_SCOOP_AUD_PWR_ON |\
TOSA_SCOOP_BT_RESET | TOSA_SCOOP_BT_PWR_EN )
/* GPIO out put level when init 1: Hi */
#define TOSA_SCOOP_IO_OUT ( TOSA_SCOOP_TC6393_REST_IN )
#define TOSA_SCOOP_IO_DIR (TOSA_SCOOP_PXA_VCORE1 | \
TOSA_SCOOP_AUD_PWR_ON)
/*
* SCOOP2 jacket GPIOs
......@@ -49,16 +46,34 @@
#define TOSA_GPIO_NOTE_LED (TOSA_SCOOP_JC_GPIO_BASE + 1)
#define TOSA_GPIO_CHRG_ERR_LED (TOSA_SCOOP_JC_GPIO_BASE + 2)
#define TOSA_GPIO_USB_PULLUP (TOSA_SCOOP_JC_GPIO_BASE + 3)
#define TOSA_SCOOP_JC_TC6393_SUSPEND SCOOP_GPCR_PA15
#define TOSA_SCOOP_JC_TC3693_L3V_ON SCOOP_GPCR_PA16
#define TOSA_GPIO_TC6393XB_SUSPEND (TOSA_SCOOP_JC_GPIO_BASE + 4)
#define TOSA_GPIO_TC6393XB_L3V_ON (TOSA_SCOOP_JC_GPIO_BASE + 5)
#define TOSA_SCOOP_JC_WLAN_DETECT SCOOP_GPCR_PA17
#define TOSA_GPIO_WLAN_LED (TOSA_SCOOP_JC_GPIO_BASE + 7)
#define TOSA_SCOOP_JC_CARD_LIMIT_SEL SCOOP_GPCR_PA19
/* GPIO Direction 1 : output mode / 0:input mode */
#define TOSA_SCOOP_JC_IO_DIR ( \
TOSA_SCOOP_JC_TC6393_SUSPEND | TOSA_SCOOP_JC_TC3693_L3V_ON | \
TOSA_SCOOP_JC_CARD_LIMIT_SEL )
#define TOSA_SCOOP_JC_IO_DIR (TOSA_SCOOP_JC_CARD_LIMIT_SEL)
/*
* TC6393XB GPIOs
*/
#define TOSA_TC6393XB_GPIO_BASE (NR_BUILTIN_GPIO + 2 * 12)
#define TOSA_TC6393XB_GPIO(i) (TOSA_TC6393XB_GPIO_BASE + (i))
#define TOSA_TC6393XB_GPIO_BIT(gpio) (1 << (gpio - TOSA_TC6393XB_GPIO_BASE))
#define TOSA_GPIO_TG_ON (TOSA_TC6393XB_GPIO_BASE + 0)
#define TOSA_GPIO_L_MUTE (TOSA_TC6393XB_GPIO_BASE + 1)
#define TOSA_GPIO_BL_C20MA (TOSA_TC6393XB_GPIO_BASE + 3)
#define TOSA_GPIO_CARD_VCC_ON (TOSA_TC6393XB_GPIO_BASE + 4)
#define TOSA_GPIO_CHARGE_OFF (TOSA_TC6393XB_GPIO_BASE + 6)
#define TOSA_GPIO_CHARGE_OFF_JC (TOSA_TC6393XB_GPIO_BASE + 7)
#define TOSA_GPIO_BAT0_V_ON (TOSA_TC6393XB_GPIO_BASE + 9)
#define TOSA_GPIO_BAT1_V_ON (TOSA_TC6393XB_GPIO_BASE + 10)
#define TOSA_GPIO_BU_CHRG_ON (TOSA_TC6393XB_GPIO_BASE + 11)
#define TOSA_GPIO_BAT_SW_ON (TOSA_TC6393XB_GPIO_BASE + 12)
#define TOSA_GPIO_BAT0_TH_ON (TOSA_TC6393XB_GPIO_BASE + 14)
#define TOSA_GPIO_BAT1_TH_ON (TOSA_TC6393XB_GPIO_BASE + 15)
/*
* Timing Generator
......@@ -84,13 +99,13 @@
#define TOSA_GPIO_JACKET_DETECT (7)
#define TOSA_GPIO_nSD_DETECT (9)
#define TOSA_GPIO_nSD_INT (10)
#define TOSA_GPIO_TC6393_CLK (11)
#define TOSA_GPIO_TC6393XB_CLK (11)
#define TOSA_GPIO_BAT1_CRG (12)
#define TOSA_GPIO_CF_CD (13)
#define TOSA_GPIO_BAT0_CRG (14)
#define TOSA_GPIO_TC6393_INT (15)
#define TOSA_GPIO_TC6393XB_INT (15)
#define TOSA_GPIO_BAT0_LOW (17)
#define TOSA_GPIO_TC6393_RDY (18)
#define TOSA_GPIO_TC6393XB_RDY (18)
#define TOSA_GPIO_ON_RESET (19)
#define TOSA_GPIO_EAR_IN (20)
#define TOSA_GPIO_CF_IRQ (21) /* CF slot0 Ready */
......@@ -99,6 +114,7 @@
#define TOSA_GPIO_TP_INT (32) /* Touch Panel pen down interrupt */
#define TOSA_GPIO_JC_CF_IRQ (36) /* CF slot1 Ready */
#define TOSA_GPIO_BAT_LOCKED (38) /* Battery locked */
#define TOSA_GPIO_IRDA_TX (47)
#define TOSA_GPIO_TG_SPI_SCLK (81)
#define TOSA_GPIO_TG_SPI_CS (82)
#define TOSA_GPIO_TG_SPI_MOSI (83)
......@@ -137,7 +153,7 @@
#define TOSA_IRQ_GPIO_BAT1_CRG IRQ_GPIO(TOSA_GPIO_BAT1_CRG)
#define TOSA_IRQ_GPIO_CF_CD IRQ_GPIO(TOSA_GPIO_CF_CD)
#define TOSA_IRQ_GPIO_BAT0_CRG IRQ_GPIO(TOSA_GPIO_BAT0_CRG)
#define TOSA_IRQ_GPIO_TC6393_INT IRQ_GPIO(TOSA_GPIO_TC6393_INT)
#define TOSA_IRQ_GPIO_TC6393XB_INT IRQ_GPIO(TOSA_GPIO_TC6393XB_INT)
#define TOSA_IRQ_GPIO_BAT0_LOW IRQ_GPIO(TOSA_GPIO_BAT0_LOW)
#define TOSA_IRQ_GPIO_EAR_IN IRQ_GPIO(TOSA_GPIO_EAR_IN)
#define TOSA_IRQ_GPIO_CF_IRQ IRQ_GPIO(TOSA_GPIO_CF_IRQ)
......
/*
* Tosa bluetooth built-in chip control.
*
* Later it may be shared with some other platforms.
*
* Copyright (c) 2008 Dmitry Baryshkov
*
* 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 TOSA_BT_H
#define TOSA_BT_H
struct tosa_bt_data {
int gpio_pwr;
int gpio_reset;
};
#endif
#ifndef MFD_CORE_H
#define MFD_CORE_H
/*
* drivers/mfd/mfd-core.h
*
* core MFD support
* Copyright (c) 2006 Ian Molton
* Copyright (c) 2007 Dmitry Baryshkov
*
* 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/platform_device.h>
/*
* This struct describes the MFD part ("cell").
* After registration the copy of this structure will become the platform data
* of the resulting platform_device
*/
struct mfd_cell {
const char *name;
int (*enable)(struct platform_device *dev);
int (*disable)(struct platform_device *dev);
int (*suspend)(struct platform_device *dev);
int (*resume)(struct platform_device *dev);
void *driver_data; /* driver-specific data */
/*
* This resources can be specified relatievly to the parent device.
* For accessing device you should use resources from device
*/
int num_resources;
const struct resource *resources;
};
static inline struct mfd_cell *
mfd_get_cell(struct platform_device *pdev)
{
return (struct mfd_cell *)pdev->dev.platform_data;
}
extern int mfd_add_devices(
struct platform_device *parent,
const struct mfd_cell *cells, int n_devs,
struct resource *mem_base,
int irq_base);
extern void mfd_remove_devices(struct platform_device *parent);
#endif
/*
* Toshiba TC6393XB SoC support
*
* Copyright(c) 2005-2006 Chris Humbert
* Copyright(c) 2005 Dirk Opfer
* Copyright(c) 2005 Ian Molton <spyro@f2s.com>
* Copyright(c) 2007 Dmitry Baryshkov
*
* Based on code written by Sharp/Lineo for 2.4 kernels
* Based on locomo.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.
*/
#ifndef TC6393XB_H
#define TC6393XB_H
/* Also one should provide the CK3P6MI clock */
struct tc6393xb_platform_data {
u16 scr_pll2cr; /* PLL2 Control */
u16 scr_gper; /* GP Enable */
u32 scr_gpo_doecr; /* GPO Data OE Control */
u32 scr_gpo_dsr; /* GPO Data Set */
int (*enable)(struct platform_device *dev);
int (*disable)(struct platform_device *dev);
int (*suspend)(struct platform_device *dev);
int (*resume)(struct platform_device *dev);
int irq_base; /* a base for cascaded irq */
int gpio_base;
struct tmio_nand_data *nand_data;
};
/*
* Relative to irq_base
*/
#define IRQ_TC6393_NAND 0
#define IRQ_TC6393_MMC 1
#define IRQ_TC6393_OHCI 2
#define IRQ_TC6393_SERIAL 3
#define IRQ_TC6393_FB 4
#define TC6393XB_NR_IRQS 8
#endif
#ifndef MFD_TMIO_H
#define MFD_TMIO_H
/*
* data for the NAND controller
*/
struct tmio_nand_data {
struct nand_bbt_descr *badblock_pattern;
struct mtd_partition *partition;
unsigned int num_partitions;
};
#define TMIO_NAND_CONFIG "tmio-nand-config"
#define TMIO_NAND_CONTROL "tmio-nand-control"
#define TMIO_NAND_IRQ "tmio-nand"
#endif
......@@ -48,6 +48,7 @@ config SND_PXA2XX_SOC_POODLE
config SND_PXA2XX_SOC_TOSA
tristate "SoC AC97 Audio support for Tosa"
depends on SND_PXA2XX_SOC && MACH_TOSA
depends on MFD_TC6393XB
select SND_PXA2XX_SOC_AC97
select SND_SOC_WM9712
help
......
......@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
......@@ -31,7 +32,7 @@
#include <sound/soc-dapm.h>
#include <asm/mach-types.h>
#include <asm/hardware/tmio.h>
#include <asm/arch/tosa.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/hardware.h>
#include <asm/arch/audio.h>
......@@ -138,10 +139,7 @@ static int tosa_set_spk(struct snd_kcontrol *kcontrol,
static int tosa_hp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
if (SND_SOC_DAPM_EVENT_ON(event))
set_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_L_MUTE);
else
reset_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_L_MUTE);
gpio_set_value(TOSA_GPIO_L_MUTE, SND_SOC_DAPM_EVENT_ON(event) ? 1 :0);
return 0;
}
......@@ -261,16 +259,28 @@ static int __init tosa_init(void)
if (!machine_is_tosa())
return -ENODEV;
ret = gpio_request(TOSA_GPIO_L_MUTE, "Headphone Jack");
if (ret)
return ret;
gpio_direction_output(TOSA_GPIO_L_MUTE, 0);
tosa_snd_device = platform_device_alloc("soc-audio", -1);
if (!tosa_snd_device)
return -ENOMEM;
if (!tosa_snd_device) {
ret = -ENOMEM;
goto err_alloc;
}
platform_set_drvdata(tosa_snd_device, &tosa_snd_devdata);
tosa_snd_devdata.dev = &tosa_snd_device->dev;
ret = platform_device_add(tosa_snd_device);
if (ret)
platform_device_put(tosa_snd_device);
if (!ret)
return 0;
platform_device_put(tosa_snd_device);
err_alloc:
gpio_free(TOSA_GPIO_L_MUTE);
return ret;
}
......@@ -278,6 +288,7 @@ static int __init tosa_init(void)
static void __exit tosa_exit(void)
{
platform_device_unregister(tosa_snd_device);
gpio_free(TOSA_GPIO_L_MUTE);
}
module_init(tosa_init);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册