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 @@
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/serial_core.h>
#include <linux/mfd/ucb1x00.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
......@@ -71,6 +72,12 @@ void ASSABET_BCR_frob(unsigned int mask, unsigned int val)
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.
......@@ -167,9 +174,15 @@ static struct irda_platform_data assabet_irda_data = {
.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 = {
.mccr0 = MCCR0_ADM,
.sclk_rate = 11981000,
.codec_pdata = &assabet_ucb1x00_data,
};
static void assabet_lcd_set_visual(u32 visual)
......@@ -309,6 +322,8 @@ static void __init assabet_init(void)
PPDR |= PPC_TXD3 | PPC_TXD1;
PPSR |= PPC_TXD3 | PPC_TXD1;
sa11x0_ppc_configure_mcp();
if (machine_has_neponset()) {
/*
* Angel sets this, but other bootloaders may not.
......
......@@ -121,6 +121,7 @@ static struct mcp_plat_data cerf_mcp_data = {
static void __init cerf_init(void)
{
sa11x0_ppc_configure_mcp();
platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1);
sa11x0_register_mcp(&cerf_mcp_data);
......
......@@ -22,6 +22,7 @@
#include <linux/tty.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/mfd/ucb1x00.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/timer.h>
......@@ -83,10 +84,14 @@ static struct scoop_pcmcia_config collie_pcmcia_config = {
.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 = {
.mccr0 = MCCR0_ADM | MCCR0_ExtClk,
.sclk_rate = 9216000,
.gpio_base = COLLIE_TC35143_GPIO_BASE,
.codec_pdata = &collie_ucb1x00_data,
};
/*
......@@ -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].end = gpio_to_irq(COLLIE_GPIO_AC_IN);
sa11x0_ppc_configure_mcp();
platform_scoop_config = &collie_pcmcia_config;
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
......
......@@ -195,7 +195,8 @@ static struct platform_device sa11x0uart3_device = {
static struct resource sa11x0mcp_resources[] = {
[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;
......@@ -211,6 +212,16 @@ static struct platform_device sa11x0mcp_device = {
.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)
{
sa11x0_register_device(&sa11x0mcp_device, data);
......
......@@ -36,6 +36,7 @@ struct irda_platform_data;
void sa11x0_register_irda(struct irda_platform_data *irda);
struct mcp_plat_data;
void sa11x0_ppc_configure_mcp(void);
void sa11x0_register_mcp(struct mcp_plat_data *data);
struct sa1100fb_mach_info;
......
......@@ -16,7 +16,7 @@ struct mcp_plat_data {
u32 mccr0;
u32 mccr1;
unsigned int sclk_rate;
int gpio_base;
void *codec_pdata;
};
#endif
......@@ -107,6 +107,7 @@ static void __init lart_init(void)
if (inf)
sa11x0_register_lcd(inf);
sa11x0_ppc_configure_mcp();
sa11x0_register_mcp(&lart_mcp_data);
}
......
......@@ -72,6 +72,7 @@ static struct sa1100fb_mach_info shannon_lcd_info = {
static void __init shannon_init(void)
{
sa11x0_ppc_configure_mcp();
sa11x0_register_lcd(&shannon_lcd_info);
sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1);
sa11x0_register_mcp(&shannon_mcp_data);
......
......@@ -10,6 +10,7 @@
#include <linux/string.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/mfd/ucb1x00.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/io.h>
......@@ -180,10 +181,14 @@ static struct resource simpad_flash_resources [] = {
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 = {
.mccr0 = MCCR0_ADM,
.sclk_rate = 11981000,
.gpio_base = SIMPAD_UCB1X00_GPIO_BASE,
.codec_pdata = &simpad_ucb1x00_data,
};
......@@ -369,6 +374,7 @@ static int __init simpad_init(void)
pm_power_off = simpad_power_off;
sa11x0_ppc_configure_mcp();
sa11x0_register_mtd(&simpad_flash_data, simpad_flash_resources,
ARRAY_SIZE(simpad_flash_resources));
sa11x0_register_mcp(&simpad_mcp_data);
......
......@@ -847,8 +847,9 @@ config MCP_SA11X0
# Chip drivers
config MCP_UCB1200
tristate "Support for UCB1200 / UCB1300"
depends on MCP
bool "Support for UCB1200 / UCB1300"
depends on MCP_SA11X0
select MCP
config MCP_UCB1200_TS
tristate "Touchscreen interface support"
......
......@@ -19,7 +19,6 @@
#include <linux/string.h>
#include <linux/mfd/mcp.h>
#include <mach/dma.h>
#include <asm/system.h>
......@@ -48,39 +47,11 @@ static int mcp_bus_remove(struct device *dev)
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 = {
.name = "mcp",
.match = mcp_bus_match,
.probe = mcp_bus_probe,
.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)
mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL);
if (mcp) {
spin_lock_init(&mcp->lock);
device_initialize(&mcp->attached_device);
mcp->attached_device.parent = parent;
mcp->attached_device.bus = &mcp_bus_type;
mcp->attached_device.dma_mask = parent->dma_mask;
......@@ -217,18 +189,25 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
}
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");
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)
{
......
......@@ -13,51 +13,61 @@
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/mfd/mcp.h>
#include <mach/dma.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/system.h>
#include <mach/mcp.h>
#include <mach/assabet.h>
#define DRIVER_NAME "sa11x0-mcp"
struct mcp_sa11x0 {
u32 mccr0;
u32 mccr1;
void __iomem *base0;
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))
static void
mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
{
unsigned int mccr0;
struct mcp_sa11x0 *m = priv(mcp);
divisor /= 32;
mccr0 = Ser4MCCR0 & ~0x00007f00;
mccr0 |= divisor << 8;
Ser4MCCR0 = mccr0;
m->mccr0 &= ~0x00007f00;
m->mccr0 |= divisor << 8;
writel_relaxed(m->mccr0, MCCR0(m));
}
static void
mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
{
unsigned int mccr0;
struct mcp_sa11x0 *m = priv(mcp);
divisor /= 32;
mccr0 = Ser4MCCR0 & ~0x0000007f;
mccr0 |= divisor;
Ser4MCCR0 = mccr0;
m->mccr0 &= ~0x0000007f;
m->mccr0 |= divisor;
writel_relaxed(m->mccr0, MCCR0(m));
}
/*
......@@ -69,14 +79,15 @@ mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
static void
mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
{
struct mcp_sa11x0 *m = priv(mcp);
int ret = -ETIME;
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++) {
udelay(mcp->rw_timeout);
if (Ser4MCSR & MCSR_CWC) {
if (readl_relaxed(MCSR(m)) & MCSR_CWC) {
ret = 0;
break;
}
......@@ -95,15 +106,16 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
static unsigned int
mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
{
struct mcp_sa11x0 *m = priv(mcp);
int ret = -ETIME;
int i;
Ser4MCDR2 = reg << 17 | MCDR2_Rd;
writel_relaxed(reg << 17 | MCDR2_Rd, MCDR2(m));
for (i = 0; i < 2; i++) {
udelay(mcp->rw_timeout);
if (Ser4MCSR & MCSR_CRC) {
ret = Ser4MCDR2 & 0xffff;
if (readl_relaxed(MCSR(m)) & MCSR_CRC) {
ret = readl_relaxed(MCDR2(m)) & 0xffff;
break;
}
}
......@@ -116,13 +128,19 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
static void mcp_sa11x0_enable(struct mcp *mcp)
{
Ser4MCSR = -1;
Ser4MCCR0 |= MCCR0_MCE;
struct mcp_sa11x0 *m = priv(mcp);
writel(-1, MCSR(m));
m->mccr0 |= MCCR0_MCE;
writel_relaxed(m->mccr0, MCCR0(m));
}
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 = {
.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;
int ret;
if (!data)
return -ENODEV;
if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
return -EBUSY;
mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
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) {
ret = -ENOMEM;
goto release;
goto err_alloc;
}
mcp->owner = THIS_MODULE;
mcp->ops = &mcp_sa11x0;
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()) {
ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
m->base0 = ioremap(mem0->start, resource_size(mem0));
m->base1 = ioremap(mem1->start, resource_size(mem1));
if (!m->base0 || !m->base1) {
ret = -ENOMEM;
goto err_ioremap;
}
/*
* 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);
platform_set_drvdata(dev, mcp);
/*
* Initialise device. Note that we initially
* set the sampling rate to minimum.
*/
Ser4MCSR = -1;
Ser4MCCR1 = data->mccr1;
Ser4MCCR0 = data->mccr0 | 0x7f7f;
writel_relaxed(-1, MCSR(m));
writel_relaxed(m->mccr1, MCCR1(m));
writel_relaxed(m->mccr0, MCCR0(m));
/*
* Calculate the read/write timeout (us) from the bit clock
......@@ -195,62 +222,90 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
mcp->sclk_rate;
ret = mcp_host_register(mcp);
ret = mcp_host_add(mcp, data->codec_pdata);
if (ret == 0)
goto out;
return 0;
release:
release_mem_region(0x80060000, 0x60);
platform_set_drvdata(pdev, NULL);
platform_set_drvdata(dev, 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;
}
static int mcp_sa11x0_remove(struct platform_device *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);
mcp_host_unregister(mcp);
release_mem_region(0x80060000, 0x60);
mcp_host_del(mcp);
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;
}
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;
priv(mcp)->mccr1 = Ser4MCCR1;
Ser4MCCR0 &= ~MCCR0_MCE;
writel(m->mccr0 & ~MCCR0_MCE, MCCR0(m));
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;
Ser4MCCR0 = priv(mcp)->mccr0;
writel_relaxed(m->mccr1, MCCR1(m));
writel_relaxed(m->mccr0, MCCR0(m));
return 0;
}
/*
* The driver for the SA11x0 MCP port.
*/
MODULE_ALIAS("platform:sa11x0-mcp");
#endif
static const struct dev_pm_ops mcp_sa11x0_pm_ops = {
#ifdef CONFIG_PM_SLEEP
.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 = {
.probe = mcp_sa11x0_probe,
.remove = mcp_sa11x0_remove,
.suspend = mcp_sa11x0_suspend,
.resume = mcp_sa11x0_resume,
.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 = {
*/
module_platform_driver(mcp_sa11x0_driver);
MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
MODULE_LICENSE("GPL");
......@@ -11,14 +11,15 @@
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/err.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/device.h>
#include <linux/mfd/ucb1x00.h>
#include <mach/dma.h>
#define UCB1X00_ATTR(name,input)\
static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
char *buf) \
......@@ -38,14 +39,45 @@ UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2);
static int ucb1x00_assabet_add(struct ucb1x00_dev *dev)
{
device_create_file(&dev->ucb->dev, &dev_attr_vbatt);
device_create_file(&dev->ucb->dev, &dev_attr_vcharger);
device_create_file(&dev->ucb->dev, &dev_attr_batt_temp);
struct ucb1x00 *ucb = dev->ucb;
struct platform_device *pdev;
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;
}
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_vcharger);
device_remove_file(&dev->ucb->dev, &dev_attr_vbatt);
......
This diff is collapsed.
......@@ -20,8 +20,9 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/string.h>
......@@ -32,7 +33,6 @@
#include <linux/kthread.h>
#include <linux/mfd/ucb1x00.h>
#include <mach/dma.h>
#include <mach/collie.h>
#include <asm/mach-types.h>
......@@ -42,6 +42,8 @@ struct ucb1x00_ts {
struct input_dev *idev;
struct ucb1x00 *ucb;
spinlock_t irq_lock;
unsigned irq_disabled;
wait_queue_head_t irq_wait;
struct task_struct *rtask;
u16 x_res;
......@@ -238,7 +240,12 @@ static int ucb1x00_thread(void *_ts)
if (ucb1x00_ts_pen_down(ts)) {
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);
/*
......@@ -281,23 +288,37 @@ static int ucb1x00_thread(void *_ts)
* We only detect touch screen _touches_ with this interrupt
* 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;
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);
return IRQ_HANDLED;
}
static int ucb1x00_ts_open(struct input_dev *idev)
{
struct ucb1x00_ts *ts = input_get_drvdata(idev);
unsigned long flags = 0;
int ret = 0;
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);
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)
goto out;
......@@ -314,7 +335,7 @@ static int ucb1x00_ts_open(struct input_dev *idev)
if (!IS_ERR(ts->rtask)) {
ret = 0;
} else {
ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
free_irq(ts->ucb->irq_base + UCB_IRQ_TSPX, ts);
ts->rtask = NULL;
ret = -EFAULT;
}
......@@ -334,7 +355,7 @@ static void ucb1x00_ts_close(struct input_dev *idev)
kthread_stop(ts->rtask);
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_disable(ts->ucb);
}
......@@ -359,11 +380,13 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
ts->ucb = dev->ucb;
ts->idev = idev;
ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
spin_lock_init(&ts->irq_lock);
idev->name = "Touchscreen panel";
idev->id.product = ts->ucb->id;
idev->open = ucb1x00_ts_open;
idev->close = ucb1x00_ts_close;
idev->dev.parent = &ts->ucb->dev;
idev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
......
......@@ -10,8 +10,6 @@
#ifndef MCP_H
#define MCP_H
#include <mach/dma.h>
struct mcp_ops;
struct mcp {
......@@ -21,12 +19,7 @@ struct mcp {
int use_count;
unsigned int sclk_rate;
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;
int gpio_base;
};
struct mcp_ops {
......@@ -47,15 +40,14 @@ void mcp_disable(struct mcp *);
#define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate)
struct mcp *mcp_host_alloc(struct device *, size_t);
int mcp_host_register(struct mcp *);
void mcp_host_unregister(struct mcp *);
int mcp_host_add(struct mcp *, void *);
void mcp_host_del(struct mcp *);
void mcp_host_free(struct mcp *);
struct mcp_driver {
struct device_driver drv;
int (*probe)(struct mcp *);
void (*remove)(struct mcp *);
int (*suspend)(struct mcp *, pm_message_t);
int (*resume)(struct mcp *);
};
int mcp_driver_register(struct mcp_driver *);
......
......@@ -12,7 +12,7 @@
#include <linux/mfd/mcp.h>
#include <linux/gpio.h>
#include <linux/semaphore.h>
#include <linux/mutex.h>
#define UCB_IO_DATA 0x00
#define UCB_IO_DIR 0x01
......@@ -104,17 +104,27 @@
#define UCB_MODE_DYN_VFLAG_ENA (1 << 12)
#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 {
void *devid;
void (*fn)(int, void *);
struct ucb1x00_plat_data {
void (*reset)(enum ucb1x00_reset);
unsigned irq_base;
int gpio_base;
unsigned can_wakeup;
};
struct ucb1x00 {
spinlock_t lock;
raw_spinlock_t irq_lock;
struct mcp *mcp;
unsigned int irq;
struct semaphore adc_sem;
int irq_base;
struct mutex adc_mutex;
spinlock_t io_lock;
u16 id;
u16 io_dir;
......@@ -122,7 +132,8 @@ struct ucb1x00 {
u16 adc_cr;
u16 irq_fal_enbl;
u16 irq_ris_enbl;
struct ucb1x00_irq irq_handler[16];
u16 irq_mask;
u16 irq_wake;
struct device dev;
struct list_head node;
struct list_head devs;
......@@ -144,7 +155,7 @@ struct ucb1x00_driver {
struct list_head devs;
int (*add)(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);
};
......@@ -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_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
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