#include <linux/list.h>
#include <linux/notifier.h>
#include <linux/platform_device.h>
+#include <linux/mfd/core.h>
#include "nvec.h"
static unsigned char EC_DISABLE_EVENT_REPORTING[] = {'\x04','\x00','\x00'};
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,
unsigned int events)
{
} else {
parse_msg(nvec, msg);
if((!msg) || (!msg->data))
- dev_warn(nvec->dev, "attempt access zero pointer");
+ dev_warn(nvec->dev, "attempt access zero pointer\n");
else {
kfree(msg->data);
kfree(msg);
}
}
-static irqreturn_t i2c_interrupt(int irq, void *dev)
+static irqreturn_t nvec_interrupt(int irq, void *dev)
{
unsigned long status;
unsigned long received;
unsigned char to_send;
struct nvec_msg *msg;
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))
{
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);
goto handled;
} else {
- received = readl(i2c_regs + I2C_SL_RCVD);
+ received = readl(base + I2C_SL_RCVD);
//Workaround?
if(status & RCVD) {
- writel(0, i2c_regs + I2C_SL_RCVD);
+ writel(0, base + I2C_SL_RCVD);
goto handled;
}
return IRQ_HANDLED;
}
-static int __devinit nvec_add_subdev(struct nvec_chip *nvec, struct nvec_subdev *subdev)
-{
- 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)
+static void tegra_init_i2c_slave(struct nvec_chip *nvec)
{
u32 val;
- clk_enable(i2c_clk);
- tegra_periph_reset_assert(i2c_clk);
+ clk_enable(nvec->i2c_clk);
+
+ tegra_periph_reset_assert(nvec->i2c_clk);
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(0, i2c_regs + I2C_SL_ADDR2);
+ writel(nvec->i2c_addr>>1, nvec->base + I2C_SL_ADDR1);
+ 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 |
(0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
- writel(val, i2c_regs + I2C_CNFG);
- writel(I2C_SL_NEWL, i2c_regs + I2C_SL_CNFG);
+ writel(val, nvec->base + I2C_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 int __devinit tegra_nvec_probe(struct platform_device *pdev)
{
- int err, i, ret;
+ int err, ret;
struct clk *i2c_clk;
struct nvec_platform_data *pdata = pdev->dev.platform_data;
struct nvec_chip *nvec;
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);
if(nvec == NULL) {
platform_set_drvdata(pdev, nvec);
nvec->dev = &pdev->dev;
nvec->gpio = pdata->gpio;
- nvec->irq = pdata->irq;
-
-/*
- i2c_clk=clk_get_sys(NULL, "i2c");
- if(IS_ERR_OR_NULL(i2c_clk))
- printk(KERN_ERR"No such clock tegra-i2c.2\n");
- 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_addr = pdata->i2c_addr;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -ENODEV;
}
- 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);
- if(IS_ERR_OR_NULL(i2c_clk)) {
- dev_err(nvec->dev, "failed to get clock tegra-i2c.2\n");
- goto failed;
+ base = ioremap(iomem->start, resource_size(iomem));
+ if (!base) {
+ dev_err(&pdev->dev, "Can't ioremap I2C region\n");
+ 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);
- if(err) {
- dev_err(nvec->dev, "couldn't request irq");
- goto failed;
+ i2c_clk = clk_get_sys("tegra-i2c.2", NULL);
+ if (IS_ERR(i2c_clk)) {
+ dev_err(nvec->dev, "failed to get controller clock\n");
+ goto err_iounmap;
}
clk_enable(i2c_clk);
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 */
err = gpio_request(nvec->gpio, "nvec gpio");
if(err < 0)
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);
init_completion(&nvec->sync_write);
INIT_WORK(&nvec->rx_work, nvec_dispatch);
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 */
nvec_write_async(nvec, 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_register_notifier(nvec, &nvec->nvec_status_notifier, 0);
kfree(msg->data);
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? */
nvec_write_async(nvec, "\x0d\x10\x59\x94", 4);
return 0;
+err_iounmap:
+ iounmap(base);
failed:
kfree(nvec);
return -ENOMEM;
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;
}
struct nvec_chip *nvec = platform_get_drvdata(pdev);
dev_dbg(nvec->dev, "resuming\n");
+ tegra_init_i2c_slave(nvec);
nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING, 3);
return 0;