forked from Sricharanti/sricharan
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
unicore32 machine related files: add i2c bus drivers for pkunity-v3 soc
change from original version -- by advice of Jean Delvare 1. remove global variable i2c_reg, replaced by local variables 2. replace ENXIO with ENODEV when no platform resources 3. add adapter->nr assignment before i2c_add_numbered_adapter() call 4. add judgement for i2c_del_adapter() return value 5. release adapter when driver removed 6. add __devexit for puv3_i2c_remove() function 7. modify several names to more appropriated ones Signed-off-by: Guan Xuetao <[email protected]> Acked-by: Arnd Bergmann <[email protected]>
- Loading branch information
Showing
5 changed files
with
323 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4901,6 +4901,7 @@ W: http://mprc.pku.edu.cn/~guanxuetao/linux | |
S: Maintained | ||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/epip/linux-2.6-unicore32.git | ||
F: drivers/input/serio/i8042-unicore32io.h | ||
F: drivers/i2c/busses/i2c-puv3.c | ||
|
||
PMC SIERRA MaxRAID DRIVER | ||
M: Anil Ravindranath <[email protected]> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,306 @@ | ||
/* | ||
* I2C driver for PKUnity-v3 SoC | ||
* Code specific to PKUnity SoC and UniCore ISA | ||
* | ||
* Maintained by GUAN Xue-tao <[email protected]> | ||
* Copyright (C) 2001-2010 Guan Xuetao | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
*/ | ||
|
||
#include <linux/module.h> | ||
#include <linux/kernel.h> | ||
#include <linux/err.h> | ||
#include <linux/slab.h> | ||
#include <linux/types.h> | ||
#include <linux/delay.h> | ||
#include <linux/i2c.h> | ||
#include <linux/init.h> | ||
#include <linux/clk.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/io.h> | ||
#include <mach/hardware.h> | ||
|
||
/* | ||
* Poll the i2c status register until the specified bit is set. | ||
* Returns 0 if timed out (100 msec). | ||
*/ | ||
static short poll_status(unsigned long bit) | ||
{ | ||
int loop_cntr = 1000; | ||
|
||
if (bit & I2C_STATUS_TFNF) { | ||
do { | ||
udelay(10); | ||
} while (!(readl(I2C_STATUS) & bit) && (--loop_cntr > 0)); | ||
} else { | ||
/* RXRDY handler */ | ||
do { | ||
if (readl(I2C_TAR) == I2C_TAR_EEPROM) | ||
msleep(20); | ||
else | ||
udelay(10); | ||
} while (!(readl(I2C_RXFLR) & 0xf) && (--loop_cntr > 0)); | ||
} | ||
|
||
return (loop_cntr > 0); | ||
} | ||
|
||
static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length) | ||
{ | ||
int i2c_reg = *buf; | ||
|
||
/* Read data */ | ||
while (length--) { | ||
if (!poll_status(I2C_STATUS_TFNF)) { | ||
dev_dbg(&adap->dev, "Tx FIFO Not Full timeout\n"); | ||
return -ETIMEDOUT; | ||
} | ||
|
||
/* send addr */ | ||
writel(i2c_reg | I2C_DATACMD_WRITE, I2C_DATACMD); | ||
|
||
/* get ready to next write */ | ||
i2c_reg++; | ||
|
||
/* send read CMD */ | ||
writel(I2C_DATACMD_READ, I2C_DATACMD); | ||
|
||
/* wait until the Rx FIFO have available */ | ||
if (!poll_status(I2C_STATUS_RFNE)) { | ||
dev_dbg(&adap->dev, "RXRDY timeout\n"); | ||
return -ETIMEDOUT; | ||
} | ||
|
||
/* read the data to buf */ | ||
*buf = (readl(I2C_DATACMD) & I2C_DATACMD_DAT_MASK); | ||
buf++; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length) | ||
{ | ||
int i2c_reg = *buf; | ||
|
||
/* Do nothing but storing the reg_num to a static variable */ | ||
if (i2c_reg == -1) { | ||
printk(KERN_WARNING "Error i2c reg\n"); | ||
return -ETIMEDOUT; | ||
} | ||
|
||
if (length == 1) | ||
return 0; | ||
|
||
buf++; | ||
length--; | ||
while (length--) { | ||
/* send addr */ | ||
writel(i2c_reg | I2C_DATACMD_WRITE, I2C_DATACMD); | ||
|
||
/* send write CMD */ | ||
writel(*buf | I2C_DATACMD_WRITE, I2C_DATACMD); | ||
|
||
/* wait until the Rx FIFO have available */ | ||
msleep(20); | ||
|
||
/* read the data to buf */ | ||
i2c_reg++; | ||
buf++; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
/* | ||
* Generic i2c master transfer entrypoint. | ||
* | ||
*/ | ||
static int puv3_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, | ||
int num) | ||
{ | ||
int i, ret; | ||
unsigned char swap; | ||
|
||
/* Disable i2c */ | ||
writel(I2C_ENABLE_DISABLE, I2C_ENABLE); | ||
|
||
/* Set the work mode and speed*/ | ||
writel(I2C_CON_MASTER | I2C_CON_SPEED_STD | I2C_CON_SLAVEDISABLE, I2C_CON); | ||
|
||
writel(pmsg->addr, I2C_TAR); | ||
|
||
/* Enable i2c */ | ||
writel(I2C_ENABLE_ENABLE, I2C_ENABLE); | ||
|
||
dev_dbg(&adap->dev, "puv3_i2c_xfer: processing %d messages:\n", num); | ||
|
||
for (i = 0; i < num; i++) { | ||
dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i, | ||
pmsg->flags & I2C_M_RD ? "read" : "writ", | ||
pmsg->len, pmsg->len > 1 ? "s" : "", | ||
pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr); | ||
|
||
if (pmsg->len && pmsg->buf) { /* sanity check */ | ||
if (pmsg->flags & I2C_M_RD) | ||
ret = xfer_read(adap, pmsg->buf, pmsg->len); | ||
else | ||
ret = xfer_write(adap, pmsg->buf, pmsg->len); | ||
|
||
if (ret) | ||
return ret; | ||
|
||
} | ||
dev_dbg(&adap->dev, "transfer complete\n"); | ||
pmsg++; /* next message */ | ||
} | ||
|
||
/* XXX: fixup be16_to_cpu in bq27x00_battery.c */ | ||
if (pmsg->addr == I2C_TAR_PWIC) { | ||
swap = pmsg->buf[0]; | ||
pmsg->buf[0] = pmsg->buf[1]; | ||
pmsg->buf[1] = swap; | ||
} | ||
|
||
return i; | ||
} | ||
|
||
/* | ||
* Return list of supported functionality. | ||
*/ | ||
static u32 puv3_i2c_func(struct i2c_adapter *adapter) | ||
{ | ||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||
} | ||
|
||
static struct i2c_algorithm puv3_i2c_algorithm = { | ||
.master_xfer = puv3_i2c_xfer, | ||
.functionality = puv3_i2c_func, | ||
}; | ||
|
||
/* | ||
* Main initialization routine. | ||
*/ | ||
static int __devinit puv3_i2c_probe(struct platform_device *pdev) | ||
{ | ||
struct i2c_adapter *adapter; | ||
struct resource *mem; | ||
int rc; | ||
|
||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
if (!mem) | ||
return -ENODEV; | ||
|
||
if (!request_mem_region(mem->start, resource_size(mem), "puv3_i2c")) | ||
return -EBUSY; | ||
|
||
adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); | ||
if (adapter == NULL) { | ||
dev_err(&pdev->dev, "can't allocate inteface!\n"); | ||
rc = -ENOMEM; | ||
goto fail_nomem; | ||
} | ||
snprintf(adapter->name, sizeof(adapter->name), "PUV3-I2C at 0x%08x", | ||
mem->start); | ||
adapter->algo = &puv3_i2c_algorithm; | ||
adapter->class = I2C_CLASS_HWMON; | ||
adapter->dev.parent = &pdev->dev; | ||
|
||
platform_set_drvdata(pdev, adapter); | ||
|
||
adapter->nr = pdev->id; | ||
rc = i2c_add_numbered_adapter(adapter); | ||
if (rc) { | ||
dev_err(&pdev->dev, "Adapter '%s' registration failed\n", | ||
adapter->name); | ||
goto fail_add_adapter; | ||
} | ||
|
||
dev_info(&pdev->dev, "PKUnity v3 i2c bus adapter.\n"); | ||
return 0; | ||
|
||
fail_add_adapter: | ||
platform_set_drvdata(pdev, NULL); | ||
kfree(adapter); | ||
fail_nomem: | ||
release_mem_region(mem->start, resource_size(mem)); | ||
|
||
return rc; | ||
} | ||
|
||
static int __devexit puv3_i2c_remove(struct platform_device *pdev) | ||
{ | ||
struct i2c_adapter *adapter = platform_get_drvdata(pdev); | ||
struct resource *mem; | ||
int rc; | ||
|
||
rc = i2c_del_adapter(adapter); | ||
if (rc) { | ||
dev_err(&pdev->dev, "Adapter '%s' delete fail\n", | ||
adapter->name); | ||
return rc; | ||
} | ||
|
||
put_device(&pdev->dev); | ||
platform_set_drvdata(pdev, NULL); | ||
|
||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
release_mem_region(mem->start, resource_size(mem)); | ||
|
||
return rc; | ||
} | ||
|
||
#ifdef CONFIG_PM | ||
static int puv3_i2c_suspend(struct platform_device *dev, pm_message_t state) | ||
{ | ||
int poll_count; | ||
/* Disable the IIC */ | ||
writel(I2C_ENABLE_DISABLE, I2C_ENABLE); | ||
for (poll_count = 0; poll_count < 50; poll_count++) { | ||
if (readl(I2C_ENSTATUS) & I2C_ENSTATUS_ENABLE) | ||
udelay(25); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int puv3_i2c_resume(struct platform_device *dev) | ||
{ | ||
return 0 ; | ||
} | ||
#else | ||
#define puv3_i2c_suspend NULL | ||
#define puv3_i2c_resume NULL | ||
#endif | ||
|
||
MODULE_ALIAS("platform:puv3_i2c"); | ||
|
||
static struct platform_driver puv3_i2c_driver = { | ||
.probe = puv3_i2c_probe, | ||
.remove = __devexit_p(puv3_i2c_remove), | ||
.suspend = puv3_i2c_suspend, | ||
.resume = puv3_i2c_resume, | ||
.driver = { | ||
.name = "PKUnity-v3-I2C", | ||
.owner = THIS_MODULE, | ||
} | ||
}; | ||
|
||
static int __init puv3_i2c_init(void) | ||
{ | ||
return platform_driver_register(&puv3_i2c_driver); | ||
} | ||
|
||
static void __exit puv3_i2c_exit(void) | ||
{ | ||
platform_driver_unregister(&puv3_i2c_driver); | ||
} | ||
|
||
module_init(puv3_i2c_init); | ||
module_exit(puv3_i2c_exit); | ||
|
||
MODULE_DESCRIPTION("PKUnity v3 I2C driver"); | ||
MODULE_LICENSE("GPL v2"); |