/*
* arch/powerpc/platforms/powermac/low_i2c.c
*
* Copyright (C) 2003-2005 Ben. Herrenschmidt (benh@kernel.crashing.org)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* The linux i2c layer isn't completely suitable for our needs for various
* reasons ranging from too late initialisation to semantics not perfectly
* matching some requirements of the apple platform functions etc...
*
* This file thus provides a simple low level unified i2c interface for
* powermac that covers the various types of i2c busses used in Apple machines.
* For now, keywest, PMU and SMU, though we could add Cuda, or other bit
* banging busses found on older chipstes in earlier machines if we ever need
* one of them.
*
* The drivers in this file are synchronous/blocking. In addition, the
* keywest one is fairly slow due to the use of msleep instead of interrupts
* as the interrupt is currently used by i2c-keywest. In the long run, we
* might want to get rid of those high-level interfaces to linux i2c layer
* either completely (converting all drivers) or replacing them all with a
* single stub driver on top of this one. Once done, the interrupt will be
* available for our use.
*/
#undef DEBUG
#undef DEBUG_LOW
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/export.h>
#include <linux/adb.h>
#include <linux/pmu.h>
#include <linux/delay.h>
#include <linux/completion.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/mutex.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <asm/keylargo.h>
#include <asm/uninorth.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/smu.h>
#include <asm/pmac_pfunc.h>
#include <asm/pmac_low_i2c.h>
#ifdef DEBUG
#define DBG(x...) do {\
printk(KERN_DEBUG "low_i2c:" x); \
} while(0)
#else
#define DBG(x...)
#endif
#ifdef DEBUG_LOW
#define DBG_LOW(x...) do {\
printk(KERN_DEBUG "low_i2c:" x); \
} while(0)
#else
#define DBG_LOW(x...)
#endif
static int pmac_i2c_force_poll = 1;
/*
* A bus structure. Each bus in the system has such a structure associated.
*/
struct pmac_i2c_bus
{
struct list_head link;
struct device_node *controller;
struct device_node *busnode;
int type;
int flags;
struct i2c_adapter adapter;
void *hostdata;
int channel; /* some hosts have multiple */
int mode; /* current mode */
struct mutex mutex;
int opened;
int polled; /* open mode */
struct platform_device *platform_dev;
/* ops */
int (*open)(struct pmac_i2c_bus *bus);
void (*close)(struct pmac_i2c_bus *bus);
int (*xfer)(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
u32 subaddr, u8 *data, int len);
};
static LIST_HEAD(pmac_i2c_busses);
/*
* Keywest implementation
*/
struct pmac_i2c_host_kw
{
struct mutex mutex; /* Access mutex for use by
* i2c-keywest */
void __iomem *base; /* register base address */
int bsteps; /* register step
|