Commit f686e9af authored by Marc Dietrich's avatar Marc Dietrich Committed by Greg Kroah-Hartman

staging: nvec: convert to use platform register and mfdcells

This patch converts the nvec to use mfd cells and improves the
registration of the platform driver. The child drivers are also
converted to use mfd cells and platform registration.
Signed-off-by: default avatarMarc Dietrich <marvin24@gmx.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 208b813c
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include "nvec.h" #include "nvec.h"
static unsigned char EC_DISABLE_EVENT_REPORTING[] = {'\x04','\x00','\x00'}; static unsigned char EC_DISABLE_EVENT_REPORTING[] = {'\x04','\x00','\x00'};
...@@ -30,6 +31,25 @@ static unsigned char EC_GET_FIRMWARE_VERSION[] = {'\x07','\x15'}; ...@@ -30,6 +31,25 @@ static unsigned char EC_GET_FIRMWARE_VERSION[] = {'\x07','\x15'};
static struct nvec_chip *nvec_power_handle; static struct nvec_chip *nvec_power_handle;
static struct mfd_cell nvec_devices[] = {
{
.name = "nvec-kbd",
.id = 1,
},
{
.name = "nvec-mouse",
.id = 1,
},
{
.name = "nvec-power",
.id = 1,
},
{
.name = "nvec-power",
.id = 2,
},
};
int nvec_register_notifier(struct nvec_chip *nvec, struct notifier_block *nb, int nvec_register_notifier(struct nvec_chip *nvec, struct notifier_block *nb,
unsigned int events) unsigned int events)
{ {
...@@ -139,7 +159,7 @@ static void nvec_dispatch(struct work_struct *work) ...@@ -139,7 +159,7 @@ static void nvec_dispatch(struct work_struct *work)
} else { } else {
parse_msg(nvec, msg); parse_msg(nvec, msg);
if((!msg) || (!msg->data)) if((!msg) || (!msg->data))
dev_warn(nvec->dev, "attempt access zero pointer"); dev_warn(nvec->dev, "attempt access zero pointer\n");
else { else {
kfree(msg->data); kfree(msg->data);
kfree(msg); kfree(msg);
...@@ -148,16 +168,16 @@ static void nvec_dispatch(struct work_struct *work) ...@@ -148,16 +168,16 @@ static void nvec_dispatch(struct work_struct *work)
} }
} }
static irqreturn_t i2c_interrupt(int irq, void *dev) static irqreturn_t nvec_interrupt(int irq, void *dev)
{ {
unsigned long status; unsigned long status;
unsigned long received; unsigned long received;
unsigned char to_send; unsigned char to_send;
struct nvec_msg *msg; struct nvec_msg *msg;
struct nvec_chip *nvec = (struct nvec_chip *)dev; struct nvec_chip *nvec = (struct nvec_chip *)dev;
unsigned char *i2c_regs = nvec->i2c_regs; void __iomem *base = nvec->base;
status = readl(i2c_regs + I2C_SL_STATUS); status = readl(base + I2C_SL_STATUS);
if(!(status & I2C_SL_IRQ)) if(!(status & I2C_SL_IRQ))
{ {
...@@ -222,7 +242,7 @@ static irqreturn_t i2c_interrupt(int irq, void *dev) ...@@ -222,7 +242,7 @@ static irqreturn_t i2c_interrupt(int irq, void *dev)
nvec->state = NVEC_WAIT; nvec->state = NVEC_WAIT;
} }
} }
writel(to_send, i2c_regs + I2C_SL_RCVD); writel(to_send, base + I2C_SL_RCVD);
gpio_set_value(nvec->gpio, 1); gpio_set_value(nvec->gpio, 1);
...@@ -230,10 +250,10 @@ static irqreturn_t i2c_interrupt(int irq, void *dev) ...@@ -230,10 +250,10 @@ static irqreturn_t i2c_interrupt(int irq, void *dev)
goto handled; goto handled;
} else { } else {
received = readl(i2c_regs + I2C_SL_RCVD); received = readl(base + I2C_SL_RCVD);
//Workaround? //Workaround?
if(status & RCVD) { if(status & RCVD) {
writel(0, i2c_regs + I2C_SL_RCVD); writel(0, base + I2C_SL_RCVD);
goto handled; goto handled;
} }
...@@ -258,37 +278,26 @@ static irqreturn_t i2c_interrupt(int irq, void *dev) ...@@ -258,37 +278,26 @@ static irqreturn_t i2c_interrupt(int irq, void *dev)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int __devinit nvec_add_subdev(struct nvec_chip *nvec, struct nvec_subdev *subdev) static void tegra_init_i2c_slave(struct nvec_chip *nvec)
{
struct platform_device *pdev;
pdev = platform_device_alloc(subdev->name, subdev->id);
pdev->dev.parent = nvec->dev;
pdev->dev.platform_data = subdev->platform_data;
return platform_device_add(pdev);
}
static void tegra_init_i2c_slave(struct nvec_platform_data *pdata, unsigned char *i2c_regs,
struct clk *i2c_clk)
{ {
u32 val; u32 val;
clk_enable(i2c_clk); clk_enable(nvec->i2c_clk);
tegra_periph_reset_assert(i2c_clk);
tegra_periph_reset_assert(nvec->i2c_clk);
udelay(2); udelay(2);
tegra_periph_reset_deassert(i2c_clk); tegra_periph_reset_deassert(nvec->i2c_clk);
writel(pdata->i2c_addr>>1, i2c_regs + I2C_SL_ADDR1); writel(nvec->i2c_addr>>1, nvec->base + I2C_SL_ADDR1);
writel(0, i2c_regs + I2C_SL_ADDR2); writel(0, nvec->base + I2C_SL_ADDR2);
writel(0x1E, i2c_regs + I2C_SL_DELAY_COUNT); writel(0x1E, nvec->base + I2C_SL_DELAY_COUNT);
val = I2C_CNFG_NEW_MASTER_SFM | I2C_CNFG_PACKET_MODE_EN | val = I2C_CNFG_NEW_MASTER_SFM | I2C_CNFG_PACKET_MODE_EN |
(0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
writel(val, i2c_regs + I2C_CNFG); writel(val, nvec->base + I2C_CNFG);
writel(I2C_SL_NEWL, i2c_regs + I2C_SL_CNFG); writel(I2C_SL_NEWL, nvec->base + I2C_SL_CNFG);
clk_disable(i2c_clk); clk_disable(nvec->i2c_clk);
} }
static void nvec_power_off(void) static void nvec_power_off(void)
...@@ -299,12 +308,14 @@ static void nvec_power_off(void) ...@@ -299,12 +308,14 @@ static void nvec_power_off(void)
static int __devinit tegra_nvec_probe(struct platform_device *pdev) static int __devinit tegra_nvec_probe(struct platform_device *pdev)
{ {
int err, i, ret; int err, ret;
struct clk *i2c_clk; struct clk *i2c_clk;
struct nvec_platform_data *pdata = pdev->dev.platform_data; struct nvec_platform_data *pdata = pdev->dev.platform_data;
struct nvec_chip *nvec; struct nvec_chip *nvec;
struct nvec_msg *msg; struct nvec_msg *msg;
unsigned char *i2c_regs; struct resource *res;
struct resource *iomem;
void __iomem *base;
nvec = kzalloc(sizeof(struct nvec_chip), GFP_KERNEL); nvec = kzalloc(sizeof(struct nvec_chip), GFP_KERNEL);
if(nvec == NULL) { if(nvec == NULL) {
...@@ -314,49 +325,51 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev) ...@@ -314,49 +325,51 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, nvec); platform_set_drvdata(pdev, nvec);
nvec->dev = &pdev->dev; nvec->dev = &pdev->dev;
nvec->gpio = pdata->gpio; nvec->gpio = pdata->gpio;
nvec->irq = pdata->irq; nvec->i2c_addr = pdata->i2c_addr;
/* res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c_clk=clk_get_sys(NULL, "i2c"); if (!res) {
if(IS_ERR_OR_NULL(i2c_clk)) dev_err(&pdev->dev, "no mem resource?\n");
printk(KERN_ERR"No such clock tegra-i2c.2\n"); return -ENODEV;
else
clk_enable(i2c_clk);
*/
i2c_regs = ioremap(pdata->base, pdata->size);
if(!i2c_regs) {
dev_err(nvec->dev, "failed to ioremap registers\n");
goto failed;
} }
nvec->i2c_regs = i2c_regs; iomem = request_mem_region(res->start, resource_size(res), pdev->name);
if (!iomem) {
dev_err(&pdev->dev, "I2C region already claimed\n");
return -EBUSY;
}
i2c_clk = clk_get_sys(pdata->clock, NULL); base = ioremap(iomem->start, resource_size(iomem));
if(IS_ERR_OR_NULL(i2c_clk)) { if (!base) {
dev_err(nvec->dev, "failed to get clock tegra-i2c.2\n"); dev_err(&pdev->dev, "Can't ioremap I2C region\n");
goto failed; return -ENOMEM;
} }
tegra_init_i2c_slave(pdata, i2c_regs, i2c_clk); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(&pdev->dev, "no irq resource?\n");
ret = -ENODEV;
goto err_iounmap;
}
err = request_irq(nvec->irq, i2c_interrupt, IRQF_DISABLED, "nvec", nvec); i2c_clk = clk_get_sys("tegra-i2c.2", NULL);
if(err) { if (IS_ERR(i2c_clk)) {
dev_err(nvec->dev, "couldn't request irq"); dev_err(nvec->dev, "failed to get controller clock\n");
goto failed; goto err_iounmap;
} }
clk_enable(i2c_clk); clk_enable(i2c_clk);
clk_set_rate(i2c_clk, 8*80000); clk_set_rate(i2c_clk, 8*80000);
nvec->base = base;
nvec->irq = res->start;
nvec->i2c_clk = i2c_clk;
/* Set the gpio to low when we've got something to say */ /* Set the gpio to low when we've got something to say */
err = gpio_request(nvec->gpio, "nvec gpio"); err = gpio_request(nvec->gpio, "nvec gpio");
if(err < 0) if(err < 0)
dev_err(nvec->dev, "couldn't request gpio\n"); dev_err(nvec->dev, "couldn't request gpio\n");
tegra_gpio_enable(nvec->gpio);
gpio_direction_output(nvec->gpio, 1);
gpio_set_value(nvec->gpio, 1);
ATOMIC_INIT_NOTIFIER_HEAD(&nvec->notifier_list); ATOMIC_INIT_NOTIFIER_HEAD(&nvec->notifier_list);
init_completion(&nvec->sync_write); init_completion(&nvec->sync_write);
...@@ -366,20 +379,21 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev) ...@@ -366,20 +379,21 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
INIT_WORK(&nvec->rx_work, nvec_dispatch); INIT_WORK(&nvec->rx_work, nvec_dispatch);
INIT_WORK(&nvec->tx_work, nvec_request_master); INIT_WORK(&nvec->tx_work, nvec_request_master);
err = request_irq(nvec->irq, nvec_interrupt, 0, "nvec", nvec);
if (err) {
dev_err(nvec->dev, "couldn't request irq\n");
goto failed;
}
tegra_init_i2c_slave(nvec);
gpio_direction_output(nvec->gpio, 1);
gpio_set_value(nvec->gpio, 1);
/* enable event reporting */ /* enable event reporting */
nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING, nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING,
sizeof(EC_ENABLE_EVENT_REPORTING)); sizeof(EC_ENABLE_EVENT_REPORTING));
nvec_kbd_init(nvec);
#ifdef CONFIG_SERIO_NVEC_PS2
nvec_ps2(nvec);
#endif
/* setup subdevs */
for (i = 0; i < pdata->num_subdevs; i++) {
ret = nvec_add_subdev(nvec, &pdata->subdevs[i]);
}
nvec->nvec_status_notifier.notifier_call = nvec_status_notifier; nvec->nvec_status_notifier.notifier_call = nvec_status_notifier;
nvec_register_notifier(nvec, &nvec->nvec_status_notifier, 0); nvec_register_notifier(nvec, &nvec->nvec_status_notifier, 0);
...@@ -396,6 +410,11 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev) ...@@ -396,6 +410,11 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
kfree(msg->data); kfree(msg->data);
kfree(msg); kfree(msg);
ret = mfd_add_devices(nvec->dev, -1, nvec_devices,
ARRAY_SIZE(nvec_devices), base, 0);
if(ret)
dev_err(nvec->dev, "error adding subdevices\n");
/* unmute speakers? */ /* unmute speakers? */
nvec_write_async(nvec, "\x0d\x10\x59\x94", 4); nvec_write_async(nvec, "\x0d\x10\x59\x94", 4);
...@@ -407,6 +426,8 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev) ...@@ -407,6 +426,8 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
return 0; return 0;
err_iounmap:
iounmap(base);
failed: failed:
kfree(nvec); kfree(nvec);
return -ENOMEM; return -ENOMEM;
...@@ -414,7 +435,15 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev) ...@@ -414,7 +435,15 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
static int __devexit tegra_nvec_remove(struct platform_device *pdev) static int __devexit tegra_nvec_remove(struct platform_device *pdev)
{ {
// TODO: unregister struct nvec_chip *nvec = platform_get_drvdata(pdev);
nvec_write_async(nvec, EC_DISABLE_EVENT_REPORTING, 3);
mfd_remove_devices(nvec->dev);
free_irq(nvec->irq, &nvec_interrupt);
iounmap(nvec->base);
gpio_free(nvec->gpio);
kfree(nvec);
return 0; return 0;
} }
...@@ -436,6 +465,7 @@ static int tegra_nvec_resume(struct platform_device *pdev) { ...@@ -436,6 +465,7 @@ static int tegra_nvec_resume(struct platform_device *pdev) {
struct nvec_chip *nvec = platform_get_drvdata(pdev); struct nvec_chip *nvec = platform_get_drvdata(pdev);
dev_dbg(nvec->dev, "resuming\n"); dev_dbg(nvec->dev, "resuming\n");
tegra_init_i2c_slave(nvec);
nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING, 3); nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING, 3);
return 0; return 0;
......
...@@ -45,21 +45,17 @@ struct nvec_subdev { ...@@ -45,21 +45,17 @@ struct nvec_subdev {
}; };
struct nvec_platform_data { struct nvec_platform_data {
int num_subdevs;
int i2c_addr; int i2c_addr;
int gpio; int gpio;
int irq;
int base;
int size;
char clock[16];
struct nvec_subdev *subdevs;
}; };
struct nvec_chip { struct nvec_chip {
struct device *dev; struct device *dev;
int gpio; int gpio;
int irq; int irq;
unsigned char *i2c_regs; int i2c_addr;
void __iomem *base;
struct clk *i2c_clk;
nvec_state state; nvec_state state;
struct atomic_notifier_head notifier_list; struct atomic_notifier_head notifier_list;
struct list_head rx_data, tx_data; struct list_head rx_data, tx_data;
...@@ -84,9 +80,6 @@ extern int nvec_unregister_notifier(struct device *dev, ...@@ -84,9 +80,6 @@ extern int nvec_unregister_notifier(struct device *dev,
const char *nvec_send_msg(unsigned char *src, unsigned char *dst_size, how_care care_resp, void (*rt_handler)(unsigned char *data)); const char *nvec_send_msg(unsigned char *src, unsigned char *dst_size, how_care care_resp, void (*rt_handler)(unsigned char *data));
extern int nvec_ps2(struct nvec_chip *nvec);
extern int nvec_kbd_init(struct nvec_chip *nvec);
#define I2C_CNFG 0x00 #define I2C_CNFG 0x00
#define I2C_CNFG_PACKET_MODE_EN (1<<10) #define I2C_CNFG_PACKET_MODE_EN (1<<10)
#define I2C_CNFG_NEW_MASTER_SFM (1<<11) #define I2C_CNFG_NEW_MASTER_SFM (1<<11)
......
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/platform_device.h>
#include "nvec-keytable.h" #include "nvec-keytable.h"
#include "nvec.h" #include "nvec.h"
...@@ -66,8 +67,9 @@ static int nvec_kbd_event(struct input_dev *dev, unsigned int type, ...@@ -66,8 +67,9 @@ static int nvec_kbd_event(struct input_dev *dev, unsigned int type,
return 0; return 0;
} }
int __init nvec_kbd_init(struct nvec_chip *nvec) static int __devinit nvec_kbd_probe(struct platform_device *pdev)
{ {
struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
int i, j, err; int i, j, err;
struct input_dev *idev; struct input_dev *idev;
...@@ -120,3 +122,18 @@ int __init nvec_kbd_init(struct nvec_chip *nvec) ...@@ -120,3 +122,18 @@ int __init nvec_kbd_init(struct nvec_chip *nvec)
input_free_device(idev); input_free_device(idev);
return err; return err;
} }
static struct platform_driver nvec_kbd_driver = {
.probe = nvec_kbd_probe,
.driver = {
.name = "nvec-kbd",
.owner = THIS_MODULE,
},
};
static int __init nvec_kbd_init(void)
{
return platform_driver_register(&nvec_kbd_driver);
}
module_init(nvec_kbd_init);
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/platform_device.h>
#include "nvec.h" #include "nvec.h"
#define START_STREAMING {'\x06','\x03','\x01'} #define START_STREAMING {'\x06','\x03','\x01'}
...@@ -77,8 +78,9 @@ static int nvec_ps2_notifier(struct notifier_block *nb, ...@@ -77,8 +78,9 @@ static int nvec_ps2_notifier(struct notifier_block *nb,
} }
int __init nvec_ps2(struct nvec_chip *nvec) static int __devinit nvec_mouse_probe(struct platform_device *pdev)
{ {
struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
struct serio *ser_dev = kzalloc(sizeof(struct serio), GFP_KERNEL); struct serio *ser_dev = kzalloc(sizeof(struct serio), GFP_KERNEL);
ser_dev->id.type=SERIO_8042; ser_dev->id.type=SERIO_8042;
...@@ -101,3 +103,18 @@ int __init nvec_ps2(struct nvec_chip *nvec) ...@@ -101,3 +103,18 @@ int __init nvec_ps2(struct nvec_chip *nvec)
return 0; return 0;
} }
static struct platform_driver nvec_mouse_driver = {
.probe = nvec_mouse_probe,
.driver = {
.name = "nvec-mouse",
.owner = THIS_MODULE,
},
};
static int __init nvec_mouse_init(void)
{
return platform_driver_register(&nvec_mouse_driver);
}
module_init(nvec_mouse_init);
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