1e21e245bcd9d5244735799387d14421789b20557David S. Miller/* bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * platforms. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4e21e245bcd9d5244735799387d14421789b20557David S. Miller * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net) 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/wait.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 16e21e245bcd9d5244735799387d14421789b20557David S. Miller#include <linux/of.h> 17e21e245bcd9d5244735799387d14421789b20557David S. Miller#include <linux/of_device.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/bbc.h> 194b5dff76a70cb1d8b935b8b93fe0df0bbe66640dDavid S. Miller#include <asm/io.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "bbc_i2c.h" 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Convert this driver to use i2c bus layer someday... */ 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_PIN 0x80 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_ESO 0x40 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_ES1 0x20 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_ES2 0x10 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_ENI 0x08 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_STA 0x04 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_STO 0x02 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_ACK 0x01 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_START (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ENI | I2C_PCF_STA | I2C_PCF_ACK) 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_STOP (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK) 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_REPSTART ( I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK) 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_IDLE (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ACK) 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_INI 0x40 /* 1 if not initialized */ 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_STS 0x20 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_BER 0x10 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_AD0 0x08 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_LRB 0x08 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_AAS 0x04 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_LAB 0x02 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define I2C_PCF_BB 0x01 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The BBC devices have two I2C controllers. The first I2C controller 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * connects mainly to configuration proms (NVRAM, cpu configuration, 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dimm types, etc.). Whereas the second I2C controller connects to 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * environmental control devices such as fans and temperature sensors. 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The second controller also connects to the smartcard reader, if present. 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 542dc11581376829303b98eadb2de253bee065a56aGrant Likelystatic void set_device_claimage(struct bbc_i2c_bus *bp, struct platform_device *op, int val) 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < NUM_CHILDREN; i++) { 59e21e245bcd9d5244735799387d14421789b20557David S. Miller if (bp->devs[i].device == op) { 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->devs[i].client_claimed = val; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define claim_device(BP,ECHILD) set_device_claimage(BP,ECHILD,1) 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define release_device(BP,ECHILD) set_device_claimage(BP,ECHILD,0) 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 692dc11581376829303b98eadb2de253bee065a56aGrant Likelystruct platform_device *bbc_i2c_getdev(struct bbc_i2c_bus *bp, int index) 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 712dc11581376829303b98eadb2de253bee065a56aGrant Likely struct platform_device *op = NULL; 72e21e245bcd9d5244735799387d14421789b20557David S. Miller int curidx = 0, i; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74e21e245bcd9d5244735799387d14421789b20557David S. Miller for (i = 0; i < NUM_CHILDREN; i++) { 75e21e245bcd9d5244735799387d14421789b20557David S. Miller if (!(op = bp->devs[i].device)) 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 77e21e245bcd9d5244735799387d14421789b20557David S. Miller if (curidx == index) 78e21e245bcd9d5244735799387d14421789b20557David S. Miller goto out; 79e21e245bcd9d5244735799387d14421789b20557David S. Miller op = NULL; 80e21e245bcd9d5244735799387d14421789b20557David S. Miller curidx++; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curidx == index) 85e21e245bcd9d5244735799387d14421789b20557David S. Miller return op; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 892dc11581376829303b98eadb2de253bee065a56aGrant Likelystruct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct platform_device *op) 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bbc_i2c_client *client; 92e21e245bcd9d5244735799387d14421789b20557David S. Miller const u32 *reg; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 94dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau client = kzalloc(sizeof(*client), GFP_KERNEL); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!client) 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client->bp = bp; 98e21e245bcd9d5244735799387d14421789b20557David S. Miller client->op = op; 99e21e245bcd9d5244735799387d14421789b20557David S. Miller 10061c7a080a5a061c976988fd4b844dfb468dda255Grant Likely reg = of_get_property(op->dev.of_node, "reg", NULL); 101e21e245bcd9d5244735799387d14421789b20557David S. Miller if (!reg) { 102e21e245bcd9d5244735799387d14421789b20557David S. Miller kfree(client); 103e21e245bcd9d5244735799387d14421789b20557David S. Miller return NULL; 104e21e245bcd9d5244735799387d14421789b20557David S. Miller } 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 106e21e245bcd9d5244735799387d14421789b20557David S. Miller client->bus = reg[0]; 107e21e245bcd9d5244735799387d14421789b20557David S. Miller client->address = reg[1]; 108e21e245bcd9d5244735799387d14421789b20557David S. Miller 109e21e245bcd9d5244735799387d14421789b20557David S. Miller claim_device(bp, op); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return client; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid bbc_i2c_detach(struct bbc_i2c_client *client) 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bbc_i2c_bus *bp = client->bp; 1172dc11581376829303b98eadb2de253bee065a56aGrant Likely struct platform_device *op = client->op; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 119e21e245bcd9d5244735799387d14421789b20557David S. Miller release_device(bp, op); 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(client); 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_for_pin(struct bbc_i2c_bus *bp, u8 *status) 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DECLARE_WAITQUEUE(wait, current); 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int limit = 32; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 1; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->waiting = 1; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_wait_queue(&bp->wq, &wait); 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (limit-- > 0) { 132f4c13638185c91a269c63fcfb980d89180cf43a1Roel Kluin long val; 1333b36fb8471f8639d565b69c9a456a3ef9413df59David S. Miller 1343b36fb8471f8639d565b69c9a456a3ef9413df59David S. Miller val = wait_event_interruptible_timeout( 1353b36fb8471f8639d565b69c9a456a3ef9413df59David S. Miller bp->wq, 1363b36fb8471f8639d565b69c9a456a3ef9413df59David S. Miller (((*status = readb(bp->i2c_control_regs + 0)) 1373b36fb8471f8639d565b69c9a456a3ef9413df59David S. Miller & I2C_PCF_PIN) == 0), 1383b36fb8471f8639d565b69c9a456a3ef9413df59David S. Miller msecs_to_jiffies(250)); 1393b36fb8471f8639d565b69c9a456a3ef9413df59David S. Miller if (val > 0) { 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remove_wait_queue(&bp->wq, &wait); 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->waiting = 0; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint bbc_i2c_writeb(struct bbc_i2c_client *client, unsigned char val, int off) 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bbc_i2c_bus *bp = client->bp; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int address = client->address; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 status; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -1; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->i2c_bussel_reg != NULL) 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(client->bus, bp->i2c_bussel_reg); 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(address, bp->i2c_control_regs + 0x1); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wait_for_pin(bp, &status)) 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(off, bp->i2c_control_regs + 0x1); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wait_for_pin(bp, &status) || 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (status & I2C_PCF_LRB) != 0) 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(val, bp->i2c_control_regs + 0x1); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wait_for_pin(bp, &status)) 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint bbc_i2c_readb(struct bbc_i2c_client *client, unsigned char *byte, int off) 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bbc_i2c_bus *bp = client->bp; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char address = client->address, status; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -1; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->i2c_bussel_reg != NULL) 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(client->bus, bp->i2c_bussel_reg); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(address, bp->i2c_control_regs + 0x1); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wait_for_pin(bp, &status)) 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(off, bp->i2c_control_regs + 0x1); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wait_for_pin(bp, &status) || 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (status & I2C_PCF_LRB) != 0) 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0); 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds address |= 0x1; /* READ */ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(address, bp->i2c_control_regs + 0x1); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wait_for_pin(bp, &status)) 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set PIN back to one so the device sends the first 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte. 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) readb(bp->i2c_control_regs + 0x1); 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wait_for_pin(bp, &status)) 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(I2C_PCF_ESO | I2C_PCF_ENI, bp->i2c_control_regs + 0x0); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *byte = readb(bp->i2c_control_regs + 0x1); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wait_for_pin(bp, &status)) 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0); 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) readb(bp->i2c_control_regs + 0x1); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint bbc_i2c_write_buf(struct bbc_i2c_client *client, 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf, int len, int off) 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (len > 0) { 236e410471029ba99e85af5e2a1e7e747c7b4de2bc3Axel Lin ret = bbc_i2c_writeb(client, *buf, off); 237e410471029ba99e85af5e2a1e7e747c7b4de2bc3Axel Lin if (ret < 0) 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len--; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf++; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds off++; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint bbc_i2c_read_buf(struct bbc_i2c_client *client, 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf, int len, int off) 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (len > 0) { 252e410471029ba99e85af5e2a1e7e747c7b4de2bc3Axel Lin ret = bbc_i2c_readb(client, buf, off); 253e410471029ba99e85af5e2a1e7e747c7b4de2bc3Axel Lin if (ret < 0) 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len--; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf++; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds off++; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(bbc_i2c_getdev); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(bbc_i2c_attach); 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(bbc_i2c_detach); 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(bbc_i2c_writeb); 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(bbc_i2c_readb); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(bbc_i2c_write_buf); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(bbc_i2c_read_buf); 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2717d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t bbc_i2c_interrupt(int irq, void *dev_id) 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bbc_i2c_bus *bp = dev_id; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PIN going from set to clear is the only event which 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * makes the i2c assert an interrupt. 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->waiting && 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !(readb(bp->i2c_control_regs + 0x0) & I2C_PCF_PIN)) 2803b36fb8471f8639d565b69c9a456a3ef9413df59David S. Miller wake_up_interruptible(&bp->wq); 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __init reset_one_i2c(struct bbc_i2c_bus *bp) 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(I2C_PCF_PIN, bp->i2c_control_regs + 0x0); 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(bp->own, bp->i2c_control_regs + 0x1); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(I2C_PCF_PIN | I2C_PCF_ES1, bp->i2c_control_regs + 0x0); 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(bp->clock, bp->i2c_control_regs + 0x1); 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0); 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2942dc11581376829303b98eadb2de253bee065a56aGrant Likelystatic struct bbc_i2c_bus * __init attach_one_i2c(struct platform_device *op, int index) 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 29650aa485e1abb7566ce68418c7bbc6a6b454f9039Mariusz Kozlowski struct bbc_i2c_bus *bp; 297e21e245bcd9d5244735799387d14421789b20557David S. Miller struct device_node *dp; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int entry; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30050aa485e1abb7566ce68418c7bbc6a6b454f9039Mariusz Kozlowski bp = kzalloc(sizeof(*bp), GFP_KERNEL); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bp) 302e21e245bcd9d5244735799387d14421789b20557David S. Miller return NULL; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 304e21e245bcd9d5244735799387d14421789b20557David S. Miller bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs"); 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bp->i2c_control_regs) 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 308e21e245bcd9d5244735799387d14421789b20557David S. Miller bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel"); 309e21e245bcd9d5244735799387d14421789b20557David S. Miller if (!bp->i2c_bussel_reg) 310e21e245bcd9d5244735799387d14421789b20557David S. Miller goto fail; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->waiting = 0; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&bp->wq); 3141636f8ac2b08410df4766449f7c86b912443cd99Grant Likely if (request_irq(op->archdata.irqs[0], bbc_i2c_interrupt, 315dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner IRQF_SHARED, "bbc_i2c", bp)) 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->index = index; 319e21e245bcd9d5244735799387d14421789b20557David S. Miller bp->op = op; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&bp->lock); 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = 0; 32461c7a080a5a061c976988fd4b844dfb468dda255Grant Likely for (dp = op->dev.of_node->child; 325e21e245bcd9d5244735799387d14421789b20557David S. Miller dp && entry < 8; 326e21e245bcd9d5244735799387d14421789b20557David S. Miller dp = dp->sibling, entry++) { 3272dc11581376829303b98eadb2de253bee065a56aGrant Likely struct platform_device *child_op; 328e21e245bcd9d5244735799387d14421789b20557David S. Miller 329e21e245bcd9d5244735799387d14421789b20557David S. Miller child_op = of_find_device_by_node(dp); 330e21e245bcd9d5244735799387d14421789b20557David S. Miller bp->devs[entry].device = child_op; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->devs[entry].client_claimed = 0; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(I2C_PCF_PIN, bp->i2c_control_regs + 0x0); 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->own = readb(bp->i2c_control_regs + 0x01); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(I2C_PCF_PIN | I2C_PCF_ES1, bp->i2c_control_regs + 0x0); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->clock = readb(bp->i2c_control_regs + 0x01); 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "i2c-%d: Regs at %p, %d devices, own %02x, clock %02x.\n", 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bp->index, bp->i2c_control_regs, entry, bp->own, bp->clock); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reset_one_i2c(bp); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 344e21e245bcd9d5244735799387d14421789b20557David S. Miller return bp; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfail: 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->i2c_bussel_reg) 348e21e245bcd9d5244735799387d14421789b20557David S. Miller of_iounmap(&op->resource[1], bp->i2c_bussel_reg, 1); 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bp->i2c_control_regs) 350e21e245bcd9d5244735799387d14421789b20557David S. Miller of_iounmap(&op->resource[0], bp->i2c_control_regs, 2); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(bp); 352e21e245bcd9d5244735799387d14421789b20557David S. Miller return NULL; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 355e21e245bcd9d5244735799387d14421789b20557David S. Millerextern int bbc_envctrl_init(struct bbc_i2c_bus *bp); 356e21e245bcd9d5244735799387d14421789b20557David S. Millerextern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3584ebb24f707187196937607c60810d42f7112d7aaGrant Likelystatic int __devinit bbc_i2c_probe(struct platform_device *op) 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 360e21e245bcd9d5244735799387d14421789b20557David S. Miller struct bbc_i2c_bus *bp; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err, index = 0; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 363e21e245bcd9d5244735799387d14421789b20557David S. Miller bp = attach_one_i2c(op, index); 364e21e245bcd9d5244735799387d14421789b20557David S. Miller if (!bp) 365e21e245bcd9d5244735799387d14421789b20557David S. Miller return -EINVAL; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 367e21e245bcd9d5244735799387d14421789b20557David S. Miller err = bbc_envctrl_init(bp); 368e21e245bcd9d5244735799387d14421789b20557David S. Miller if (err) { 3691636f8ac2b08410df4766449f7c86b912443cd99Grant Likely free_irq(op->archdata.irqs[0], bp); 370e21e245bcd9d5244735799387d14421789b20557David S. Miller if (bp->i2c_bussel_reg) 371e21e245bcd9d5244735799387d14421789b20557David S. Miller of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1); 372e21e245bcd9d5244735799387d14421789b20557David S. Miller if (bp->i2c_control_regs) 373e21e245bcd9d5244735799387d14421789b20557David S. Miller of_iounmap(&op->resource[1], bp->i2c_control_regs, 2); 374e21e245bcd9d5244735799387d14421789b20557David S. Miller kfree(bp); 375e21e245bcd9d5244735799387d14421789b20557David S. Miller } else { 376e21e245bcd9d5244735799387d14421789b20557David S. Miller dev_set_drvdata(&op->dev, bp); 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3822dc11581376829303b98eadb2de253bee065a56aGrant Likelystatic int __devexit bbc_i2c_remove(struct platform_device *op) 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 384e21e245bcd9d5244735799387d14421789b20557David S. Miller struct bbc_i2c_bus *bp = dev_get_drvdata(&op->dev); 385e21e245bcd9d5244735799387d14421789b20557David S. Miller 386e21e245bcd9d5244735799387d14421789b20557David S. Miller bbc_envctrl_cleanup(bp); 387e21e245bcd9d5244735799387d14421789b20557David S. Miller 3881636f8ac2b08410df4766449f7c86b912443cd99Grant Likely free_irq(op->archdata.irqs[0], bp); 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 390e21e245bcd9d5244735799387d14421789b20557David S. Miller if (bp->i2c_bussel_reg) 391e21e245bcd9d5244735799387d14421789b20557David S. Miller of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1); 392e21e245bcd9d5244735799387d14421789b20557David S. Miller if (bp->i2c_control_regs) 393e21e245bcd9d5244735799387d14421789b20557David S. Miller of_iounmap(&op->resource[1], bp->i2c_control_regs, 2); 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 395e21e245bcd9d5244735799387d14421789b20557David S. Miller kfree(bp); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 397e21e245bcd9d5244735799387d14421789b20557David S. Miller return 0; 398e21e245bcd9d5244735799387d14421789b20557David S. Miller} 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 400fd098316ef533e8441576f020ead4beab93154ceDavid S. Millerstatic const struct of_device_id bbc_i2c_match[] = { 401e21e245bcd9d5244735799387d14421789b20557David S. Miller { 402e21e245bcd9d5244735799387d14421789b20557David S. Miller .name = "i2c", 403e21e245bcd9d5244735799387d14421789b20557David S. Miller .compatible = "SUNW,bbc-i2c", 404e21e245bcd9d5244735799387d14421789b20557David S. Miller }, 405e21e245bcd9d5244735799387d14421789b20557David S. Miller {}, 406e21e245bcd9d5244735799387d14421789b20557David S. Miller}; 407e21e245bcd9d5244735799387d14421789b20557David S. MillerMODULE_DEVICE_TABLE(of, bbc_i2c_match); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4094ebb24f707187196937607c60810d42f7112d7aaGrant Likelystatic struct platform_driver bbc_i2c_driver = { 4104018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .driver = { 4114018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .name = "bbc_i2c", 4124018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .owner = THIS_MODULE, 4134018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .of_match_table = bbc_i2c_match, 4144018294b53d1dae026880e45f174c1cc63b5d435Grant Likely }, 415e21e245bcd9d5244735799387d14421789b20557David S. Miller .probe = bbc_i2c_probe, 41633b07db9f38fe73b3895f8d4db8fdee03e3afec3Linus Torvalds .remove = __devexit_p(bbc_i2c_remove), 417e21e245bcd9d5244735799387d14421789b20557David S. Miller}; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 419dbf2b92d54e73e4a2524b90d29bd498ecc4aa593Axel Linmodule_platform_driver(bbc_i2c_driver); 420e21e245bcd9d5244735799387d14421789b20557David S. Miller 421b5e7ae5dd034c2c0ed75c31fca04a805097817bcDavid S. MillerMODULE_LICENSE("GPL"); 422