Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 308460
b: refs/heads/master
c: a092de1
h: refs/heads/master
v: v3
  • Loading branch information
Roland Stigge authored and Wolfram Sang committed May 12, 2012
1 parent 4e3cd0a commit 15fd5d1
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 17 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: 973c5ed45dbdf8fd90e300826507b5e6814916af
refs/heads/master: a092de11bb4a96ac43ede0352e09bdf7e06280e8
36 changes: 36 additions & 0 deletions trunk/Documentation/devicetree/bindings/i2c/pnx.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
* NXP PNX I2C Controller

Required properties:

- reg: Offset and length of the register set for the device
- compatible: should be "nxp,pnx-i2c"
- interrupts: configure one interrupt line
- #address-cells: always 1 (for i2c addresses)
- #size-cells: always 0
- interrupt-parent: the phandle for the interrupt controller that
services interrupts for this device.

Optional properties:

- clock-frequency: desired I2C bus clock frequency in Hz, Default: 100000 Hz

Examples:

i2c1: i2c@400a0000 {
compatible = "nxp,pnx-i2c";
reg = <0x400a0000 0x100>;
interrupt-parent = <&mic>;
interrupts = <51 0>;
#address-cells = <1>;
#size-cells = <0>;
};

i2c2: i2c@400a8000 {
compatible = "nxp,pnx-i2c";
reg = <0x400a8000 0x100>;
interrupt-parent = <&mic>;
interrupts = <50 0>;
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <100000>;
};
63 changes: 47 additions & 16 deletions trunk/drivers/i2c/busses/i2c-pnx.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/of_i2c.h>

#define I2C_PNX_TIMEOUT 10 /* msec */
#define I2C_PNX_SPEED_KHZ 100
#define I2C_PNX_REGION_SIZE 0x100
#define I2C_PNX_TIMEOUT_DEFAULT 10 /* msec */
#define I2C_PNX_SPEED_KHZ_DEFAULT 100
#define I2C_PNX_REGION_SIZE 0x100

enum {
mstatus_tdi = 0x00000001,
Expand Down Expand Up @@ -74,8 +75,9 @@ enum {
#define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */
#define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */

static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data)
static inline int wait_timeout(struct i2c_pnx_algo_data *data)
{
long timeout = data->timeout;
while (timeout > 0 &&
(ioread32(I2C_REG_STS(data)) & mstatus_active)) {
mdelay(1);
Expand All @@ -84,8 +86,9 @@ static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data)
return (timeout <= 0);
}

static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
static inline int wait_reset(struct i2c_pnx_algo_data *data)
{
long timeout = data->timeout;
while (timeout > 0 &&
(ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) {
mdelay(1);
Expand All @@ -97,7 +100,7 @@ static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data)
{
struct timer_list *timer = &alg_data->mif.timer;
unsigned long expires = msecs_to_jiffies(I2C_PNX_TIMEOUT);
unsigned long expires = msecs_to_jiffies(alg_data->timeout);

if (expires <= 1)
expires = 2;
Expand Down Expand Up @@ -135,7 +138,7 @@ static int i2c_pnx_start(unsigned char slave_addr,
}

/* First, make sure bus is idle */
if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) {
if (wait_timeout(alg_data)) {
/* Somebody else is monopolizing the bus */
dev_err(&alg_data->adapter.dev,
"%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n",
Expand Down Expand Up @@ -228,7 +231,7 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data)
if (alg_data->mif.len == 0) {
if (alg_data->last) {
/* Wait until the STOP is seen. */
if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
if (wait_timeout(alg_data))
dev_err(&alg_data->adapter.dev,
"The bus is still active after timeout\n");
}
Expand Down Expand Up @@ -326,7 +329,7 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data)
if (alg_data->mif.len == 0) {
if (alg_data->last)
/* Wait until the STOP is seen. */
if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
if (wait_timeout(alg_data))
dev_err(&alg_data->adapter.dev,
"The bus is still active after timeout\n");

Expand Down Expand Up @@ -442,7 +445,7 @@ static void i2c_pnx_timeout(unsigned long data)

ctl |= mcntrl_reset;
iowrite32(ctl, I2C_REG_CTL(alg_data));
wait_reset(I2C_PNX_TIMEOUT, alg_data);
wait_reset(alg_data);
alg_data->mif.ret = -EIO;
complete(&alg_data->mif.complete);
}
Expand All @@ -457,18 +460,18 @@ static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data)
alg_data->adapter.name);
iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
I2C_REG_CTL(alg_data));
wait_reset(I2C_PNX_TIMEOUT, alg_data);
wait_reset(alg_data);
} else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) {
/* If there is data in the fifo's after transfer,
* flush fifo's by reset.
*/
iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
I2C_REG_CTL(alg_data));
wait_reset(I2C_PNX_TIMEOUT, alg_data);
wait_reset(alg_data);
} else if (stat & mstatus_nai) {
iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
I2C_REG_CTL(alg_data));
wait_reset(I2C_PNX_TIMEOUT, alg_data);
wait_reset(alg_data);
}
}

Expand Down Expand Up @@ -612,6 +615,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
struct i2c_pnx_algo_data *alg_data;
unsigned long freq;
struct resource *res;
u32 speed = I2C_PNX_SPEED_KHZ_DEFAULT * 1000;

alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL);
if (!alg_data) {
Expand All @@ -626,6 +630,22 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
alg_data->adapter.algo_data = alg_data;
alg_data->adapter.nr = pdev->id;

alg_data->timeout = I2C_PNX_TIMEOUT_DEFAULT;
#ifdef CONFIG_OF
alg_data->adapter.dev.of_node = of_node_get(pdev->dev.of_node);
if (pdev->dev.of_node) {
of_property_read_u32(pdev->dev.of_node, "clock-frequency",
&speed);
/*
* At this point, it is planned to add an OF timeout property.
* As soon as there is a consensus about how to call and handle
* this, sth. like the following can be put here:
*
* of_property_read_u32(pdev->dev.of_node, "timeout",
* &alg_data->timeout);
*/
}
#endif
alg_data->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(alg_data->clk)) {
ret = PTR_ERR(alg_data->clk);
Expand All @@ -651,7 +671,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
dev_err(&pdev->dev,
"I/O region 0x%08x for I2C already in use.\n",
res->start);
ret = -ENODEV;
ret = -ENOMEM;
goto out_clkget;
}

Expand Down Expand Up @@ -680,14 +700,14 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
* the deglitching filter length.
*/

tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
tmp = (freq / speed) / 2 - 2;
if (tmp > 0x3FF)
tmp = 0x3FF;
iowrite32(tmp, I2C_REG_CKH(alg_data));
iowrite32(tmp, I2C_REG_CKL(alg_data));

iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data));
if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) {
if (wait_reset(alg_data)) {
ret = -ENODEV;
goto out_clock;
}
Expand All @@ -710,6 +730,8 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
goto out_irq;
}

of_i2c_register_devices(&alg_data->adapter);

dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
alg_data->adapter.name, res->start, alg_data->irq);

Expand Down Expand Up @@ -748,10 +770,19 @@ static int __devexit i2c_pnx_remove(struct platform_device *pdev)
return 0;
}

#ifdef CONFIG_OF
static const struct of_device_id i2c_pnx_of_match[] = {
{ .compatible = "nxp,pnx-i2c" },
{ },
};
MODULE_DEVICE_TABLE(of, i2c_pnx_of_match);
#endif

static struct platform_driver i2c_pnx_driver = {
.driver = {
.name = "pnx-i2c",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(i2c_pnx_of_match),
},
.probe = i2c_pnx_probe,
.remove = __devexit_p(i2c_pnx_remove),
Expand Down
1 change: 1 addition & 0 deletions trunk/include/linux/i2c-pnx.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct i2c_pnx_algo_data {
struct i2c_adapter adapter;
phys_addr_t base;
int irq;
u32 timeout;
};

#endif /* __I2C_PNX_H__ */

0 comments on commit 15fd5d1

Please sign in to comment.