linux/drivers/sbus/char/bbc_i2c.c
<<
>>
Prefs
   1/* bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III
   2 *            platforms.
   3 *
   4 * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
   5 */
   6
   7#include <linux/module.h>
   8#include <linux/kernel.h>
   9#include <linux/types.h>
  10#include <linux/slab.h>
  11#include <linux/sched.h>
  12#include <linux/wait.h>
  13#include <linux/delay.h>
  14#include <linux/init.h>
  15#include <linux/interrupt.h>
  16#include <linux/of.h>
  17#include <linux/of_device.h>
  18#include <asm/bbc.h>
  19#include <asm/io.h>
  20
  21#include "bbc_i2c.h"
  22
  23/* Convert this driver to use i2c bus layer someday... */
  24#define I2C_PCF_PIN     0x80
  25#define I2C_PCF_ESO     0x40
  26#define I2C_PCF_ES1     0x20
  27#define I2C_PCF_ES2     0x10
  28#define I2C_PCF_ENI     0x08
  29#define I2C_PCF_STA     0x04
  30#define I2C_PCF_STO     0x02
  31#define I2C_PCF_ACK     0x01
  32
  33#define I2C_PCF_START    (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ENI | I2C_PCF_STA | I2C_PCF_ACK)
  34#define I2C_PCF_STOP     (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK)
  35#define I2C_PCF_REPSTART (              I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
  36#define I2C_PCF_IDLE     (I2C_PCF_PIN | I2C_PCF_ESO               | I2C_PCF_ACK)
  37
  38#define I2C_PCF_INI 0x40   /* 1 if not initialized */
  39#define I2C_PCF_STS 0x20
  40#define I2C_PCF_BER 0x10
  41#define I2C_PCF_AD0 0x08
  42#define I2C_PCF_LRB 0x08
  43#define I2C_PCF_AAS 0x04
  44#define I2C_PCF_LAB 0x02
  45#define I2C_PCF_BB  0x01
  46
  47/* The BBC devices have two I2C controllers.  The first I2C controller
  48 * connects mainly to configuration proms (NVRAM, cpu configuration,
  49 * dimm types, etc.).  Whereas the second I2C controller connects to
  50 * environmental control devices such as fans and temperature sensors.
  51 * The second controller also connects to the smartcard reader, if present.
  52 */
  53
  54static void set_device_claimage(struct bbc_i2c_bus *bp, struct platform_device *op, int val)
  55{
  56        int i;
  57
  58        for (i = 0; i < NUM_CHILDREN; i++) {
  59                if (bp->devs[i].device == op) {
  60                        bp->devs[i].client_claimed = val;
  61                        return;
  62                }
  63        }
  64}
  65
  66#define claim_device(BP,ECHILD)         set_device_claimage(BP,ECHILD,1)
  67#define release_device(BP,ECHILD)       set_device_claimage(BP,ECHILD,0)
  68
  69struct platform_device *bbc_i2c_getdev(struct bbc_i2c_bus *bp, int index)
  70{
  71        struct platform_device *op = NULL;
  72        int curidx = 0, i;
  73
  74        for (i = 0; i < NUM_CHILDREN; i++) {
  75                if (!(op = bp->devs[i].device))
  76                        break;
  77                if (curidx == index)
  78                        goto out;
  79                op = NULL;
  80                curidx++;
  81        }
  82
  83out:
  84        if (curidx == index)
  85                return op;
  86        return NULL;
  87}
  88
  89struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct platform_device *op)
  90{
  91        struct bbc_i2c_client *client;
  92        const u32 *reg;
  93
  94        client = kzalloc(sizeof(*client), GFP_KERNEL);
  95        if (!client)
  96                return NULL;
  97        client->bp = bp;
  98        client->op = op;
  99
 100        reg = of_get_property(op->dev.of_node, "reg", NULL);
 101        if (!reg) {
 102                kfree(client);
 103                return NULL;
 104        }
 105
 106        client->bus = reg[0];
 107        client->address = reg[1];
 108
 109        claim_device(bp, op);
 110
 111        return client;
 112}
 113
 114void bbc_i2c_detach(struct bbc_i2c_client *client)
 115{
 116        struct bbc_i2c_bus *bp = client->bp;
 117        struct platform_device *op = client->op;
 118
 119        release_device(bp, op);
 120        kfree(client);
 121}
 122
 123static int wait_for_pin(struct bbc_i2c_bus *bp, u8 *status)
 124{
 125        DECLARE_WAITQUEUE(wait, current);
 126        int limit = 32;
 127        int ret = 1;
 128
 129        bp->waiting = 1;
 130        add_wait_queue(&bp->wq, &wait);
 131        while (limit-- > 0) {
 132                long val;
 133
 134                val = wait_event_interruptible_timeout(
 135                                bp->wq,
 136                                (((*status = readb(bp->i2c_control_regs + 0))
 137                                  & I2C_PCF_PIN) == 0),
 138                                msecs_to_jiffies(250));
 139                if (val > 0) {
 140                        ret = 0;
 141                        break;
 142                }
 143        }
 144        remove_wait_queue(&bp->wq, &wait);
 145        bp->waiting = 0;
 146
 147        return ret;
 148}
 149
 150int bbc_i2c_writeb(struct bbc_i2c_client *client, unsigned char val, int off)
 151{
 152        struct bbc_i2c_bus *bp = client->bp;
 153        int address = client->address;
 154        u8 status;
 155        int ret = -1;
 156
 157        if (bp->i2c_bussel_reg != NULL)
 158                writeb(client->bus, bp->i2c_bussel_reg);
 159
 160        writeb(address, bp->i2c_control_regs + 0x1);
 161        writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0);
 162        if (wait_for_pin(bp, &status))
 163                goto out;
 164
 165        writeb(off, bp->i2c_control_regs + 0x1);
 166        if (wait_for_pin(bp, &status) ||
 167            (status & I2C_PCF_LRB) != 0)
 168                goto out;
 169
 170        writeb(val, bp->i2c_control_regs + 0x1);
 171        if (wait_for_pin(bp, &status))
 172                goto out;
 173
 174        ret = 0;
 175
 176out:
 177        writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0);
 178        return ret;
 179}
 180
 181int bbc_i2c_readb(struct bbc_i2c_client *client, unsigned char *byte, int off)
 182{
 183        struct bbc_i2c_bus *bp = client->bp;
 184        unsigned char address = client->address, status;
 185        int ret = -1;
 186
 187        if (bp->i2c_bussel_reg != NULL)
 188                writeb(client->bus, bp->i2c_bussel_reg);
 189
 190        writeb(address, bp->i2c_control_regs + 0x1);
 191        writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0);
 192        if (wait_for_pin(bp, &status))
 193                goto out;
 194
 195        writeb(off, bp->i2c_control_regs + 0x1);
 196        if (wait_for_pin(bp, &status) ||
 197            (status & I2C_PCF_LRB) != 0)
 198                goto out;
 199
 200        writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0);
 201
 202        address |= 0x1; /* READ */
 203
 204        writeb(address, bp->i2c_control_regs + 0x1);
 205        writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0);
 206        if (wait_for_pin(bp, &status))
 207                goto out;
 208
 209        /* Set PIN back to one so the device sends the first
 210         * byte.
 211         */
 212        (void) readb(bp->i2c_control_regs + 0x1);
 213        if (wait_for_pin(bp, &status))
 214                goto out;
 215
 216        writeb(I2C_PCF_ESO | I2C_PCF_ENI, bp->i2c_control_regs + 0x0);
 217        *byte = readb(bp->i2c_control_regs + 0x1);
 218        if (wait_for_pin(bp, &status))
 219                goto out;
 220
 221        ret = 0;
 222
 223out:
 224        writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0);
 225        (void) readb(bp->i2c_control_regs + 0x1);
 226
 227        return ret;
 228}
 229
 230int bbc_i2c_write_buf(struct bbc_i2c_client *client,
 231                      char *buf, int len, int off)
 232{
 233        int ret = 0;
 234
 235        while (len > 0) {
 236                ret = bbc_i2c_writeb(client, *buf, off);
 237                if (ret < 0)
 238                        break;
 239                len--;
 240                buf++;
 241                off++;
 242        }
 243        return ret;
 244}
 245
 246int bbc_i2c_read_buf(struct bbc_i2c_client *client,
 247                     char *buf, int len, int off)
 248{
 249        int ret = 0;
 250
 251        while (len > 0) {
 252                ret = bbc_i2c_readb(client, buf, off);
 253                if (ret < 0)
 254                        break;
 255                len--;
 256                buf++;
 257                off++;
 258        }
 259
 260        return ret;
 261}
 262
 263EXPORT_SYMBOL(bbc_i2c_getdev);
 264EXPORT_SYMBOL(bbc_i2c_attach);
 265EXPORT_SYMBOL(bbc_i2c_detach);
 266EXPORT_SYMBOL(bbc_i2c_writeb);
 267EXPORT_SYMBOL(bbc_i2c_readb);
 268EXPORT_SYMBOL(bbc_i2c_write_buf);
 269EXPORT_SYMBOL(bbc_i2c_read_buf);
 270
 271static irqreturn_t bbc_i2c_interrupt(int irq, void *dev_id)
 272{
 273        struct bbc_i2c_bus *bp = dev_id;
 274
 275        /* PIN going from set to clear is the only event which
 276         * makes the i2c assert an interrupt.
 277         */
 278        if (bp->waiting &&
 279            !(readb(bp->i2c_control_regs + 0x0) & I2C_PCF_PIN))
 280                wake_up_interruptible(&bp->wq);
 281
 282        return IRQ_HANDLED;
 283}
 284
 285static void __init reset_one_i2c(struct bbc_i2c_bus *bp)
 286{
 287        writeb(I2C_PCF_PIN, bp->i2c_control_regs + 0x0);
 288        writeb(bp->own, bp->i2c_control_regs + 0x1);
 289        writeb(I2C_PCF_PIN | I2C_PCF_ES1, bp->i2c_control_regs + 0x0);
 290        writeb(bp->clock, bp->i2c_control_regs + 0x1);
 291        writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0);
 292}
 293
 294static struct bbc_i2c_bus * __init attach_one_i2c(struct platform_device *op, int index)
 295{
 296        struct bbc_i2c_bus *bp;
 297        struct device_node *dp;
 298        int entry;
 299
 300        bp = kzalloc(sizeof(*bp), GFP_KERNEL);
 301        if (!bp)
 302                return NULL;
 303
 304        bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs");
 305        if (!bp->i2c_control_regs)
 306                goto fail;
 307
 308        bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel");
 309        if (!bp->i2c_bussel_reg)
 310                goto fail;
 311
 312        bp->waiting = 0;
 313        init_waitqueue_head(&bp->wq);
 314        if (request_irq(op->archdata.irqs[0], bbc_i2c_interrupt,
 315                        IRQF_SHARED, "bbc_i2c", bp))
 316                goto fail;
 317
 318        bp->index = index;
 319        bp->op = op;
 320
 321        spin_lock_init(&bp->lock);
 322
 323        entry = 0;
 324        for (dp = op->dev.of_node->child;
 325             dp && entry < 8;
 326             dp = dp->sibling, entry++) {
 327                struct platform_device *child_op;
 328
 329                child_op = of_find_device_by_node(dp);
 330                bp->devs[entry].device = child_op;
 331                bp->devs[entry].client_claimed = 0;
 332        }
 333
 334        writeb(I2C_PCF_PIN, bp->i2c_control_regs + 0x0);
 335        bp->own = readb(bp->i2c_control_regs + 0x01);
 336        writeb(I2C_PCF_PIN | I2C_PCF_ES1, bp->i2c_control_regs + 0x0);
 337        bp->clock = readb(bp->i2c_control_regs + 0x01);
 338
 339        printk(KERN_INFO "i2c-%d: Regs at %p, %d devices, own %02x, clock %02x.\n",
 340               bp->index, bp->i2c_control_regs, entry, bp->own, bp->clock);
 341
 342        reset_one_i2c(bp);
 343
 344        return bp;
 345
 346fail:
 347        if (bp->i2c_bussel_reg)
 348                of_iounmap(&op->resource[1], bp->i2c_bussel_reg, 1);
 349        if (bp->i2c_control_regs)
 350                of_iounmap(&op->resource[0], bp->i2c_control_regs, 2);
 351        kfree(bp);
 352        return NULL;
 353}
 354
 355extern int bbc_envctrl_init(struct bbc_i2c_bus *bp);
 356extern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp);
 357
 358static int __devinit bbc_i2c_probe(struct platform_device *op)
 359{
 360        struct bbc_i2c_bus *bp;
 361        int err, index = 0;
 362
 363        bp = attach_one_i2c(op, index);
 364        if (!bp)
 365                return -EINVAL;
 366
 367        err = bbc_envctrl_init(bp);
 368        if (err) {
 369                free_irq(op->archdata.irqs[0], bp);
 370                if (bp->i2c_bussel_reg)
 371                        of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1);
 372                if (bp->i2c_control_regs)
 373                        of_iounmap(&op->resource[1], bp->i2c_control_regs, 2);
 374                kfree(bp);
 375        } else {
 376                dev_set_drvdata(&op->dev, bp);
 377        }
 378
 379        return err;
 380}
 381
 382static int __devexit bbc_i2c_remove(struct platform_device *op)
 383{
 384        struct bbc_i2c_bus *bp = dev_get_drvdata(&op->dev);
 385
 386        bbc_envctrl_cleanup(bp);
 387
 388        free_irq(op->archdata.irqs[0], bp);
 389
 390        if (bp->i2c_bussel_reg)
 391                of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1);
 392        if (bp->i2c_control_regs)
 393                of_iounmap(&op->resource[1], bp->i2c_control_regs, 2);
 394
 395        kfree(bp);
 396
 397        return 0;
 398}
 399
 400static const struct of_device_id bbc_i2c_match[] = {
 401        {
 402                .name = "i2c",
 403                .compatible = "SUNW,bbc-i2c",
 404        },
 405        {},
 406};
 407MODULE_DEVICE_TABLE(of, bbc_i2c_match);
 408
 409static struct platform_driver bbc_i2c_driver = {
 410        .driver = {
 411                .name = "bbc_i2c",
 412                .owner = THIS_MODULE,
 413                .of_match_table = bbc_i2c_match,
 414        },
 415        .probe          = bbc_i2c_probe,
 416        .remove         = __devexit_p(bbc_i2c_remove),
 417};
 418
 419module_platform_driver(bbc_i2c_driver);
 420
 421MODULE_LICENSE("GPL");
 422
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.