Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 267717
b: refs/heads/master
c: f686e9a
h: refs/heads/master
i:
  267715: 4dc0549
v: v3
  • Loading branch information
Marc Dietrich authored and Greg Kroah-Hartman committed Aug 24, 2011
1 parent 826ac64 commit 98f8332
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 82 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 208b813c04ef7e628783cc62eeb1a140ae25bd19
refs/heads/master: f686e9affba24cfdf94fb155aaeb36a1e14719f1
168 changes: 99 additions & 69 deletions trunk/drivers/staging/nvec/nvec.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#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'};
Expand All @@ -30,6 +31,25 @@ static unsigned char EC_GET_FIRMWARE_VERSION[] = {'\x07','\x15'};

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)
{
Expand Down Expand Up @@ -139,7 +159,7 @@ static void nvec_dispatch(struct work_struct *work)
} 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);
Expand All @@ -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 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))
{
Expand Down Expand Up @@ -222,18 +242,18 @@ static irqreturn_t i2c_interrupt(int irq, void *dev)
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);

dev_dbg(nvec->dev, "nvec sent %x\n", to_send);

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;
}

Expand All @@ -258,37 +278,26 @@ static irqreturn_t i2c_interrupt(int irq, void *dev)
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)
Expand All @@ -299,12 +308,14 @@ 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) {
Expand All @@ -314,49 +325,51 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
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);
Expand All @@ -366,20 +379,21 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
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);

Expand All @@ -396,6 +410,11 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
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);

Expand All @@ -407,14 +426,24 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)

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;
}

Expand All @@ -436,6 +465,7 @@ static int tegra_nvec_resume(struct platform_device *pdev) {
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;
Expand Down
13 changes: 3 additions & 10 deletions trunk/drivers/staging/nvec/nvec.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,17 @@ struct nvec_subdev {
};

struct nvec_platform_data {
int num_subdevs;
int i2c_addr;
int gpio;
int irq;
int base;
int size;
char clock[16];
struct nvec_subdev *subdevs;
};

struct nvec_chip {
struct device *dev;
int gpio;
int irq;
unsigned char *i2c_regs;
int i2c_addr;
void __iomem *base;
struct clk *i2c_clk;
nvec_state state;
struct atomic_notifier_head notifier_list;
struct list_head rx_data, tx_data;
Expand All @@ -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));

extern int nvec_ps2(struct nvec_chip *nvec);
extern int nvec_kbd_init(struct nvec_chip *nvec);

#define I2C_CNFG 0x00
#define I2C_CNFG_PACKET_MODE_EN (1<<10)
#define I2C_CNFG_NEW_MASTER_SFM (1<<11)
Expand Down
19 changes: 18 additions & 1 deletion trunk/drivers/staging/nvec/nvec_kbd.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include "nvec-keytable.h"
#include "nvec.h"

Expand Down Expand Up @@ -66,8 +67,9 @@ static int nvec_kbd_event(struct input_dev *dev, unsigned int type,
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;
struct input_dev *idev;

Expand Down Expand Up @@ -120,3 +122,18 @@ int __init nvec_kbd_init(struct nvec_chip *nvec)
input_free_device(idev);
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);
Loading

0 comments on commit 98f8332

Please sign in to comment.