summaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig2
-rw-r--r--drivers/mfd/mcp-core.c61
-rw-r--r--drivers/mfd/mcp-sa11x0.c169
-rw-r--r--drivers/mfd/twl-core.c6
-rw-r--r--drivers/mfd/twl4030-power.c20
-rw-r--r--drivers/mfd/twl6040-core.c128
-rw-r--r--drivers/mfd/ucb1x00-core.c67
-rw-r--r--drivers/mfd/ucb1x00-ts.c34
8 files changed, 189 insertions, 298 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index cd13e9f2f5e..f147395bac9 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -200,7 +200,7 @@ config MENELAUS
config TWL4030_CORE
bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support"
- depends on I2C=y && GENERIC_HARDIRQS && IRQ_DOMAIN
+ depends on I2C=y && GENERIC_HARDIRQS
help
Say yes here if you have TWL4030 / TWL6030 family chip on your board.
This core driver provides register access and IRQ handling
diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index 63be60bc345..86cc3f7841c 100644
--- a/drivers/mfd/mcp-core.c
+++ b/drivers/mfd/mcp-core.c
@@ -26,35 +26,9 @@
#define to_mcp(d) container_of(d, struct mcp, attached_device)
#define to_mcp_driver(d) container_of(d, struct mcp_driver, drv)
-static const struct mcp_device_id *mcp_match_id(const struct mcp_device_id *id,
- const char *codec)
-{
- while (id->name[0]) {
- if (strcmp(codec, id->name) == 0)
- return id;
- id++;
- }
- return NULL;
-}
-
-const struct mcp_device_id *mcp_get_device_id(const struct mcp *mcp)
-{
- const struct mcp_driver *driver =
- to_mcp_driver(mcp->attached_device.driver);
-
- return mcp_match_id(driver->id_table, mcp->codec);
-}
-EXPORT_SYMBOL(mcp_get_device_id);
-
static int mcp_bus_match(struct device *dev, struct device_driver *drv)
{
- const struct mcp *mcp = to_mcp(dev);
- const struct mcp_driver *driver = to_mcp_driver(drv);
-
- if (driver->id_table)
- return !!mcp_match_id(driver->id_table, mcp->codec);
-
- return 0;
+ return 1;
}
static int mcp_bus_probe(struct device *dev)
@@ -100,18 +74,9 @@ static int mcp_bus_resume(struct device *dev)
return ret;
}
-static int mcp_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- struct mcp *mcp = to_mcp(dev);
-
- add_uevent_var(env, "MODALIAS=%s%s", MCP_MODULE_PREFIX, mcp->codec);
- return 0;
-}
-
static struct bus_type mcp_bus_type = {
.name = "mcp",
.match = mcp_bus_match,
- .uevent = mcp_bus_uevent,
.probe = mcp_bus_probe,
.remove = mcp_bus_remove,
.suspend = mcp_bus_suspend,
@@ -128,9 +93,11 @@ static struct bus_type mcp_bus_type = {
*/
void mcp_set_telecom_divisor(struct mcp *mcp, unsigned int div)
{
- spin_lock_irq(&mcp->lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&mcp->lock, flags);
mcp->ops->set_telecom_divisor(mcp, div);
- spin_unlock_irq(&mcp->lock);
+ spin_unlock_irqrestore(&mcp->lock, flags);
}
EXPORT_SYMBOL(mcp_set_telecom_divisor);
@@ -143,9 +110,11 @@ EXPORT_SYMBOL(mcp_set_telecom_divisor);
*/
void mcp_set_audio_divisor(struct mcp *mcp, unsigned int div)
{
- spin_lock_irq(&mcp->lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&mcp->lock, flags);
mcp->ops->set_audio_divisor(mcp, div);
- spin_unlock_irq(&mcp->lock);
+ spin_unlock_irqrestore(&mcp->lock, flags);
}
EXPORT_SYMBOL(mcp_set_audio_divisor);
@@ -198,10 +167,11 @@ EXPORT_SYMBOL(mcp_reg_read);
*/
void mcp_enable(struct mcp *mcp)
{
- spin_lock_irq(&mcp->lock);
+ unsigned long flags;
+ spin_lock_irqsave(&mcp->lock, flags);
if (mcp->use_count++ == 0)
mcp->ops->enable(mcp);
- spin_unlock_irq(&mcp->lock);
+ spin_unlock_irqrestore(&mcp->lock, flags);
}
EXPORT_SYMBOL(mcp_enable);
@@ -247,14 +217,9 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
}
EXPORT_SYMBOL(mcp_host_alloc);
-int mcp_host_register(struct mcp *mcp, void *pdata)
+int mcp_host_register(struct mcp *mcp)
{
- if (!mcp->codec)
- return -EINVAL;
-
- mcp->attached_device.platform_data = pdata;
dev_set_name(&mcp->attached_device, "mcp0");
- request_module("%s%s", MCP_MODULE_PREFIX, mcp->codec);
return device_register(&mcp->attached_device);
}
EXPORT_SYMBOL(mcp_host_register);
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 9adc2eb6949..02c53a0766c 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -19,7 +19,6 @@
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/mfd/mcp.h>
-#include <linux/io.h>
#include <mach/dma.h>
#include <mach/hardware.h>
@@ -27,19 +26,12 @@
#include <asm/system.h>
#include <mach/mcp.h>
-/* Register offsets */
-#define MCCR0 0x00
-#define MCDR0 0x08
-#define MCDR1 0x0C
-#define MCDR2 0x10
-#define MCSR 0x18
-#define MCCR1 0x00
+#include <mach/assabet.h>
+
struct mcp_sa11x0 {
- u32 mccr0;
- u32 mccr1;
- unsigned char *mccr0_base;
- unsigned char *mccr1_base;
+ u32 mccr0;
+ u32 mccr1;
};
#define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp))
@@ -47,25 +39,25 @@ struct mcp_sa11x0 {
static void
mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
{
- struct mcp_sa11x0 *priv = priv(mcp);
+ unsigned int mccr0;
divisor /= 32;
- priv->mccr0 &= ~0x00007f00;
- priv->mccr0 |= divisor << 8;
- __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
+ mccr0 = Ser4MCCR0 & ~0x00007f00;
+ mccr0 |= divisor << 8;
+ Ser4MCCR0 = mccr0;
}
static void
mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
{
- struct mcp_sa11x0 *priv = priv(mcp);
+ unsigned int mccr0;
divisor /= 32;
- priv->mccr0 &= ~0x0000007f;
- priv->mccr0 |= divisor;
- __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
+ mccr0 = Ser4MCCR0 & ~0x0000007f;
+ mccr0 |= divisor;
+ Ser4MCCR0 = mccr0;
}
/*
@@ -79,16 +71,12 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
{
int ret = -ETIME;
int i;
- u32 mcpreg;
- struct mcp_sa11x0 *priv = priv(mcp);
- mcpreg = reg << 17 | MCDR2_Wr | (val & 0xffff);
- __raw_writel(mcpreg, priv->mccr0_base + MCDR2);
+ Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
for (i = 0; i < 2; i++) {
udelay(mcp->rw_timeout);
- mcpreg = __raw_readl(priv->mccr0_base + MCSR);
- if (mcpreg & MCSR_CWC) {
+ if (Ser4MCSR & MCSR_CWC) {
ret = 0;
break;
}
@@ -109,18 +97,13 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
{
int ret = -ETIME;
int i;
- u32 mcpreg;
- struct mcp_sa11x0 *priv = priv(mcp);
- mcpreg = reg << 17 | MCDR2_Rd;
- __raw_writel(mcpreg, priv->mccr0_base + MCDR2);
+ Ser4MCDR2 = reg << 17 | MCDR2_Rd;
for (i = 0; i < 2; i++) {
udelay(mcp->rw_timeout);
- mcpreg = __raw_readl(priv->mccr0_base + MCSR);
- if (mcpreg & MCSR_CRC) {
- ret = __raw_readl(priv->mccr0_base + MCDR2)
- & 0xffff;
+ if (Ser4MCSR & MCSR_CRC) {
+ ret = Ser4MCDR2 & 0xffff;
break;
}
}
@@ -133,19 +116,13 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
static void mcp_sa11x0_enable(struct mcp *mcp)
{
- struct mcp_sa11x0 *priv = priv(mcp);
-
- __raw_writel(-1, priv->mccr0_base + MCSR);
- priv->mccr0 |= MCCR0_MCE;
- __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
+ Ser4MCSR = -1;
+ Ser4MCCR0 |= MCCR0_MCE;
}
static void mcp_sa11x0_disable(struct mcp *mcp)
{
- struct mcp_sa11x0 *priv = priv(mcp);
-
- priv->mccr0 &= ~MCCR0_MCE;
- __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
+ Ser4MCCR0 &= ~MCCR0_MCE;
}
/*
@@ -165,69 +142,50 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
struct mcp_plat_data *data = pdev->dev.platform_data;
struct mcp *mcp;
int ret;
- struct mcp_sa11x0 *priv;
- struct resource *res_mem0, *res_mem1;
- u32 size0, size1;
if (!data)
return -ENODEV;
- if (!data->codec)
- return -ENODEV;
-
- res_mem0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res_mem0)
- return -ENODEV;
- size0 = res_mem0->end - res_mem0->start + 1;
-
- res_mem1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!res_mem1)
- return -ENODEV;
- size1 = res_mem1->end - res_mem1->start + 1;
-
- if (!request_mem_region(res_mem0->start, size0, "sa11x0-mcp"))
+ if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
return -EBUSY;
- if (!request_mem_region(res_mem1->start, size1, "sa11x0-mcp")) {
- ret = -EBUSY;
- goto release;
- }
-
mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
if (!mcp) {
ret = -ENOMEM;
- goto release2;
+ goto release;
}
- priv = priv(mcp);
-
mcp->owner = THIS_MODULE;
mcp->ops = &mcp_sa11x0;
mcp->sclk_rate = data->sclk_rate;
- mcp->dma_audio_rd = DDAR_DevAdd(res_mem0->start + MCDR0)
- + DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
- mcp->dma_audio_wr = DDAR_DevAdd(res_mem0->start + MCDR0)
- + DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
- mcp->dma_telco_rd = DDAR_DevAdd(res_mem0->start + MCDR1)
- + DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
- mcp->dma_telco_wr = DDAR_DevAdd(res_mem0->start + MCDR1)
- + DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
- mcp->codec = data->codec;
+ 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);
+ if (machine_is_assabet()) {
+ ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
+ }
+
+ /*
+ * 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
* set the sampling rate to minimum.
*/
- priv->mccr0_base = ioremap(res_mem0->start, size0);
- priv->mccr1_base = ioremap(res_mem1->start, size1);
-
- __raw_writel(-1, priv->mccr0_base + MCSR);
- priv->mccr1 = data->mccr1;
- priv->mccr0 = data->mccr0 | 0x7f7f;
- __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
- __raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
+ Ser4MCSR = -1;
+ Ser4MCCR1 = data->mccr1;
+ Ser4MCCR0 = data->mccr0 | 0x7f7f;
/*
* Calculate the read/write timeout (us) from the bit clock
@@ -237,53 +195,36 @@ 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, data->codec_pdata);
+ ret = mcp_host_register(mcp);
if (ret == 0)
goto out;
- release2:
- release_mem_region(res_mem1->start, size1);
release:
- release_mem_region(res_mem0->start, size0);
+ release_mem_region(0x80060000, 0x60);
platform_set_drvdata(pdev, NULL);
out:
return ret;
}
-static int mcp_sa11x0_remove(struct platform_device *pdev)
+static int mcp_sa11x0_remove(struct platform_device *dev)
{
- struct mcp *mcp = platform_get_drvdata(pdev);
- struct mcp_sa11x0 *priv = priv(mcp);
- struct resource *res_mem;
- u32 size;
+ struct mcp *mcp = platform_get_drvdata(dev);
- platform_set_drvdata(pdev, NULL);
+ platform_set_drvdata(dev, NULL);
mcp_host_unregister(mcp);
+ release_mem_region(0x80060000, 0x60);
- res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res_mem) {
- size = res_mem->end - res_mem->start + 1;
- release_mem_region(res_mem->start, size);
- }
- res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (res_mem) {
- size = res_mem->end - res_mem->start + 1;
- release_mem_region(res_mem->start, size);
- }
- iounmap(priv->mccr0_base);
- iounmap(priv->mccr1_base);
return 0;
}
static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
{
struct mcp *mcp = platform_get_drvdata(dev);
- struct mcp_sa11x0 *priv = priv(mcp);
- u32 mccr0;
- mccr0 = priv->mccr0 & ~MCCR0_MCE;
- __raw_writel(mccr0, priv->mccr0_base + MCCR0);
+ priv(mcp)->mccr0 = Ser4MCCR0;
+ priv(mcp)->mccr1 = Ser4MCCR1;
+ Ser4MCCR0 &= ~MCCR0_MCE;
return 0;
}
@@ -291,10 +232,9 @@ static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
static int mcp_sa11x0_resume(struct platform_device *dev)
{
struct mcp *mcp = platform_get_drvdata(dev);
- struct mcp_sa11x0 *priv = priv(mcp);
- __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
- __raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
+ Ser4MCCR1 = priv(mcp)->mccr1;
+ Ser4MCCR0 = priv(mcp)->mccr0;
return 0;
}
@@ -311,7 +251,6 @@ static struct platform_driver mcp_sa11x0_driver = {
.resume = mcp_sa11x0_resume,
.driver = {
.name = "sa11x0-mcp",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index e04e04ddc15..8ce3959c691 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -263,7 +263,9 @@ struct twl_client {
static struct twl_client twl_modules[TWL_NUM_SLAVES];
+#ifdef CONFIG_IRQ_DOMAIN
static struct irq_domain domain;
+#endif
/* mapping the module id to slave id and base address */
struct twl_mapping {
@@ -1226,13 +1228,13 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
pdata->irq_base = status;
pdata->irq_end = pdata->irq_base + nr_irqs;
+#ifdef CONFIG_IRQ_DOMAIN
domain.irq_base = pdata->irq_base;
domain.nr_irq = nr_irqs;
-#ifdef CONFIG_OF_IRQ
domain.of_node = of_node_get(node);
domain.ops = &irq_domain_simple_ops;
-#endif
irq_domain_add(&domain);
+#endif
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
dev_dbg(&client->dev, "can't talk I2C?\n");
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index d905f517115..79ca33dfacc 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -124,7 +124,7 @@ static u8 res_config_addrs[] = {
[RES_MAIN_REF] = 0x94,
};
-static int __init twl4030_write_script_byte(u8 address, u8 byte)
+static int __devinit twl4030_write_script_byte(u8 address, u8 byte)
{
int err;
@@ -138,7 +138,7 @@ out:
return err;
}
-static int __init twl4030_write_script_ins(u8 address, u16 pmb_message,
+static int __devinit twl4030_write_script_ins(u8 address, u16 pmb_message,
u8 delay, u8 next)
{
int err;
@@ -158,7 +158,7 @@ out:
return err;
}
-static int __init twl4030_write_script(u8 address, struct twl4030_ins *script,
+static int __devinit twl4030_write_script(u8 address, struct twl4030_ins *script,
int len)
{
int err;
@@ -183,7 +183,7 @@ static int __init twl4030_write_script(u8 address, struct twl4030_ins *script,
return err;
}
-static int __init twl4030_config_wakeup3_sequence(u8 address)
+static int __devinit twl4030_config_wakeup3_sequence(u8 address)
{
int err;
u8 data;
@@ -208,7 +208,7 @@ out:
return err;
}
-static int __init twl4030_config_wakeup12_sequence(u8 address)
+static int __devinit twl4030_config_wakeup12_sequence(u8 address)
{
int err = 0;
u8 data;
@@ -262,7 +262,7 @@ out:
return err;
}
-static int __init twl4030_config_sleep_sequence(u8 address)
+static int __devinit twl4030_config_sleep_sequence(u8 address)
{
int err;
@@ -276,7 +276,7 @@ static int __init twl4030_config_sleep_sequence(u8 address)
return err;
}
-static int __init twl4030_config_warmreset_sequence(u8 address)
+static int __devinit twl4030_config_warmreset_sequence(u8 address)
{
int err;
u8 rd_data;
@@ -324,7 +324,7 @@ out:
return err;
}
-static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
+static int __devinit twl4030_configure_resource(struct twl4030_resconfig *rconfig)
{
int rconfig_addr;
int err;
@@ -416,7 +416,7 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig)
return 0;
}
-static int __init load_twl4030_script(struct twl4030_script *tscript,
+static int __devinit load_twl4030_script(struct twl4030_script *tscript,
u8 address)
{
int err;
@@ -527,7 +527,7 @@ void twl4030_power_off(void)
pr_err("TWL4030 Unable to power off\n");
}
-void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
+void __devinit twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
{
int err = 0;
int i;
diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c
index dda86293dc9..b2d8e512d3c 100644
--- a/drivers/mfd/twl6040-core.c
+++ b/drivers/mfd/twl6040-core.c
@@ -282,6 +282,7 @@ int twl6040_power(struct twl6040 *twl6040, int on)
/* Default PLL configuration after power up */
twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL;
twl6040->sysclk = 19200000;
+ twl6040->mclk = 32768;
} else {
/* already powered-down */
if (!twl6040->power_count) {
@@ -305,6 +306,7 @@ int twl6040_power(struct twl6040 *twl6040, int on)
twl6040_power_down(twl6040);
}
twl6040->sysclk = 0;
+ twl6040->mclk = 0;
}
out:
@@ -324,23 +326,38 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
hppllctl = twl6040_reg_read(twl6040, TWL6040_REG_HPPLLCTL);
lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL);
+ /* Force full reconfiguration when switching between PLL */
+ if (pll_id != twl6040->pll) {
+ twl6040->sysclk = 0;
+ twl6040->mclk = 0;
+ }
+
switch (pll_id) {
case TWL6040_SYSCLK_SEL_LPPLL:
/* low-power PLL divider */
- switch (freq_out) {
- case 17640000:
- lppllctl |= TWL6040_LPLLFIN;
- break;
- case 19200000:
- lppllctl &= ~TWL6040_LPLLFIN;
- break;
- default:
- dev_err(twl6040->dev,
- "freq_out %d not supported\n", freq_out);
- ret = -EINVAL;
- goto pll_out;
+ /* Change the sysclk configuration only if it has been canged */
+ if (twl6040->sysclk != freq_out) {
+ switch (freq_out) {
+ case 17640000:
+ lppllctl |= TWL6040_LPLLFIN;
+ break;
+ case 19200000:
+ lppllctl &= ~TWL6040_LPLLFIN;
+ break;
+ default:
+ dev_err(twl6040->dev,
+ "freq_out %d not supported\n",
+ freq_out);
+ ret = -EINVAL;
+ goto pll_out;
+ }
+ twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
+ lppllctl);
}
- twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+
+ /* The PLL in use has not been change, we can exit */
+ if (twl6040->pll == pll_id)
+ break;
switch (freq_in) {
case 32768:
@@ -371,48 +388,56 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
goto pll_out;
}
- hppllctl &= ~TWL6040_MCLK_MSK;
+ if (twl6040->mclk != freq_in) {
+ hppllctl &= ~TWL6040_MCLK_MSK;
+
+ switch (freq_in) {
+ case 12000000:
+ /* PLL enabled, active mode */
+ hppllctl |= TWL6040_MCLK_12000KHZ |
+ TWL6040_HPLLENA;
+ break;
+ case 19200000:
+ /*
+ * PLL disabled
+ * (enable PLL if MCLK jitter quality
+ * doesn't meet specification)
+ */
+ hppllctl |= TWL6040_MCLK_19200KHZ;
+ break;
+ case 26000000:
+ /* PLL enabled, active mode */
+ hppllctl |= TWL6040_MCLK_26000KHZ |
+ TWL6040_HPLLENA;
+ break;
+ case 38400000:
+ /* PLL enabled, active mode */
+ hppllctl |= TWL6040_MCLK_38400KHZ |
+ TWL6040_HPLLENA;
+ break;
+ default:
+ dev_err(twl6040->dev,
+ "freq_in %d not supported\n", freq_in);
+ ret = -EINVAL;
+ goto pll_out;
+ }
- switch (freq_in) {
- case 12000000:
- /* PLL enabled, active mode */
- hppllctl |= TWL6040_MCLK_12000KHZ |
- TWL6040_HPLLENA;
- break;
- case 19200000:
/*
- * PLL disabled
- * (enable PLL if MCLK jitter quality
- * doesn't meet specification)
+ * enable clock slicer to ensure input waveform is
+ * square
*/
- hppllctl |= TWL6040_MCLK_19200KHZ;
- break;
- case 26000000:
- /* PLL enabled, active mode */
- hppllctl |= TWL6040_MCLK_26000KHZ |
- TWL6040_HPLLENA;
- break;
- case 38400000:
- /* PLL enabled, active mode */
- hppllctl |= TWL6040_MCLK_38400KHZ |
- TWL6040_HPLLENA;
- break;
- default:
- dev_err(twl6040->dev,
- "freq_in %d not supported\n", freq_in);
- ret = -EINVAL;
- goto pll_out;
- }
+ hppllctl |= TWL6040_HPLLSQRENA;
- /* enable clock slicer to ensure input waveform is square */
- hppllctl |= TWL6040_HPLLSQRENA;
-
- twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL, hppllctl);
- usleep_range(500, 700);
- lppllctl |= TWL6040_HPLLSEL;
- twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
- lppllctl &= ~TWL6040_LPLLENA;
- twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
+ twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL,
+ hppllctl);
+ usleep_range(500, 700);
+ lppllctl |= TWL6040_HPLLSEL;
+ twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
+ lppllctl);
+ lppllctl &= ~TWL6040_LPLLENA;
+ twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
+ lppllctl);
+ }
break;
default:
dev_err(twl6040->dev, "unknown pll id %d\n", pll_id);
@@ -421,6 +446,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
}
twl6040->sysclk = freq_out;
+ twl6040->mclk = freq_in;
twl6040->pll = pll_id;
pll_out:
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 91c4f25e0e5..febc90cdef7 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -36,15 +36,6 @@ static DEFINE_MUTEX(ucb1x00_mutex);
static LIST_HEAD(ucb1x00_drivers);
static LIST_HEAD(ucb1x00_devices);
-static struct mcp_device_id ucb1x00_id[] = {
- { "ucb1x00", 0 }, /* auto-detection */
- { "ucb1200", UCB_ID_1200 },
- { "ucb1300", UCB_ID_1300 },
- { "tc35143", UCB_ID_TC35143 },
- { }
-};
-MODULE_DEVICE_TABLE(mcp, ucb1x00_id);
-
/**
* ucb1x00_io_set_dir - set IO direction
* @ucb: UCB1x00 structure describing chip
@@ -157,16 +148,22 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
{
struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
unsigned long flags;
+ unsigned old, mask = 1 << offset;
spin_lock_irqsave(&ucb->io_lock, flags);
- ucb->io_dir |= (1 << offset);
- ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
-
+ old = ucb->io_out;
if (value)
- ucb->io_out |= 1 << offset;
+ ucb->io_out |= mask;
else
- ucb->io_out &= ~(1 << offset);
- ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
+ ucb->io_out &= ~mask;
+
+ if (old != ucb->io_out)
+ ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
+
+ if (!(ucb->io_dir & mask)) {
+ ucb->io_dir |= mask;
+ ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
+ }
spin_unlock_irqrestore(&ucb->io_lock, flags);
return 0;
@@ -536,33 +533,17 @@ static struct class ucb1x00_class = {
static int ucb1x00_probe(struct mcp *mcp)
{
- const struct mcp_device_id *mid;
struct ucb1x00 *ucb;
struct ucb1x00_driver *drv;
- struct ucb1x00_plat_data *pdata;
unsigned int id;
int ret = -ENODEV;
int temp;
mcp_enable(mcp);
id = mcp_reg_read(mcp, UCB_ID);
- mid = mcp_get_device_id(mcp);
- if (mid && mid->driver_data) {
- if (id != mid->driver_data) {
- printk(KERN_WARNING "%s wrong ID %04x found: %04x\n",
- mid->name, (unsigned int) mid->driver_data, id);
- goto err_disable;
- }
- } else {
- mid = &ucb1x00_id[1];
- while (mid->driver_data) {
- if (id == mid->driver_data)
- break;
- mid++;
- }
- printk(KERN_WARNING "%s ID not found: %04x\n",
- ucb1x00_id[0].name, id);
+ if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) {
+ printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
goto err_disable;
}
@@ -571,28 +552,28 @@ static int ucb1x00_probe(struct mcp *mcp)
if (!ucb)
goto err_disable;
- pdata = mcp->attached_device.platform_data;
+
ucb->dev.class = &ucb1x00_class;
ucb->dev.parent = &mcp->attached_device;
- dev_set_name(&ucb->dev, mid->name);
+ dev_set_name(&ucb->dev, "ucb1x00");
spin_lock_init(&ucb->lock);
spin_lock_init(&ucb->io_lock);
sema_init(&ucb->adc_sem, 1);
- ucb->id = mid;
+ ucb->id = id;
ucb->mcp = mcp;
ucb->irq = ucb1x00_detect_irq(ucb);
if (ucb->irq == NO_IRQ) {
- printk(KERN_ERR "%s: IRQ probe failed\n", mid->name);
+ printk(KERN_ERR "UCB1x00: IRQ probe failed\n");
ret = -ENODEV;
goto err_free;
}
ucb->gpio.base = -1;
- if (pdata && (pdata->gpio_base >= 0)) {
+ if (mcp->gpio_base != 0) {
ucb->gpio.label = dev_name(&ucb->dev);
- ucb->gpio.base = pdata->gpio_base;
+ ucb->gpio.base = mcp->gpio_base;
ucb->gpio.ngpio = 10;
ucb->gpio.set = ucb1x00_gpio_set;
ucb->gpio.get = ucb1x00_gpio_get;
@@ -605,10 +586,10 @@ static int ucb1x00_probe(struct mcp *mcp)
dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
- mid->name, ucb);
+ "UCB1x00", ucb);
if (ret) {
- printk(KERN_ERR "%s: unable to grab irq%d: %d\n",
- mid->name, ucb->irq, ret);
+ printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
+ ucb->irq, ret);
goto err_gpio;
}
@@ -712,6 +693,7 @@ static int ucb1x00_resume(struct mcp *mcp)
struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
struct ucb1x00_dev *dev;
+ ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
mutex_lock(&ucb1x00_mutex);
list_for_each_entry(dev, &ucb->devs, dev_node) {
@@ -730,7 +712,6 @@ static struct mcp_driver ucb1x00_driver = {
.remove = ucb1x00_remove,
.suspend = ucb1x00_suspend,
.resume = ucb1x00_resume,
- .id_table = ucb1x00_id,
};
static int __init ucb1x00_init(void)
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index 40ec3c11886..63a3cbdfa3f 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -47,7 +47,6 @@ struct ucb1x00_ts {
u16 x_res;
u16 y_res;
- unsigned int restart:1;
unsigned int adcsync:1;
};
@@ -207,15 +206,17 @@ static int ucb1x00_thread(void *_ts)
{
struct ucb1x00_ts *ts = _ts;
DECLARE_WAITQUEUE(wait, current);
+ bool frozen, ignore = false;
int valid = 0;
set_freezable();
add_wait_queue(&ts->irq_wait, &wait);
- while (!kthread_should_stop()) {
+ while (!kthread_freezable_should_stop(&frozen)) {
unsigned int x, y, p;
signed long timeout;
- ts->restart = 0;
+ if (frozen)
+ ignore = true;
ucb1x00_adc_enable(ts->ucb);
@@ -258,7 +259,7 @@ static int ucb1x00_thread(void *_ts)
* space. We therefore leave it to user space
* to do any filtering they please.
*/
- if (!ts->restart) {
+ if (!ignore) {
ucb1x00_ts_evt_add(ts, p, x, y);
valid = 1;
}
@@ -267,8 +268,6 @@ static int ucb1x00_thread(void *_ts)
timeout = HZ / 100;
}
- try_to_freeze();
-
schedule_timeout(timeout);
}
@@ -340,26 +339,6 @@ static void ucb1x00_ts_close(struct input_dev *idev)
ucb1x00_disable(ts->ucb);
}
-#ifdef CONFIG_PM
-static int ucb1x00_ts_resume(struct ucb1x00_dev *dev)
-{
- struct ucb1x00_ts *ts = dev->priv;
-
- if (ts->rtask != NULL) {
- /*
- * Restart the TS thread to ensure the
- * TS interrupt mode is set up again
- * after sleep.
- */
- ts->restart = 1;
- wake_up(&ts->irq_wait);
- }
- return 0;
-}
-#else
-#define ucb1x00_ts_resume NULL
-#endif
-
/*
* Initialisation.
@@ -382,7 +361,7 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
idev->name = "Touchscreen panel";
- idev->id.product = ts->ucb->id->driver_data;
+ idev->id.product = ts->ucb->id;
idev->open = ucb1x00_ts_open;
idev->close = ucb1x00_ts_close;
@@ -425,7 +404,6 @@ static void ucb1x00_ts_remove(struct ucb1x00_dev *dev)
static struct ucb1x00_driver ucb1x00_ts_driver = {
.add = ucb1x00_ts_add,
.remove = ucb1x00_ts_remove,
- .resume = ucb1x00_ts_resume,
};
static int __init ucb1x00_ts_init(void)