Commit 7256ecc2 authored by Russell King's avatar Russell King

Merge branch 'sa11x0-mcp' into sa11x0

Conflicts:
	arch/arm/mach-sa1100/assabet.c
	arch/arm/mach-sa1100/collie.c
	arch/arm/mach-sa1100/generic.c
	arch/arm/mach-sa1100/lart.c
	arch/arm/mach-sa1100/shannon.c
parents 18bbff9f 6ed3e2ac
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/mfd/ucb1x00.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -71,6 +72,12 @@ void ASSABET_BCR_frob(unsigned int mask, unsigned int val) ...@@ -71,6 +72,12 @@ void ASSABET_BCR_frob(unsigned int mask, unsigned int val)
EXPORT_SYMBOL(ASSABET_BCR_frob); EXPORT_SYMBOL(ASSABET_BCR_frob);
static void assabet_ucb1x00_reset(enum ucb1x00_reset state)
{
if (state == UCB_RST_PROBE)
ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
}
/* /*
* Assabet flash support code. * Assabet flash support code.
...@@ -167,9 +174,15 @@ static struct irda_platform_data assabet_irda_data = { ...@@ -167,9 +174,15 @@ static struct irda_platform_data assabet_irda_data = {
.set_speed = assabet_irda_set_speed, .set_speed = assabet_irda_set_speed,
}; };
static struct ucb1x00_plat_data assabet_ucb1x00_data = {
.reset = assabet_ucb1x00_reset,
.gpio_base = -1,
};
static struct mcp_plat_data assabet_mcp_data = { static struct mcp_plat_data assabet_mcp_data = {
.mccr0 = MCCR0_ADM, .mccr0 = MCCR0_ADM,
.sclk_rate = 11981000, .sclk_rate = 11981000,
.codec_pdata = &assabet_ucb1x00_data,
}; };
static void assabet_lcd_set_visual(u32 visual) static void assabet_lcd_set_visual(u32 visual)
...@@ -309,6 +322,8 @@ static void __init assabet_init(void) ...@@ -309,6 +322,8 @@ static void __init assabet_init(void)
PPDR |= PPC_TXD3 | PPC_TXD1; PPDR |= PPC_TXD3 | PPC_TXD1;
PPSR |= PPC_TXD3 | PPC_TXD1; PPSR |= PPC_TXD3 | PPC_TXD1;
sa11x0_ppc_configure_mcp();
if (machine_has_neponset()) { if (machine_has_neponset()) {
/* /*
* Angel sets this, but other bootloaders may not. * Angel sets this, but other bootloaders may not.
......
...@@ -121,6 +121,7 @@ static struct mcp_plat_data cerf_mcp_data = { ...@@ -121,6 +121,7 @@ static struct mcp_plat_data cerf_mcp_data = {
static void __init cerf_init(void) static void __init cerf_init(void)
{ {
sa11x0_ppc_configure_mcp();
platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices)); platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1); sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1);
sa11x0_register_mcp(&cerf_mcp_data); sa11x0_register_mcp(&cerf_mcp_data);
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mfd/ucb1x00.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <linux/timer.h> #include <linux/timer.h>
...@@ -83,10 +84,14 @@ static struct scoop_pcmcia_config collie_pcmcia_config = { ...@@ -83,10 +84,14 @@ static struct scoop_pcmcia_config collie_pcmcia_config = {
.num_devs = 1, .num_devs = 1,
}; };
static struct ucb1x00_plat_data collie_ucb1x00_data = {
.gpio_base = COLLIE_TC35143_GPIO_BASE,
};
static struct mcp_plat_data collie_mcp_data = { static struct mcp_plat_data collie_mcp_data = {
.mccr0 = MCCR0_ADM | MCCR0_ExtClk, .mccr0 = MCCR0_ADM | MCCR0_ExtClk,
.sclk_rate = 9216000, .sclk_rate = 9216000,
.gpio_base = COLLIE_TC35143_GPIO_BASE, .codec_pdata = &collie_ucb1x00_data,
}; };
/* /*
...@@ -341,6 +346,10 @@ static void __init collie_init(void) ...@@ -341,6 +346,10 @@ static void __init collie_init(void)
collie_power_resource[0].start = gpio_to_irq(COLLIE_GPIO_AC_IN); collie_power_resource[0].start = gpio_to_irq(COLLIE_GPIO_AC_IN);
collie_power_resource[0].end = gpio_to_irq(COLLIE_GPIO_AC_IN); collie_power_resource[0].end = gpio_to_irq(COLLIE_GPIO_AC_IN);
sa11x0_ppc_configure_mcp();
platform_scoop_config = &collie_pcmcia_config; platform_scoop_config = &collie_pcmcia_config;
ret = platform_add_devices(devices, ARRAY_SIZE(devices)); ret = platform_add_devices(devices, ARRAY_SIZE(devices));
......
...@@ -195,7 +195,8 @@ static struct platform_device sa11x0uart3_device = { ...@@ -195,7 +195,8 @@ static struct platform_device sa11x0uart3_device = {
static struct resource sa11x0mcp_resources[] = { static struct resource sa11x0mcp_resources[] = {
[0] = DEFINE_RES_MEM(__PREG(Ser4MCCR0), SZ_64K), [0] = DEFINE_RES_MEM(__PREG(Ser4MCCR0), SZ_64K),
[1] = DEFINE_RES_IRQ(IRQ_Ser4MCP), [1] = DEFINE_RES_MEM(__PREG(Ser4MCCR1), 4),
[2] = DEFINE_RES_IRQ(IRQ_Ser4MCP),
}; };
static u64 sa11x0mcp_dma_mask = 0xffffffffUL; static u64 sa11x0mcp_dma_mask = 0xffffffffUL;
...@@ -211,6 +212,16 @@ static struct platform_device sa11x0mcp_device = { ...@@ -211,6 +212,16 @@ static struct platform_device sa11x0mcp_device = {
.resource = sa11x0mcp_resources, .resource = sa11x0mcp_resources,
}; };
void __init sa11x0_ppc_configure_mcp(void)
{
/* Setup the PPC unit for the MCP */
PPDR &= ~PPC_RXD4;
PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
PSDR |= PPC_RXD4;
PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
}
void sa11x0_register_mcp(struct mcp_plat_data *data) void sa11x0_register_mcp(struct mcp_plat_data *data)
{ {
sa11x0_register_device(&sa11x0mcp_device, data); sa11x0_register_device(&sa11x0mcp_device, data);
......
...@@ -36,6 +36,7 @@ struct irda_platform_data; ...@@ -36,6 +36,7 @@ struct irda_platform_data;
void sa11x0_register_irda(struct irda_platform_data *irda); void sa11x0_register_irda(struct irda_platform_data *irda);
struct mcp_plat_data; struct mcp_plat_data;
void sa11x0_ppc_configure_mcp(void);
void sa11x0_register_mcp(struct mcp_plat_data *data); void sa11x0_register_mcp(struct mcp_plat_data *data);
struct sa1100fb_mach_info; struct sa1100fb_mach_info;
......
...@@ -16,7 +16,7 @@ struct mcp_plat_data { ...@@ -16,7 +16,7 @@ struct mcp_plat_data {
u32 mccr0; u32 mccr0;
u32 mccr1; u32 mccr1;
unsigned int sclk_rate; unsigned int sclk_rate;
int gpio_base; void *codec_pdata;
}; };
#endif #endif
...@@ -107,6 +107,7 @@ static void __init lart_init(void) ...@@ -107,6 +107,7 @@ static void __init lart_init(void)
if (inf) if (inf)
sa11x0_register_lcd(inf); sa11x0_register_lcd(inf);
sa11x0_ppc_configure_mcp();
sa11x0_register_mcp(&lart_mcp_data); sa11x0_register_mcp(&lart_mcp_data);
} }
......
...@@ -72,6 +72,7 @@ static struct sa1100fb_mach_info shannon_lcd_info = { ...@@ -72,6 +72,7 @@ static struct sa1100fb_mach_info shannon_lcd_info = {
static void __init shannon_init(void) static void __init shannon_init(void)
{ {
sa11x0_ppc_configure_mcp();
sa11x0_register_lcd(&shannon_lcd_info); sa11x0_register_lcd(&shannon_lcd_info);
sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1); sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1);
sa11x0_register_mcp(&shannon_mcp_data); sa11x0_register_mcp(&shannon_mcp_data);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mfd/ucb1x00.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -180,10 +181,14 @@ static struct resource simpad_flash_resources [] = { ...@@ -180,10 +181,14 @@ static struct resource simpad_flash_resources [] = {
DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_16M), DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_16M),
}; };
static struct ucb1x00_plat_data simpad_ucb1x00_data = {
.gpio_base = SIMPAD_UCB1X00_GPIO_BASE,
};
static struct mcp_plat_data simpad_mcp_data = { static struct mcp_plat_data simpad_mcp_data = {
.mccr0 = MCCR0_ADM, .mccr0 = MCCR0_ADM,
.sclk_rate = 11981000, .sclk_rate = 11981000,
.gpio_base = SIMPAD_UCB1X00_GPIO_BASE, .codec_pdata = &simpad_ucb1x00_data,
}; };
...@@ -369,6 +374,7 @@ static int __init simpad_init(void) ...@@ -369,6 +374,7 @@ static int __init simpad_init(void)
pm_power_off = simpad_power_off; pm_power_off = simpad_power_off;
sa11x0_ppc_configure_mcp();
sa11x0_register_mtd(&simpad_flash_data, simpad_flash_resources, sa11x0_register_mtd(&simpad_flash_data, simpad_flash_resources,
ARRAY_SIZE(simpad_flash_resources)); ARRAY_SIZE(simpad_flash_resources));
sa11x0_register_mcp(&simpad_mcp_data); sa11x0_register_mcp(&simpad_mcp_data);
......
...@@ -847,8 +847,9 @@ config MCP_SA11X0 ...@@ -847,8 +847,9 @@ config MCP_SA11X0
# Chip drivers # Chip drivers
config MCP_UCB1200 config MCP_UCB1200
tristate "Support for UCB1200 / UCB1300" bool "Support for UCB1200 / UCB1300"
depends on MCP depends on MCP_SA11X0
select MCP
config MCP_UCB1200_TS config MCP_UCB1200_TS
tristate "Touchscreen interface support" tristate "Touchscreen interface support"
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/mfd/mcp.h> #include <linux/mfd/mcp.h>
#include <mach/dma.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -48,39 +47,11 @@ static int mcp_bus_remove(struct device *dev) ...@@ -48,39 +47,11 @@ static int mcp_bus_remove(struct device *dev)
return 0; return 0;
} }
static int mcp_bus_suspend(struct device *dev, pm_message_t state)
{
struct mcp *mcp = to_mcp(dev);
int ret = 0;
if (dev->driver) {
struct mcp_driver *drv = to_mcp_driver(dev->driver);
ret = drv->suspend(mcp, state);
}
return ret;
}
static int mcp_bus_resume(struct device *dev)
{
struct mcp *mcp = to_mcp(dev);
int ret = 0;
if (dev->driver) {
struct mcp_driver *drv = to_mcp_driver(dev->driver);
ret = drv->resume(mcp);
}
return ret;
}
static struct bus_type mcp_bus_type = { static struct bus_type mcp_bus_type = {
.name = "mcp", .name = "mcp",
.match = mcp_bus_match, .match = mcp_bus_match,
.probe = mcp_bus_probe, .probe = mcp_bus_probe,
.remove = mcp_bus_remove, .remove = mcp_bus_remove,
.suspend = mcp_bus_suspend,
.resume = mcp_bus_resume,
}; };
/** /**
...@@ -208,6 +179,7 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size) ...@@ -208,6 +179,7 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL); mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL);
if (mcp) { if (mcp) {
spin_lock_init(&mcp->lock); spin_lock_init(&mcp->lock);
device_initialize(&mcp->attached_device);
mcp->attached_device.parent = parent; mcp->attached_device.parent = parent;
mcp->attached_device.bus = &mcp_bus_type; mcp->attached_device.bus = &mcp_bus_type;
mcp->attached_device.dma_mask = parent->dma_mask; mcp->attached_device.dma_mask = parent->dma_mask;
...@@ -217,18 +189,25 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size) ...@@ -217,18 +189,25 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
} }
EXPORT_SYMBOL(mcp_host_alloc); EXPORT_SYMBOL(mcp_host_alloc);
int mcp_host_register(struct mcp *mcp) int mcp_host_add(struct mcp *mcp, void *pdata)
{ {
mcp->attached_device.platform_data = pdata;
dev_set_name(&mcp->attached_device, "mcp0"); dev_set_name(&mcp->attached_device, "mcp0");
return device_register(&mcp->attached_device); return device_add(&mcp->attached_device);
}
EXPORT_SYMBOL(mcp_host_add);
void mcp_host_del(struct mcp *mcp)
{
device_del(&mcp->attached_device);
} }
EXPORT_SYMBOL(mcp_host_register); EXPORT_SYMBOL(mcp_host_del);
void mcp_host_unregister(struct mcp *mcp) void mcp_host_free(struct mcp *mcp)
{ {
device_unregister(&mcp->attached_device); put_device(&mcp->attached_device);
} }
EXPORT_SYMBOL(mcp_host_unregister); EXPORT_SYMBOL(mcp_host_free);
int mcp_driver_register(struct mcp_driver *mcpdrv) int mcp_driver_register(struct mcp_driver *mcpdrv)
{ {
......
...@@ -13,51 +13,61 @@ ...@@ -13,51 +13,61 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/mfd/mcp.h> #include <linux/mfd/mcp.h>
#include <mach/dma.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/system.h> #include <asm/system.h>
#include <mach/mcp.h> #include <mach/mcp.h>
#include <mach/assabet.h> #define DRIVER_NAME "sa11x0-mcp"
struct mcp_sa11x0 { struct mcp_sa11x0 {
u32 mccr0; void __iomem *base0;
u32 mccr1; void __iomem *base1;
u32 mccr0;
u32 mccr1;
}; };
/* Register offsets */
#define MCCR0(m) ((m)->base0 + 0x00)
#define MCDR0(m) ((m)->base0 + 0x08)
#define MCDR1(m) ((m)->base0 + 0x0c)
#define MCDR2(m) ((m)->base0 + 0x10)
#define MCSR(m) ((m)->base0 + 0x18)
#define MCCR1(m) ((m)->base1 + 0x00)
#define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp)) #define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp))
static void static void
mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor) mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
{ {
unsigned int mccr0; struct mcp_sa11x0 *m = priv(mcp);
divisor /= 32; divisor /= 32;
mccr0 = Ser4MCCR0 & ~0x00007f00; m->mccr0 &= ~0x00007f00;
mccr0 |= divisor << 8; m->mccr0 |= divisor << 8;
Ser4MCCR0 = mccr0; writel_relaxed(m->mccr0, MCCR0(m));
} }
static void static void
mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor) mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
{ {
unsigned int mccr0; struct mcp_sa11x0 *m = priv(mcp);
divisor /= 32; divisor /= 32;
mccr0 = Ser4MCCR0 & ~0x0000007f; m->mccr0 &= ~0x0000007f;
mccr0 |= divisor; m->mccr0 |= divisor;
Ser4MCCR0 = mccr0; writel_relaxed(m->mccr0, MCCR0(m));
} }
/* /*
...@@ -69,14 +79,15 @@ mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor) ...@@ -69,14 +79,15 @@ mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
static void static void
mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val) mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
{ {
struct mcp_sa11x0 *m = priv(mcp);
int ret = -ETIME; int ret = -ETIME;
int i; int i;
Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff); writel_relaxed(reg << 17 | MCDR2_Wr | (val & 0xffff), MCDR2(m));
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
udelay(mcp->rw_timeout); udelay(mcp->rw_timeout);
if (Ser4MCSR & MCSR_CWC) { if (readl_relaxed(MCSR(m)) & MCSR_CWC) {
ret = 0; ret = 0;
break; break;
} }
...@@ -95,15 +106,16 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val) ...@@ -95,15 +106,16 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
static unsigned int static unsigned int
mcp_sa11x0_read(struct mcp *mcp, unsigned int reg) mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
{ {
struct mcp_sa11x0 *m = priv(mcp);
int ret = -ETIME; int ret = -ETIME;
int i; int i;
Ser4MCDR2 = reg << 17 | MCDR2_Rd; writel_relaxed(reg << 17 | MCDR2_Rd, MCDR2(m));
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
udelay(mcp->rw_timeout); udelay(mcp->rw_timeout);
if (Ser4MCSR & MCSR_CRC) { if (readl_relaxed(MCSR(m)) & MCSR_CRC) {
ret = Ser4MCDR2 & 0xffff; ret = readl_relaxed(MCDR2(m)) & 0xffff;
break; break;
} }
} }
...@@ -116,13 +128,19 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg) ...@@ -116,13 +128,19 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
static void mcp_sa11x0_enable(struct mcp *mcp) static void mcp_sa11x0_enable(struct mcp *mcp)
{ {
Ser4MCSR = -1; struct mcp_sa11x0 *m = priv(mcp);
Ser4MCCR0 |= MCCR0_MCE;
writel(-1, MCSR(m));
m->mccr0 |= MCCR0_MCE;
writel_relaxed(m->mccr0, MCCR0(m));
} }
static void mcp_sa11x0_disable(struct mcp *mcp) static void mcp_sa11x0_disable(struct mcp *mcp)
{ {
Ser4MCCR0 &= ~MCCR0_MCE; struct mcp_sa11x0 *m = priv(mcp);
m->mccr0 &= ~MCCR0_MCE;
writel_relaxed(m->mccr0, MCCR0(m));
} }
/* /*
...@@ -137,55 +155,64 @@ static struct mcp_ops mcp_sa11x0 = { ...@@ -137,55 +155,64 @@ static struct mcp_ops mcp_sa11x0 = {
.disable = mcp_sa11x0_disable, .disable = mcp_sa11x0_disable,
}; };
static int mcp_sa11x0_probe(struct platform_device *pdev) static int mcp_sa11x0_probe(struct platform_device *dev)
{ {
struct mcp_plat_data *data = pdev->dev.platform_data; struct mcp_plat_data *data = dev->dev.platform_data;
struct resource *mem0, *mem1;
struct mcp_sa11x0 *m;
struct mcp *mcp; struct mcp *mcp;
int ret; int ret;
if (!data) if (!data)
return -ENODEV; return -ENODEV;
if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp")) mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
return -EBUSY; mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
if (!mem0 || !mem1)
return -ENXIO;
if (!request_mem_region(mem0->start, resource_size(mem0),
DRIVER_NAME)) {
ret = -EBUSY;
goto err_mem0;
}
mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0)); if (!request_mem_region(mem1->start, resource_size(mem1),
DRIVER_NAME)) {
ret = -EBUSY;
goto err_mem1;
}
mcp = mcp_host_alloc(&dev->dev, sizeof(struct mcp_sa11x0));
if (!mcp) { if (!mcp) {
ret = -ENOMEM; ret = -ENOMEM;
goto release; goto err_alloc;
} }
mcp->owner = THIS_MODULE; mcp->owner = THIS_MODULE;
mcp->ops = &mcp_sa11x0; mcp->ops = &mcp_sa11x0;
mcp->sclk_rate = data->sclk_rate; mcp->sclk_rate = data->sclk_rate;
mcp->dma_audio_rd = DMA_Ser4MCP0Rd;
mcp->dma_audio_wr = DMA_Ser4MCP0Wr;
mcp->dma_telco_rd = DMA_Ser4MCP1Rd;
mcp->dma_telco_wr = DMA_Ser4MCP1Wr;
mcp->gpio_base = data->gpio_base;
platform_set_drvdata(pdev, mcp); m = priv(mcp);
m->mccr0 = data->mccr0 | 0x7f7f;
m->mccr1 = data->mccr1;
if (machine_is_assabet()) { m->base0 = ioremap(mem0->start, resource_size(mem0));
ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); m->base1 = ioremap(mem1->start, resource_size(mem1));
if (!m->base0 || !m->base1) {
ret = -ENOMEM;
goto err_ioremap;
} }
/* platform_set_drvdata(dev, mcp);
* Setup the PPC unit correctly.
*/
PPDR &= ~PPC_RXD4;
PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
PSDR |= PPC_RXD4;
PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
/* /*
* Initialise device. Note that we initially * Initialise device. Note that we initially
* set the sampling rate to minimum. * set the sampling rate to minimum.
*/ */
Ser4MCSR = -1; writel_relaxed(-1, MCSR(m));
Ser4MCCR1 = data->mccr1; writel_relaxed(m->mccr1, MCCR1(m));
Ser4MCCR0 = data->mccr0 | 0x7f7f; writel_relaxed(m->mccr0, MCCR0(m));
/* /*
* Calculate the read/write timeout (us) from the bit clock * Calculate the read/write timeout (us) from the bit clock
...@@ -195,62 +222,90 @@ static int mcp_sa11x0_probe(struct platform_device *pdev) ...@@ -195,62 +222,90 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) / mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
mcp->sclk_rate; mcp->sclk_rate;
ret = mcp_host_register(mcp); ret = mcp_host_add(mcp, data->codec_pdata);
if (ret == 0) if (ret == 0)
goto out; return 0;
release: platform_set_drvdata(dev, NULL);
release_mem_region(0x80060000, 0x60);
platform_set_drvdata(pdev, NULL);
out: err_ioremap:
iounmap(m->base1);
iounmap(m->base0);
mcp_host_free(mcp);
err_alloc:
release_mem_region(mem1->start, resource_size(mem1));
err_mem1:
release_mem_region(mem0->start, resource_size(mem0));
err_mem0:
return ret; return ret;
} }
static int mcp_sa11x0_remove(struct platform_device *dev) static int mcp_sa11x0_remove(struct platform_device *dev)
{ {
struct mcp *mcp = platform_get_drvdata(dev); struct mcp *mcp = platform_get_drvdata(dev);
struct mcp_sa11x0 *m = priv(mcp);
struct resource *mem0, *mem1;
if (m->mccr0 & MCCR0_MCE)
dev_warn(&dev->dev,
"device left active (missing disable call?)\n");
mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
platform_set_drvdata(dev, NULL); platform_set_drvdata(dev, NULL);
mcp_host_unregister(mcp); mcp_host_del(mcp);
release_mem_region(0x80060000, 0x60); iounmap(m->base1);
iounmap(m->base0);
mcp_host_free(mcp);
release_mem_region(mem1->start, resource_size(mem1));
release_mem_region(mem0->start, resource_size(mem0));
return 0; return 0;
} }
static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state) #ifdef CONFIG_PM_SLEEP
static int mcp_sa11x0_suspend(struct device *dev)
{ {
struct mcp *mcp = platform_get_drvdata(dev); struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
if (m->mccr0 & MCCR0_MCE)
dev_warn(dev, "device left active (missing disable call?)\n");
priv(mcp)->mccr0 = Ser4MCCR0; writel(m->mccr0 & ~MCCR0_MCE, MCCR0(m));
priv(mcp)->mccr1 = Ser4MCCR1;
Ser4MCCR0 &= ~MCCR0_MCE;
return 0; return 0;
} }
static int mcp_sa11x0_resume(struct platform_device *dev) static int mcp_sa11x0_resume(struct device *dev)
{ {
struct mcp *mcp = platform_get_drvdata(dev); struct mcp_sa11x0 *m = priv(dev_get_drvdata(dev));
Ser4MCCR1 = priv(mcp)->mccr1; writel_relaxed(m->mccr1, MCCR1(m));
Ser4MCCR0 = priv(mcp)->mccr0; writel_relaxed(m->mccr0, MCCR0(m));
return 0; return 0;
} }
#endif
/*
* The driver for the SA11x0 MCP port. static const struct dev_pm_ops mcp_sa11x0_pm_ops = {
*/ #ifdef CONFIG_PM_SLEEP
MODULE_ALIAS("platform:sa11x0-mcp"); .suspend = mcp_sa11x0_suspend,
.freeze = mcp_sa11x0_suspend,
.poweroff = mcp_sa11x0_suspend,
.resume_noirq = mcp_sa11x0_resume,
.thaw_noirq = mcp_sa11x0_resume,
.restore_noirq = mcp_sa11x0_resume,
#endif
};
static struct platform_driver mcp_sa11x0_driver = { static struct platform_driver mcp_sa11x0_driver = {
.probe = mcp_sa11x0_probe, .probe = mcp_sa11x0_probe,
.remove = mcp_sa11x0_remove, .remove = mcp_sa11x0_remove,
.suspend = mcp_sa11x0_suspend,
.resume = mcp_sa11x0_resume,
.driver = { .driver = {
.name = "sa11x0-mcp", .name = DRIVER_NAME,
.owner = THIS_MODULE,
.pm = &mcp_sa11x0_pm_ops,
}, },
}; };
...@@ -259,6 +314,7 @@ static struct platform_driver mcp_sa11x0_driver = { ...@@ -259,6 +314,7 @@ static struct platform_driver mcp_sa11x0_driver = {
*/ */
module_platform_driver(mcp_sa11x0_driver); module_platform_driver(mcp_sa11x0_driver);
MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
MODULE_DESCRIPTION("SA11x0 multimedia communications port driver"); MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -11,14 +11,15 @@ ...@@ -11,14 +11,15 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/mfd/ucb1x00.h> #include <linux/mfd/ucb1x00.h>
#include <mach/dma.h>
#define UCB1X00_ATTR(name,input)\ #define UCB1X00_ATTR(name,input)\
static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \ static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
char *buf) \ char *buf) \
...@@ -38,14 +39,45 @@ UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2); ...@@ -38,14 +39,45 @@ UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2);
static int ucb1x00_assabet_add(struct ucb1x00_dev *dev) static int ucb1x00_assabet_add(struct ucb1x00_dev *dev)
{ {
device_create_file(&dev->ucb->dev, &dev_attr_vbatt); struct ucb1x00 *ucb = dev->ucb;
device_create_file(&dev->ucb->dev, &dev_attr_vcharger); struct platform_device *pdev;
device_create_file(&dev->ucb->dev, &dev_attr_batt_temp); struct gpio_keys_platform_data keys;
static struct gpio_keys_button buttons[6];
unsigned i;
memset(buttons, 0, sizeof(buttons));
memset(&keys, 0, sizeof(keys));
for (i = 0; i < ARRAY_SIZE(buttons); i++) {
buttons[i].code = BTN_0 + i;
buttons[i].gpio = ucb->gpio.base + i;
buttons[i].type = EV_KEY;
buttons[i].can_disable = true;
}
keys.buttons = buttons;
keys.nbuttons = ARRAY_SIZE(buttons);
keys.poll_interval = 50;
keys.name = "ucb1x00";
pdev = platform_device_register_data(&ucb->dev, "gpio-keys", -1,
&keys, sizeof(keys));
device_create_file(&ucb->dev, &dev_attr_vbatt);
device_create_file(&ucb->dev, &dev_attr_vcharger);
device_create_file(&ucb->dev, &dev_attr_batt_temp);
dev->priv = pdev;
return 0; return 0;
} }
static void ucb1x00_assabet_remove(struct ucb1x00_dev *dev) static void ucb1x00_assabet_remove(struct ucb1x00_dev *dev)
{ {
struct platform_device *pdev = dev->priv;
if (!IS_ERR(pdev))
platform_device_unregister(pdev);
device_remove_file(&dev->ucb->dev, &dev_attr_batt_temp); device_remove_file(&dev->ucb->dev, &dev_attr_batt_temp);
device_remove_file(&dev->ucb->dev, &dev_attr_vcharger); device_remove_file(&dev->ucb->dev, &dev_attr_vcharger);
device_remove_file(&dev->ucb->dev, &dev_attr_vbatt); device_remove_file(&dev->ucb->dev, &dev_attr_vbatt);
......
This diff is collapsed.
...@@ -20,8 +20,9 @@ ...@@ -20,8 +20,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/smp.h> #include <linux/interrupt.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/string.h> #include <linux/string.h>
...@@ -32,7 +33,6 @@ ...@@ -32,7 +33,6 @@
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/mfd/ucb1x00.h> #include <linux/mfd/ucb1x00.h>
#include <mach/dma.h>
#include <mach/collie.h> #include <mach/collie.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
...@@ -42,6 +42,8 @@ struct ucb1x00_ts { ...@@ -42,6 +42,8 @@ struct ucb1x00_ts {
struct input_dev *idev; struct input_dev *idev;
struct ucb1x00 *ucb; struct ucb1x00 *ucb;
spinlock_t irq_lock;
unsigned irq_disabled;
wait_queue_head_t irq_wait; wait_queue_head_t irq_wait;
struct task_struct *rtask; struct task_struct *rtask;
u16 x_res; u16 x_res;
...@@ -238,7 +240,12 @@ static int ucb1x00_thread(void *_ts) ...@@ -238,7 +240,12 @@ static int ucb1x00_thread(void *_ts)
if (ucb1x00_ts_pen_down(ts)) { if (ucb1x00_ts_pen_down(ts)) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING); spin_lock_irq(&ts->irq_lock);
if (ts->irq_disabled) {
ts->irq_disabled = 0;
enable_irq(ts->ucb->irq_base + UCB_IRQ_TSPX);
}
spin_unlock_irq(&ts->irq_lock);
ucb1x00_disable(ts->ucb); ucb1x00_disable(ts->ucb);
/* /*
...@@ -281,23 +288,37 @@ static int ucb1x00_thread(void *_ts) ...@@ -281,23 +288,37 @@ static int ucb1x00_thread(void *_ts)
* We only detect touch screen _touches_ with this interrupt * We only detect touch screen _touches_ with this interrupt
* handler, and even then we just schedule our task. * handler, and even then we just schedule our task.
*/ */
static void ucb1x00_ts_irq(int idx, void *id) static irqreturn_t ucb1x00_ts_irq(int irq, void *id)
{ {
struct ucb1x00_ts *ts = id; struct ucb1x00_ts *ts = id;
ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING); spin_lock(&ts->irq_lock);
ts->irq_disabled = 1;
disable_irq_nosync(ts->ucb->irq_base + UCB_IRQ_TSPX);
spin_unlock(&ts->irq_lock);
wake_up(&ts->irq_wait); wake_up(&ts->irq_wait);
return IRQ_HANDLED;
} }
static int ucb1x00_ts_open(struct input_dev *idev) static int ucb1x00_ts_open(struct input_dev *idev)
{ {
struct ucb1x00_ts *ts = input_get_drvdata(idev); struct ucb1x00_ts *ts = input_get_drvdata(idev);
unsigned long flags = 0;
int ret = 0; int ret = 0;
BUG_ON(ts->rtask); BUG_ON(ts->rtask);
if (machine_is_collie())
flags = IRQF_TRIGGER_RISING;
else
flags = IRQF_TRIGGER_FALLING;
ts->irq_disabled = 0;
init_waitqueue_head(&ts->irq_wait); init_waitqueue_head(&ts->irq_wait);
ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts); ret = request_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ucb1x00_ts_irq,
flags, "ucb1x00-ts", ts);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -314,7 +335,7 @@ static int ucb1x00_ts_open(struct input_dev *idev) ...@@ -314,7 +335,7 @@ static int ucb1x00_ts_open(struct input_dev *idev)
if (!IS_ERR(ts->rtask)) { if (!IS_ERR(ts->rtask)) {
ret = 0; ret = 0;
} else { } else {
ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts);
ts->rtask = NULL; ts->rtask = NULL;
ret = -EFAULT; ret = -EFAULT;
} }
...@@ -334,7 +355,7 @@ static void ucb1x00_ts_close(struct input_dev *idev) ...@@ -334,7 +355,7 @@ static void ucb1x00_ts_close(struct input_dev *idev)
kthread_stop(ts->rtask); kthread_stop(ts->rtask);
ucb1x00_enable(ts->ucb); ucb1x00_enable(ts->ucb);
ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts);
ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
ucb1x00_disable(ts->ucb); ucb1x00_disable(ts->ucb);
} }
...@@ -359,11 +380,13 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) ...@@ -359,11 +380,13 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
ts->ucb = dev->ucb; ts->ucb = dev->ucb;
ts->idev = idev; ts->idev = idev;
ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
spin_lock_init(&ts->irq_lock);
idev->name = "Touchscreen panel"; idev->name = "Touchscreen panel";
idev->id.product = ts->ucb->id; idev->id.product = ts->ucb->id;
idev->open = ucb1x00_ts_open; idev->open = ucb1x00_ts_open;
idev->close = ucb1x00_ts_close; idev->close = ucb1x00_ts_close;
idev->dev.parent = &ts->ucb->dev;
idev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); idev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
......
...@@ -10,8 +10,6 @@ ...@@ -10,8 +10,6 @@
#ifndef MCP_H #ifndef MCP_H
#define MCP_H #define MCP_H
#include <mach/dma.h>
struct mcp_ops; struct mcp_ops;
struct mcp { struct mcp {
...@@ -21,12 +19,7 @@ struct mcp { ...@@ -21,12 +19,7 @@ struct mcp {
int use_count; int use_count;
unsigned int sclk_rate; unsigned int sclk_rate;
unsigned int rw_timeout; unsigned int rw_timeout;
dma_device_t dma_audio_rd;
dma_device_t dma_audio_wr;
dma_device_t dma_telco_rd;
dma_device_t dma_telco_wr;
struct device attached_device; struct device attached_device;
int gpio_base;
}; };
struct mcp_ops { struct mcp_ops {
...@@ -47,15 +40,14 @@ void mcp_disable(struct mcp *); ...@@ -47,15 +40,14 @@ void mcp_disable(struct mcp *);
#define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate) #define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate)
struct mcp *mcp_host_alloc(struct device *, size_t); struct mcp *mcp_host_alloc(struct device *, size_t);
int mcp_host_register(struct mcp *); int mcp_host_add(struct mcp *, void *);
void mcp_host_unregister(struct mcp *); void mcp_host_del(struct mcp *);
void mcp_host_free(struct mcp *);
struct mcp_driver { struct mcp_driver {
struct device_driver drv; struct device_driver drv;
int (*probe)(struct mcp *); int (*probe)(struct mcp *);
void (*remove)(struct mcp *); void (*remove)(struct mcp *);
int (*suspend)(struct mcp *, pm_message_t);
int (*resume)(struct mcp *);
}; };
int mcp_driver_register(struct mcp_driver *); int mcp_driver_register(struct mcp_driver *);
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include <linux/mfd/mcp.h> #include <linux/mfd/mcp.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/semaphore.h> #include <linux/mutex.h>
#define UCB_IO_DATA 0x00 #define UCB_IO_DATA 0x00
#define UCB_IO_DIR 0x01 #define UCB_IO_DIR 0x01
...@@ -104,17 +104,27 @@ ...@@ -104,17 +104,27 @@
#define UCB_MODE_DYN_VFLAG_ENA (1 << 12) #define UCB_MODE_DYN_VFLAG_ENA (1 << 12)
#define UCB_MODE_AUD_OFF_CAN (1 << 13) #define UCB_MODE_AUD_OFF_CAN (1 << 13)
enum ucb1x00_reset {
UCB_RST_PROBE,
UCB_RST_RESUME,
UCB_RST_SUSPEND,
UCB_RST_REMOVE,
UCB_RST_PROBE_FAIL,
};
struct ucb1x00_irq { struct ucb1x00_plat_data {
void *devid; void (*reset)(enum ucb1x00_reset);
void (*fn)(int, void *); unsigned irq_base;
int gpio_base;
unsigned can_wakeup;
}; };
struct ucb1x00 { struct ucb1x00 {
spinlock_t lock; raw_spinlock_t irq_lock;
struct mcp *mcp; struct mcp *mcp;
unsigned int irq; unsigned int irq;
struct semaphore adc_sem; int irq_base;
struct mutex adc_mutex;
spinlock_t io_lock; spinlock_t io_lock;
u16 id; u16 id;
u16 io_dir; u16 io_dir;
...@@ -122,7 +132,8 @@ struct ucb1x00 { ...@@ -122,7 +132,8 @@ struct ucb1x00 {
u16 adc_cr; u16 adc_cr;
u16 irq_fal_enbl; u16 irq_fal_enbl;
u16 irq_ris_enbl; u16 irq_ris_enbl;
struct ucb1x00_irq irq_handler[16]; u16 irq_mask;
u16 irq_wake;
struct device dev; struct device dev;
struct list_head node; struct list_head node;
struct list_head devs; struct list_head devs;
...@@ -144,7 +155,7 @@ struct ucb1x00_driver { ...@@ -144,7 +155,7 @@ struct ucb1x00_driver {
struct list_head devs; struct list_head devs;
int (*add)(struct ucb1x00_dev *dev); int (*add)(struct ucb1x00_dev *dev);
void (*remove)(struct ucb1x00_dev *dev); void (*remove)(struct ucb1x00_dev *dev);
int (*suspend)(struct ucb1x00_dev *dev, pm_message_t state); int (*suspend)(struct ucb1x00_dev *dev);
int (*resume)(struct ucb1x00_dev *dev); int (*resume)(struct ucb1x00_dev *dev);
}; };
...@@ -245,15 +256,4 @@ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync); ...@@ -245,15 +256,4 @@ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync);
void ucb1x00_adc_enable(struct ucb1x00 *ucb); void ucb1x00_adc_enable(struct ucb1x00 *ucb);
void ucb1x00_adc_disable(struct ucb1x00 *ucb); void ucb1x00_adc_disable(struct ucb1x00 *ucb);
/*
* Which edges of the IRQ do you want to control today?
*/
#define UCB_RISING (1 << 0)
#define UCB_FALLING (1 << 1)
int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid);
void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment