linux-bk/arch/ppc/platforms/pmac_low_i2c.c
<<
>>
Prefs
   1/*
   2 *  arch/ppc/platforms/pmac_low_i2c.c
   3 *
   4 *  Copyright (C) 2003 Ben. Herrenschmidt (benh@kernel.crashing.org)
   5 *
   6 *  This program is free software; you can redistribute it and/or
   7 *  modify it under the terms of the GNU General Public License
   8 *  as published by the Free Software Foundation; either version
   9 *  2 of the License, or (at your option) any later version.
  10 *
  11 *  This file contains some low-level i2c access routines that
  12 *  need to be used by various bits of the PowerMac platform code
  13 *  at times where the real asynchronous & interrupt driven driver
  14 *  cannot be used. The API borrows some semantics from the darwin
  15 *  driver in order to ease the implementation of the platform
  16 *  properties parser
  17 */
  18
  19#include <linux/config.h>
  20#include <linux/types.h>
  21#include <linux/delay.h>
  22#include <linux/sched.h>
  23#include <linux/init.h>
  24#include <linux/module.h>
  25#include <linux/adb.h>
  26#include <linux/pmu.h>
  27#include <asm/keylargo.h>
  28#include <asm/uninorth.h>
  29#include <asm/io.h>
  30#include <asm/prom.h>
  31#include <asm/machdep.h>
  32#include <asm/pmac_low_i2c.h>
  33
  34#define MAX_LOW_I2C_HOST        4
  35
  36#if 1
  37#define DBG(x...) do {\
  38                printk(KERN_DEBUG "KW:" x);     \
  39        } while(0)
  40#else
  41#define DBGG(x...)
  42#endif
  43
  44struct low_i2c_host;
  45
  46typedef int (*low_i2c_func_t)(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len);
  47
  48struct low_i2c_host
  49{
  50        struct device_node      *np;            /* OF device node */
  51        struct semaphore        mutex;          /* Access mutex for use by i2c-keywest */
  52        low_i2c_func_t          func;           /* Access function */
  53        int                     is_open : 1;    /* Poor man's access control */
  54        int                     mode;           /* Current mode */
  55        int                     channel;        /* Current channel */
  56        int                     num_channels;   /* Number of channels */
  57        unsigned long           base;           /* For keywest-i2c, base address */
  58        int                     bsteps;         /* And register stepping */
  59        int                     speed;          /* And speed */
  60};
  61
  62static struct low_i2c_host      low_i2c_hosts[MAX_LOW_I2C_HOST];
  63
  64/* No locking is necessary on allocation, we are running way before
  65 * anything can race with us
  66 */
  67static struct low_i2c_host *find_low_i2c_host(struct device_node *np)
  68{
  69        int i;
  70
  71        for (i = 0; i < MAX_LOW_I2C_HOST; i++)
  72                if (low_i2c_hosts[i].np == np)
  73                        return &low_i2c_hosts[i];
  74        return NULL;
  75}
  76
  77/*
  78 *
  79 * i2c-keywest implementation (UniNorth, U2, U3, Keylargo's)
  80 *
  81 */
  82
  83/*
  84 * Keywest i2c definitions borrowed from drivers/i2c/i2c-keywest.h,
  85 * should be moved somewhere in include/asm-ppc/
  86 */
  87/* Register indices */
  88typedef enum {
  89        reg_mode = 0,
  90        reg_control,
  91        reg_status,
  92        reg_isr,
  93        reg_ier,
  94        reg_addr,
  95        reg_subaddr,
  96        reg_data
  97} reg_t;
  98
  99
 100/* Mode register */
 101#define KW_I2C_MODE_100KHZ      0x00
 102#define KW_I2C_MODE_50KHZ       0x01
 103#define KW_I2C_MODE_25KHZ       0x02
 104#define KW_I2C_MODE_DUMB        0x00
 105#define KW_I2C_MODE_STANDARD    0x04
 106#define KW_I2C_MODE_STANDARDSUB 0x08
 107#define KW_I2C_MODE_COMBINED    0x0C
 108#define KW_I2C_MODE_MODE_MASK   0x0C
 109#define KW_I2C_MODE_CHAN_MASK   0xF0
 110
 111/* Control register */
 112#define KW_I2C_CTL_AAK          0x01
 113#define KW_I2C_CTL_XADDR        0x02
 114#define KW_I2C_CTL_STOP         0x04
 115#define KW_I2C_CTL_START        0x08
 116
 117/* Status register */
 118#define KW_I2C_STAT_BUSY        0x01
 119#define KW_I2C_STAT_LAST_AAK    0x02
 120#define KW_I2C_STAT_LAST_RW     0x04
 121#define KW_I2C_STAT_SDA         0x08
 122#define KW_I2C_STAT_SCL         0x10
 123
 124/* IER & ISR registers */
 125#define KW_I2C_IRQ_DATA         0x01
 126#define KW_I2C_IRQ_ADDR         0x02
 127#define KW_I2C_IRQ_STOP         0x04
 128#define KW_I2C_IRQ_START        0x08
 129#define KW_I2C_IRQ_MASK         0x0F
 130
 131/* State machine states */
 132enum {
 133        state_idle,
 134        state_addr,
 135        state_read,
 136        state_write,
 137        state_stop,
 138        state_dead
 139};
 140
 141#define WRONG_STATE(name) do {\
 142                printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \
 143                       name, __kw_state_names[state], isr); \
 144        } while(0)
 145
 146static const char *__kw_state_names[] = {
 147        "state_idle",
 148        "state_addr",
 149        "state_read",
 150        "state_write",
 151        "state_stop",
 152        "state_dead"
 153};
 154
 155static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg)
 156{
 157        return in_8(((volatile u8 *)host->base)
 158                + (((unsigned)reg) << host->bsteps));
 159}
 160
 161static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val)
 162{
 163        out_8(((volatile u8 *)host->base)
 164                + (((unsigned)reg) << host->bsteps), val);
 165        (void)__kw_read_reg(host, reg_subaddr);
 166}
 167
 168#define kw_write_reg(reg, val)  __kw_write_reg(host, reg, val) 
 169#define kw_read_reg(reg)        __kw_read_reg(host, reg) 
 170
 171
 172/* Don't schedule, the g5 fan controller is too
 173 * timing sensitive
 174 */
 175static u8 kw_wait_interrupt(struct low_i2c_host* host)
 176{
 177        int i;
 178        u8 isr;
 179        
 180        for (i = 0; i < 200000; i++) {
 181                isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK;
 182                if (isr != 0)
 183                        return isr;
 184                udelay(1);
 185        }
 186        return isr;
 187}
 188
 189static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr)
 190{
 191        u8 ack;
 192
 193        if (isr == 0) {
 194                if (state != state_stop) {
 195                        DBG("KW: Timeout !\n");
 196                        *rc = -EIO;
 197                        goto stop;
 198                }
 199                if (state == state_stop) {
 200                        ack = kw_read_reg(reg_status);
 201                        if (!(ack & KW_I2C_STAT_BUSY)) {
 202                                state = state_idle;
 203                                kw_write_reg(reg_ier, 0x00);
 204                        }
 205                }
 206                return state;
 207        }
 208
 209        if (isr & KW_I2C_IRQ_ADDR) {
 210                ack = kw_read_reg(reg_status);
 211                if (state != state_addr) {
 212                        kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
 213                        WRONG_STATE("KW_I2C_IRQ_ADDR"); 
 214                        *rc = -EIO;
 215                        goto stop;
 216                }
 217                if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {                        
 218                        *rc = -ENODEV;
 219                        DBG("KW: NAK on address\n");
 220                        return state_stop;                   
 221                } else {
 222                        if (rw) {
 223                                state = state_read;
 224                                if (*len > 1)
 225                                        kw_write_reg(reg_control, KW_I2C_CTL_AAK);
 226                        } else {
 227                                state = state_write;
 228                                kw_write_reg(reg_data, **data);
 229                                (*data)++; (*len)--;
 230                        }
 231                }
 232                kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
 233        }
 234
 235        if (isr & KW_I2C_IRQ_DATA) {
 236                if (state == state_read) {
 237                        **data = kw_read_reg(reg_data);
 238                        (*data)++; (*len)--;
 239                        kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
 240                        if ((*len) == 0)
 241                                state = state_stop;
 242                        else if ((*len) == 1)
 243                                kw_write_reg(reg_control, 0);
 244                } else if (state == state_write) {
 245                        ack = kw_read_reg(reg_status);
 246                        if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
 247                                DBG("KW: nack on data write\n");
 248                                *rc = -EIO;
 249                                goto stop;
 250                        } else if (*len) {
 251                                kw_write_reg(reg_data, **data);
 252                                (*data)++; (*len)--;
 253                        } else {
 254                                kw_write_reg(reg_control, KW_I2C_CTL_STOP);
 255                                state = state_stop;
 256                                *rc = 0;
 257                        }
 258                        kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
 259                } else {
 260                        kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
 261                        WRONG_STATE("KW_I2C_IRQ_DATA"); 
 262                        if (state != state_stop) {
 263                                *rc = -EIO;
 264                                goto stop;
 265                        }
 266                }
 267        }
 268
 269        if (isr & KW_I2C_IRQ_STOP) {
 270                kw_write_reg(reg_isr, KW_I2C_IRQ_STOP);
 271                if (state != state_stop) {
 272                        WRONG_STATE("KW_I2C_IRQ_STOP");
 273                        *rc = -EIO;
 274                }
 275                return state_idle;
 276        }
 277
 278        if (isr & KW_I2C_IRQ_START)
 279                kw_write_reg(reg_isr, KW_I2C_IRQ_START);
 280
 281        return state;
 282
 283 stop:
 284        kw_write_reg(reg_control, KW_I2C_CTL_STOP);     
 285        return state_stop;
 286}
 287
 288static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, u8 *data, int len)
 289{
 290        u8 mode_reg = host->speed;
 291        int state = state_addr;
 292        int rc = 0;
 293
 294        /* Setup mode & subaddress if any */
 295        switch(host->mode) {
 296        case pmac_low_i2c_mode_dumb:
 297                printk(KERN_ERR "low_i2c: Dumb mode not supported !\n");
 298                return -EINVAL;
 299        case pmac_low_i2c_mode_std:
 300                mode_reg |= KW_I2C_MODE_STANDARD;
 301                break;
 302        case pmac_low_i2c_mode_stdsub:
 303                mode_reg |= KW_I2C_MODE_STANDARDSUB;
 304                kw_write_reg(reg_subaddr, subaddr);
 305                break;
 306        case pmac_low_i2c_mode_combined:
 307                mode_reg |= KW_I2C_MODE_COMBINED;
 308                kw_write_reg(reg_subaddr, subaddr);
 309                break;
 310        }
 311
 312        /* Setup channel & clear pending irqs */
 313        kw_write_reg(reg_isr, kw_read_reg(reg_isr));
 314        kw_write_reg(reg_mode, mode_reg | (host->channel << 4));
 315        kw_write_reg(reg_status, 0);
 316
 317        /* Set up address and r/w bit */
 318        kw_write_reg(reg_addr, addr);
 319
 320        /* Start sending address & disable interrupt*/
 321        kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/);
 322        kw_write_reg(reg_control, KW_I2C_CTL_XADDR);
 323
 324        /* State machine, to turn into an interrupt handler */
 325        while(state != state_idle) {
 326                u8 isr = kw_wait_interrupt(host);
 327                state = kw_handle_interrupt(host, state, addr & 1, &rc, &data, &len, isr);
 328        }
 329
 330        return rc;
 331}
 332
 333static void keywest_low_i2c_add(struct device_node *np)
 334{
 335        struct low_i2c_host     *host = find_low_i2c_host(NULL);
 336        unsigned long           *psteps, *prate, steps, aoffset = 0;
 337        struct device_node      *parent;
 338
 339        if (host == NULL) {
 340                printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
 341                       np->full_name);
 342                return;
 343        }
 344        memset(host, 0, sizeof(*host));
 345
 346        init_MUTEX(&host->mutex);
 347        host->np = of_node_get(np);     
 348        psteps = (unsigned long *)get_property(np, "AAPL,address-step", NULL);
 349        steps = psteps ? (*psteps) : 0x10;
 350        for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
 351                steps >>= 1;
 352        parent = of_get_parent(np);
 353        host->num_channels = 1;
 354        if (parent && parent->name[0] == 'u') {
 355                host->num_channels = 2;
 356                aoffset = 3;
 357        }
 358        /* Select interface rate */
 359        host->speed = KW_I2C_MODE_100KHZ;
 360        prate = (unsigned long *)get_property(np, "AAPL,i2c-rate", NULL);
 361        if (prate) switch(*prate) {
 362        case 100:
 363                host->speed = KW_I2C_MODE_100KHZ;
 364                break;
 365        case 50:
 366                host->speed = KW_I2C_MODE_50KHZ;
 367                break;
 368        case 25:
 369                host->speed = KW_I2C_MODE_25KHZ;
 370                break;
 371        }       
 372        host->mode = pmac_low_i2c_mode_std;
 373        host->base = (unsigned long)ioremap(np->addrs[0].address + aoffset,
 374                                                np->addrs[0].size);
 375        host->func = keywest_low_i2c_func;
 376}
 377
 378/*
 379 *
 380 * PMU implementation
 381 *
 382 */
 383
 384
 385#ifdef CONFIG_ADB_PMU
 386
 387static int pmu_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len)
 388{
 389        // TODO
 390        return -ENODEV;
 391}
 392
 393static void pmu_low_i2c_add(struct device_node *np)
 394{
 395        struct low_i2c_host     *host = find_low_i2c_host(NULL);
 396
 397        if (host == NULL) {
 398                printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
 399                       np->full_name);
 400                return;
 401        }
 402        memset(host, 0, sizeof(*host));
 403
 404        init_MUTEX(&host->mutex);
 405        host->np = of_node_get(np);     
 406        host->num_channels = 3;
 407        host->mode = pmac_low_i2c_mode_std;
 408        host->func = pmu_low_i2c_func;
 409}
 410
 411#endif /* CONFIG_ADB_PMU */
 412
 413void __init pmac_init_low_i2c(void)
 414{
 415        struct device_node *np;
 416
 417        /* Probe keywest-i2c busses */
 418        np = of_find_compatible_node(NULL, "i2c", "keywest-i2c");
 419        while(np) {
 420                keywest_low_i2c_add(np);
 421                np = of_find_compatible_node(np, "i2c", "keywest-i2c");
 422        }
 423
 424#ifdef CONFIG_ADB_PMU
 425        /* Probe PMU busses */
 426        np = of_find_node_by_name(NULL, "via-pmu");
 427        if (np)
 428                pmu_low_i2c_add(np);
 429#endif /* CONFIG_ADB_PMU */
 430
 431        /* TODO: Add CUDA support as well */
 432}
 433
 434int pmac_low_i2c_lock(struct device_node *np)
 435{
 436        struct low_i2c_host *host = find_low_i2c_host(np);
 437
 438        if (!host)
 439                return -ENODEV;
 440        down(&host->mutex);
 441        return 0;
 442}
 443EXPORT_SYMBOL(pmac_low_i2c_lock);
 444
 445int pmac_low_i2c_unlock(struct device_node *np)
 446{
 447        struct low_i2c_host *host = find_low_i2c_host(np);
 448
 449        if (!host)
 450                return -ENODEV;
 451        up(&host->mutex);
 452        return 0;
 453}
 454EXPORT_SYMBOL(pmac_low_i2c_unlock);
 455
 456
 457int pmac_low_i2c_open(struct device_node *np, int channel)
 458{
 459        struct low_i2c_host *host = find_low_i2c_host(np);
 460
 461        if (!host)
 462                return -ENODEV;
 463
 464        if (channel >= host->num_channels)
 465                return -EINVAL;
 466
 467        down(&host->mutex);
 468        host->is_open = 1;
 469        host->channel = channel;
 470
 471        return 0;
 472}
 473EXPORT_SYMBOL(pmac_low_i2c_open);
 474
 475int pmac_low_i2c_close(struct device_node *np)
 476{
 477        struct low_i2c_host *host = find_low_i2c_host(np);
 478
 479        if (!host)
 480                return -ENODEV;
 481
 482        host->is_open = 0;
 483        up(&host->mutex);
 484
 485        return 0;
 486}
 487EXPORT_SYMBOL(pmac_low_i2c_close);
 488
 489int pmac_low_i2c_setmode(struct device_node *np, int mode)
 490{
 491        struct low_i2c_host *host = find_low_i2c_host(np);
 492
 493        if (!host)
 494                return -ENODEV;
 495        WARN_ON(!host->is_open);
 496        host->mode = mode;
 497
 498        return 0;
 499}
 500EXPORT_SYMBOL(pmac_low_i2c_setmode);
 501
 502int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len)
 503{
 504        struct low_i2c_host *host = find_low_i2c_host(np);
 505
 506        if (!host)
 507                return -ENODEV;
 508        WARN_ON(!host->is_open);
 509
 510        return host->func(host, addrdir, subaddr, data, len);
 511}
 512EXPORT_SYMBOL(pmac_low_i2c_xfer);
 513
 514
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.