162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * arch/powerpc/platforms/powermac/low_i2c.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2003-2005 Ben. Herrenschmidt (benh@kernel.crashing.org) 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * The linux i2c layer isn't completely suitable for our needs for various 862306a36Sopenharmony_ci * reasons ranging from too late initialisation to semantics not perfectly 962306a36Sopenharmony_ci * matching some requirements of the apple platform functions etc... 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * This file thus provides a simple low level unified i2c interface for 1262306a36Sopenharmony_ci * powermac that covers the various types of i2c busses used in Apple machines. 1362306a36Sopenharmony_ci * For now, keywest, PMU and SMU, though we could add Cuda, or other bit 1462306a36Sopenharmony_ci * banging busses found on older chipsets in earlier machines if we ever need 1562306a36Sopenharmony_ci * one of them. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * The drivers in this file are synchronous/blocking. In addition, the 1862306a36Sopenharmony_ci * keywest one is fairly slow due to the use of msleep instead of interrupts 1962306a36Sopenharmony_ci * as the interrupt is currently used by i2c-keywest. In the long run, we 2062306a36Sopenharmony_ci * might want to get rid of those high-level interfaces to linux i2c layer 2162306a36Sopenharmony_ci * either completely (converting all drivers) or replacing them all with a 2262306a36Sopenharmony_ci * single stub driver on top of this one. Once done, the interrupt will be 2362306a36Sopenharmony_ci * available for our use. 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#undef DEBUG 2762306a36Sopenharmony_ci#undef DEBUG_LOW 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <linux/types.h> 3062306a36Sopenharmony_ci#include <linux/sched.h> 3162306a36Sopenharmony_ci#include <linux/init.h> 3262306a36Sopenharmony_ci#include <linux/export.h> 3362306a36Sopenharmony_ci#include <linux/adb.h> 3462306a36Sopenharmony_ci#include <linux/pmu.h> 3562306a36Sopenharmony_ci#include <linux/delay.h> 3662306a36Sopenharmony_ci#include <linux/completion.h> 3762306a36Sopenharmony_ci#include <linux/platform_device.h> 3862306a36Sopenharmony_ci#include <linux/interrupt.h> 3962306a36Sopenharmony_ci#include <linux/timer.h> 4062306a36Sopenharmony_ci#include <linux/mutex.h> 4162306a36Sopenharmony_ci#include <linux/i2c.h> 4262306a36Sopenharmony_ci#include <linux/slab.h> 4362306a36Sopenharmony_ci#include <linux/of_irq.h> 4462306a36Sopenharmony_ci#include <asm/keylargo.h> 4562306a36Sopenharmony_ci#include <asm/uninorth.h> 4662306a36Sopenharmony_ci#include <asm/io.h> 4762306a36Sopenharmony_ci#include <asm/machdep.h> 4862306a36Sopenharmony_ci#include <asm/smu.h> 4962306a36Sopenharmony_ci#include <asm/pmac_pfunc.h> 5062306a36Sopenharmony_ci#include <asm/pmac_low_i2c.h> 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#ifdef DEBUG 5362306a36Sopenharmony_ci#define DBG(x...) do {\ 5462306a36Sopenharmony_ci printk(KERN_DEBUG "low_i2c:" x); \ 5562306a36Sopenharmony_ci } while(0) 5662306a36Sopenharmony_ci#else 5762306a36Sopenharmony_ci#define DBG(x...) 5862306a36Sopenharmony_ci#endif 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#ifdef DEBUG_LOW 6162306a36Sopenharmony_ci#define DBG_LOW(x...) do {\ 6262306a36Sopenharmony_ci printk(KERN_DEBUG "low_i2c:" x); \ 6362306a36Sopenharmony_ci } while(0) 6462306a36Sopenharmony_ci#else 6562306a36Sopenharmony_ci#define DBG_LOW(x...) 6662306a36Sopenharmony_ci#endif 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic int pmac_i2c_force_poll = 1; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* 7262306a36Sopenharmony_ci * A bus structure. Each bus in the system has such a structure associated. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_cistruct pmac_i2c_bus 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct list_head link; 7762306a36Sopenharmony_ci struct device_node *controller; 7862306a36Sopenharmony_ci struct device_node *busnode; 7962306a36Sopenharmony_ci int type; 8062306a36Sopenharmony_ci int flags; 8162306a36Sopenharmony_ci struct i2c_adapter adapter; 8262306a36Sopenharmony_ci void *hostdata; 8362306a36Sopenharmony_ci int channel; /* some hosts have multiple */ 8462306a36Sopenharmony_ci int mode; /* current mode */ 8562306a36Sopenharmony_ci struct mutex mutex; 8662306a36Sopenharmony_ci int opened; 8762306a36Sopenharmony_ci int polled; /* open mode */ 8862306a36Sopenharmony_ci struct platform_device *platform_dev; 8962306a36Sopenharmony_ci struct lock_class_key lock_key; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* ops */ 9262306a36Sopenharmony_ci int (*open)(struct pmac_i2c_bus *bus); 9362306a36Sopenharmony_ci void (*close)(struct pmac_i2c_bus *bus); 9462306a36Sopenharmony_ci int (*xfer)(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, 9562306a36Sopenharmony_ci u32 subaddr, u8 *data, int len); 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic LIST_HEAD(pmac_i2c_busses); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* 10162306a36Sopenharmony_ci * Keywest implementation 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistruct pmac_i2c_host_kw 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct mutex mutex; /* Access mutex for use by 10762306a36Sopenharmony_ci * i2c-keywest */ 10862306a36Sopenharmony_ci void __iomem *base; /* register base address */ 10962306a36Sopenharmony_ci int bsteps; /* register stepping */ 11062306a36Sopenharmony_ci int speed; /* speed */ 11162306a36Sopenharmony_ci int irq; 11262306a36Sopenharmony_ci u8 *data; 11362306a36Sopenharmony_ci unsigned len; 11462306a36Sopenharmony_ci int state; 11562306a36Sopenharmony_ci int rw; 11662306a36Sopenharmony_ci int polled; 11762306a36Sopenharmony_ci int result; 11862306a36Sopenharmony_ci struct completion complete; 11962306a36Sopenharmony_ci spinlock_t lock; 12062306a36Sopenharmony_ci struct timer_list timeout_timer; 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* Register indices */ 12462306a36Sopenharmony_citypedef enum { 12562306a36Sopenharmony_ci reg_mode = 0, 12662306a36Sopenharmony_ci reg_control, 12762306a36Sopenharmony_ci reg_status, 12862306a36Sopenharmony_ci reg_isr, 12962306a36Sopenharmony_ci reg_ier, 13062306a36Sopenharmony_ci reg_addr, 13162306a36Sopenharmony_ci reg_subaddr, 13262306a36Sopenharmony_ci reg_data 13362306a36Sopenharmony_ci} reg_t; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/* The Tumbler audio equalizer can be really slow sometimes */ 13662306a36Sopenharmony_ci#define KW_POLL_TIMEOUT (2*HZ) 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/* Mode register */ 13962306a36Sopenharmony_ci#define KW_I2C_MODE_100KHZ 0x00 14062306a36Sopenharmony_ci#define KW_I2C_MODE_50KHZ 0x01 14162306a36Sopenharmony_ci#define KW_I2C_MODE_25KHZ 0x02 14262306a36Sopenharmony_ci#define KW_I2C_MODE_DUMB 0x00 14362306a36Sopenharmony_ci#define KW_I2C_MODE_STANDARD 0x04 14462306a36Sopenharmony_ci#define KW_I2C_MODE_STANDARDSUB 0x08 14562306a36Sopenharmony_ci#define KW_I2C_MODE_COMBINED 0x0C 14662306a36Sopenharmony_ci#define KW_I2C_MODE_MODE_MASK 0x0C 14762306a36Sopenharmony_ci#define KW_I2C_MODE_CHAN_MASK 0xF0 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/* Control register */ 15062306a36Sopenharmony_ci#define KW_I2C_CTL_AAK 0x01 15162306a36Sopenharmony_ci#define KW_I2C_CTL_XADDR 0x02 15262306a36Sopenharmony_ci#define KW_I2C_CTL_STOP 0x04 15362306a36Sopenharmony_ci#define KW_I2C_CTL_START 0x08 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* Status register */ 15662306a36Sopenharmony_ci#define KW_I2C_STAT_BUSY 0x01 15762306a36Sopenharmony_ci#define KW_I2C_STAT_LAST_AAK 0x02 15862306a36Sopenharmony_ci#define KW_I2C_STAT_LAST_RW 0x04 15962306a36Sopenharmony_ci#define KW_I2C_STAT_SDA 0x08 16062306a36Sopenharmony_ci#define KW_I2C_STAT_SCL 0x10 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/* IER & ISR registers */ 16362306a36Sopenharmony_ci#define KW_I2C_IRQ_DATA 0x01 16462306a36Sopenharmony_ci#define KW_I2C_IRQ_ADDR 0x02 16562306a36Sopenharmony_ci#define KW_I2C_IRQ_STOP 0x04 16662306a36Sopenharmony_ci#define KW_I2C_IRQ_START 0x08 16762306a36Sopenharmony_ci#define KW_I2C_IRQ_MASK 0x0F 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/* State machine states */ 17062306a36Sopenharmony_cienum { 17162306a36Sopenharmony_ci state_idle, 17262306a36Sopenharmony_ci state_addr, 17362306a36Sopenharmony_ci state_read, 17462306a36Sopenharmony_ci state_write, 17562306a36Sopenharmony_ci state_stop, 17662306a36Sopenharmony_ci state_dead 17762306a36Sopenharmony_ci}; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci#define WRONG_STATE(name) do {\ 18062306a36Sopenharmony_ci printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s " \ 18162306a36Sopenharmony_ci "(isr: %02x)\n", \ 18262306a36Sopenharmony_ci name, __kw_state_names[host->state], isr); \ 18362306a36Sopenharmony_ci } while(0) 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic const char *__kw_state_names[] = { 18662306a36Sopenharmony_ci "state_idle", 18762306a36Sopenharmony_ci "state_addr", 18862306a36Sopenharmony_ci "state_read", 18962306a36Sopenharmony_ci "state_write", 19062306a36Sopenharmony_ci "state_stop", 19162306a36Sopenharmony_ci "state_dead" 19262306a36Sopenharmony_ci}; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic inline u8 __kw_read_reg(struct pmac_i2c_host_kw *host, reg_t reg) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci return readb(host->base + (((unsigned int)reg) << host->bsteps)); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic inline void __kw_write_reg(struct pmac_i2c_host_kw *host, 20062306a36Sopenharmony_ci reg_t reg, u8 val) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci writeb(val, host->base + (((unsigned)reg) << host->bsteps)); 20362306a36Sopenharmony_ci (void)__kw_read_reg(host, reg_subaddr); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val) 20762306a36Sopenharmony_ci#define kw_read_reg(reg) __kw_read_reg(host, reg) 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic u8 kw_i2c_wait_interrupt(struct pmac_i2c_host_kw *host) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci int i, j; 21262306a36Sopenharmony_ci u8 isr; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci for (i = 0; i < 1000; i++) { 21562306a36Sopenharmony_ci isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK; 21662306a36Sopenharmony_ci if (isr != 0) 21762306a36Sopenharmony_ci return isr; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* This code is used with the timebase frozen, we cannot rely 22062306a36Sopenharmony_ci * on udelay nor schedule when in polled mode ! 22162306a36Sopenharmony_ci * For now, just use a bogus loop.... 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_ci if (host->polled) { 22462306a36Sopenharmony_ci for (j = 1; j < 100000; j++) 22562306a36Sopenharmony_ci mb(); 22662306a36Sopenharmony_ci } else 22762306a36Sopenharmony_ci msleep(1); 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci return isr; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic void kw_i2c_do_stop(struct pmac_i2c_host_kw *host, int result) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci kw_write_reg(reg_control, KW_I2C_CTL_STOP); 23562306a36Sopenharmony_ci host->state = state_stop; 23662306a36Sopenharmony_ci host->result = result; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci u8 ack; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci DBG_LOW("kw_handle_interrupt(%s, isr: %x)\n", 24562306a36Sopenharmony_ci __kw_state_names[host->state], isr); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (host->state == state_idle) { 24862306a36Sopenharmony_ci printk(KERN_WARNING "low_i2c: Keywest got an out of state" 24962306a36Sopenharmony_ci " interrupt, ignoring\n"); 25062306a36Sopenharmony_ci kw_write_reg(reg_isr, isr); 25162306a36Sopenharmony_ci return; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (isr == 0) { 25562306a36Sopenharmony_ci printk(KERN_WARNING "low_i2c: Timeout in i2c transfer" 25662306a36Sopenharmony_ci " on keywest !\n"); 25762306a36Sopenharmony_ci if (host->state != state_stop) { 25862306a36Sopenharmony_ci kw_i2c_do_stop(host, -EIO); 25962306a36Sopenharmony_ci return; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci ack = kw_read_reg(reg_status); 26262306a36Sopenharmony_ci if (ack & KW_I2C_STAT_BUSY) 26362306a36Sopenharmony_ci kw_write_reg(reg_status, 0); 26462306a36Sopenharmony_ci host->state = state_idle; 26562306a36Sopenharmony_ci kw_write_reg(reg_ier, 0x00); 26662306a36Sopenharmony_ci if (!host->polled) 26762306a36Sopenharmony_ci complete(&host->complete); 26862306a36Sopenharmony_ci return; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (isr & KW_I2C_IRQ_ADDR) { 27262306a36Sopenharmony_ci ack = kw_read_reg(reg_status); 27362306a36Sopenharmony_ci if (host->state != state_addr) { 27462306a36Sopenharmony_ci WRONG_STATE("KW_I2C_IRQ_ADDR"); 27562306a36Sopenharmony_ci kw_i2c_do_stop(host, -EIO); 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { 27862306a36Sopenharmony_ci host->result = -ENXIO; 27962306a36Sopenharmony_ci host->state = state_stop; 28062306a36Sopenharmony_ci DBG_LOW("KW: NAK on address\n"); 28162306a36Sopenharmony_ci } else { 28262306a36Sopenharmony_ci if (host->len == 0) 28362306a36Sopenharmony_ci kw_i2c_do_stop(host, 0); 28462306a36Sopenharmony_ci else if (host->rw) { 28562306a36Sopenharmony_ci host->state = state_read; 28662306a36Sopenharmony_ci if (host->len > 1) 28762306a36Sopenharmony_ci kw_write_reg(reg_control, 28862306a36Sopenharmony_ci KW_I2C_CTL_AAK); 28962306a36Sopenharmony_ci } else { 29062306a36Sopenharmony_ci host->state = state_write; 29162306a36Sopenharmony_ci kw_write_reg(reg_data, *(host->data++)); 29262306a36Sopenharmony_ci host->len--; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (isr & KW_I2C_IRQ_DATA) { 29962306a36Sopenharmony_ci if (host->state == state_read) { 30062306a36Sopenharmony_ci *(host->data++) = kw_read_reg(reg_data); 30162306a36Sopenharmony_ci host->len--; 30262306a36Sopenharmony_ci kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); 30362306a36Sopenharmony_ci if (host->len == 0) 30462306a36Sopenharmony_ci host->state = state_stop; 30562306a36Sopenharmony_ci else if (host->len == 1) 30662306a36Sopenharmony_ci kw_write_reg(reg_control, 0); 30762306a36Sopenharmony_ci } else if (host->state == state_write) { 30862306a36Sopenharmony_ci ack = kw_read_reg(reg_status); 30962306a36Sopenharmony_ci if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { 31062306a36Sopenharmony_ci DBG_LOW("KW: nack on data write\n"); 31162306a36Sopenharmony_ci host->result = -EFBIG; 31262306a36Sopenharmony_ci host->state = state_stop; 31362306a36Sopenharmony_ci } else if (host->len) { 31462306a36Sopenharmony_ci kw_write_reg(reg_data, *(host->data++)); 31562306a36Sopenharmony_ci host->len--; 31662306a36Sopenharmony_ci } else 31762306a36Sopenharmony_ci kw_i2c_do_stop(host, 0); 31862306a36Sopenharmony_ci } else { 31962306a36Sopenharmony_ci WRONG_STATE("KW_I2C_IRQ_DATA"); 32062306a36Sopenharmony_ci if (host->state != state_stop) 32162306a36Sopenharmony_ci kw_i2c_do_stop(host, -EIO); 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (isr & KW_I2C_IRQ_STOP) { 32762306a36Sopenharmony_ci kw_write_reg(reg_isr, KW_I2C_IRQ_STOP); 32862306a36Sopenharmony_ci if (host->state != state_stop) { 32962306a36Sopenharmony_ci WRONG_STATE("KW_I2C_IRQ_STOP"); 33062306a36Sopenharmony_ci host->result = -EIO; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci host->state = state_idle; 33362306a36Sopenharmony_ci if (!host->polled) 33462306a36Sopenharmony_ci complete(&host->complete); 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* Below should only happen in manual mode which we don't use ... */ 33862306a36Sopenharmony_ci if (isr & KW_I2C_IRQ_START) 33962306a36Sopenharmony_ci kw_write_reg(reg_isr, KW_I2C_IRQ_START); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci/* Interrupt handler */ 34462306a36Sopenharmony_cistatic irqreturn_t kw_i2c_irq(int irq, void *dev_id) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct pmac_i2c_host_kw *host = dev_id; 34762306a36Sopenharmony_ci unsigned long flags; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 35062306a36Sopenharmony_ci del_timer(&host->timeout_timer); 35162306a36Sopenharmony_ci kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr)); 35262306a36Sopenharmony_ci if (host->state != state_idle) { 35362306a36Sopenharmony_ci host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT; 35462306a36Sopenharmony_ci add_timer(&host->timeout_timer); 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 35762306a36Sopenharmony_ci return IRQ_HANDLED; 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic void kw_i2c_timeout(struct timer_list *t) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci struct pmac_i2c_host_kw *host = from_timer(host, t, timeout_timer); 36362306a36Sopenharmony_ci unsigned long flags; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* 36862306a36Sopenharmony_ci * If the timer is pending, that means we raced with the 36962306a36Sopenharmony_ci * irq, in which case we just return 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_ci if (timer_pending(&host->timeout_timer)) 37262306a36Sopenharmony_ci goto skip; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci kw_i2c_handle_interrupt(host, kw_read_reg(reg_isr)); 37562306a36Sopenharmony_ci if (host->state != state_idle) { 37662306a36Sopenharmony_ci host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT; 37762306a36Sopenharmony_ci add_timer(&host->timeout_timer); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci skip: 38062306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic int kw_i2c_open(struct pmac_i2c_bus *bus) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct pmac_i2c_host_kw *host = bus->hostdata; 38662306a36Sopenharmony_ci mutex_lock(&host->mutex); 38762306a36Sopenharmony_ci return 0; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic void kw_i2c_close(struct pmac_i2c_bus *bus) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct pmac_i2c_host_kw *host = bus->hostdata; 39362306a36Sopenharmony_ci mutex_unlock(&host->mutex); 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, 39762306a36Sopenharmony_ci u32 subaddr, u8 *data, int len) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct pmac_i2c_host_kw *host = bus->hostdata; 40062306a36Sopenharmony_ci u8 mode_reg = host->speed; 40162306a36Sopenharmony_ci int use_irq = host->irq && !bus->polled; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* Setup mode & subaddress if any */ 40462306a36Sopenharmony_ci switch(bus->mode) { 40562306a36Sopenharmony_ci case pmac_i2c_mode_dumb: 40662306a36Sopenharmony_ci return -EINVAL; 40762306a36Sopenharmony_ci case pmac_i2c_mode_std: 40862306a36Sopenharmony_ci mode_reg |= KW_I2C_MODE_STANDARD; 40962306a36Sopenharmony_ci if (subsize != 0) 41062306a36Sopenharmony_ci return -EINVAL; 41162306a36Sopenharmony_ci break; 41262306a36Sopenharmony_ci case pmac_i2c_mode_stdsub: 41362306a36Sopenharmony_ci mode_reg |= KW_I2C_MODE_STANDARDSUB; 41462306a36Sopenharmony_ci if (subsize != 1) 41562306a36Sopenharmony_ci return -EINVAL; 41662306a36Sopenharmony_ci break; 41762306a36Sopenharmony_ci case pmac_i2c_mode_combined: 41862306a36Sopenharmony_ci mode_reg |= KW_I2C_MODE_COMBINED; 41962306a36Sopenharmony_ci if (subsize != 1) 42062306a36Sopenharmony_ci return -EINVAL; 42162306a36Sopenharmony_ci break; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* Setup channel & clear pending irqs */ 42562306a36Sopenharmony_ci kw_write_reg(reg_isr, kw_read_reg(reg_isr)); 42662306a36Sopenharmony_ci kw_write_reg(reg_mode, mode_reg | (bus->channel << 4)); 42762306a36Sopenharmony_ci kw_write_reg(reg_status, 0); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* Set up address and r/w bit, strip possible stale bus number from 43062306a36Sopenharmony_ci * address top bits 43162306a36Sopenharmony_ci */ 43262306a36Sopenharmony_ci kw_write_reg(reg_addr, addrdir & 0xff); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci /* Set up the sub address */ 43562306a36Sopenharmony_ci if ((mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB 43662306a36Sopenharmony_ci || (mode_reg & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED) 43762306a36Sopenharmony_ci kw_write_reg(reg_subaddr, subaddr); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* Prepare for async operations */ 44062306a36Sopenharmony_ci host->data = data; 44162306a36Sopenharmony_ci host->len = len; 44262306a36Sopenharmony_ci host->state = state_addr; 44362306a36Sopenharmony_ci host->result = 0; 44462306a36Sopenharmony_ci host->rw = (addrdir & 1); 44562306a36Sopenharmony_ci host->polled = bus->polled; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci /* Enable interrupt if not using polled mode and interrupt is 44862306a36Sopenharmony_ci * available 44962306a36Sopenharmony_ci */ 45062306a36Sopenharmony_ci if (use_irq) { 45162306a36Sopenharmony_ci /* Clear completion */ 45262306a36Sopenharmony_ci reinit_completion(&host->complete); 45362306a36Sopenharmony_ci /* Ack stale interrupts */ 45462306a36Sopenharmony_ci kw_write_reg(reg_isr, kw_read_reg(reg_isr)); 45562306a36Sopenharmony_ci /* Arm timeout */ 45662306a36Sopenharmony_ci host->timeout_timer.expires = jiffies + KW_POLL_TIMEOUT; 45762306a36Sopenharmony_ci add_timer(&host->timeout_timer); 45862306a36Sopenharmony_ci /* Enable emission */ 45962306a36Sopenharmony_ci kw_write_reg(reg_ier, KW_I2C_IRQ_MASK); 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* Start sending address */ 46362306a36Sopenharmony_ci kw_write_reg(reg_control, KW_I2C_CTL_XADDR); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci /* Wait for completion */ 46662306a36Sopenharmony_ci if (use_irq) 46762306a36Sopenharmony_ci wait_for_completion(&host->complete); 46862306a36Sopenharmony_ci else { 46962306a36Sopenharmony_ci while(host->state != state_idle) { 47062306a36Sopenharmony_ci unsigned long flags; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci u8 isr = kw_i2c_wait_interrupt(host); 47362306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 47462306a36Sopenharmony_ci kw_i2c_handle_interrupt(host, isr); 47562306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* Disable emission */ 48062306a36Sopenharmony_ci kw_write_reg(reg_ier, 0); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci return host->result; 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct pmac_i2c_host_kw *host; 48862306a36Sopenharmony_ci const u32 *psteps, *prate, *addrp; 48962306a36Sopenharmony_ci u32 steps; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci host = kzalloc(sizeof(*host), GFP_KERNEL); 49262306a36Sopenharmony_ci if (host == NULL) { 49362306a36Sopenharmony_ci printk(KERN_ERR "low_i2c: Can't allocate host for %pOF\n", 49462306a36Sopenharmony_ci np); 49562306a36Sopenharmony_ci return NULL; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* Apple is kind enough to provide a valid AAPL,address property 49962306a36Sopenharmony_ci * on all i2c keywest nodes so far ... we would have to fallback 50062306a36Sopenharmony_ci * to macio parsing if that wasn't the case 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_ci addrp = of_get_property(np, "AAPL,address", NULL); 50362306a36Sopenharmony_ci if (addrp == NULL) { 50462306a36Sopenharmony_ci printk(KERN_ERR "low_i2c: Can't find address for %pOF\n", 50562306a36Sopenharmony_ci np); 50662306a36Sopenharmony_ci kfree(host); 50762306a36Sopenharmony_ci return NULL; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci mutex_init(&host->mutex); 51062306a36Sopenharmony_ci init_completion(&host->complete); 51162306a36Sopenharmony_ci spin_lock_init(&host->lock); 51262306a36Sopenharmony_ci timer_setup(&host->timeout_timer, kw_i2c_timeout, 0); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci psteps = of_get_property(np, "AAPL,address-step", NULL); 51562306a36Sopenharmony_ci steps = psteps ? (*psteps) : 0x10; 51662306a36Sopenharmony_ci for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++) 51762306a36Sopenharmony_ci steps >>= 1; 51862306a36Sopenharmony_ci /* Select interface rate */ 51962306a36Sopenharmony_ci host->speed = KW_I2C_MODE_25KHZ; 52062306a36Sopenharmony_ci prate = of_get_property(np, "AAPL,i2c-rate", NULL); 52162306a36Sopenharmony_ci if (prate) switch(*prate) { 52262306a36Sopenharmony_ci case 100: 52362306a36Sopenharmony_ci host->speed = KW_I2C_MODE_100KHZ; 52462306a36Sopenharmony_ci break; 52562306a36Sopenharmony_ci case 50: 52662306a36Sopenharmony_ci host->speed = KW_I2C_MODE_50KHZ; 52762306a36Sopenharmony_ci break; 52862306a36Sopenharmony_ci case 25: 52962306a36Sopenharmony_ci host->speed = KW_I2C_MODE_25KHZ; 53062306a36Sopenharmony_ci break; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci host->irq = irq_of_parse_and_map(np, 0); 53362306a36Sopenharmony_ci if (!host->irq) 53462306a36Sopenharmony_ci printk(KERN_WARNING 53562306a36Sopenharmony_ci "low_i2c: Failed to map interrupt for %pOF\n", 53662306a36Sopenharmony_ci np); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci host->base = ioremap((*addrp), 0x1000); 53962306a36Sopenharmony_ci if (host->base == NULL) { 54062306a36Sopenharmony_ci printk(KERN_ERR "low_i2c: Can't map registers for %pOF\n", 54162306a36Sopenharmony_ci np); 54262306a36Sopenharmony_ci kfree(host); 54362306a36Sopenharmony_ci return NULL; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci /* Make sure IRQ is disabled */ 54762306a36Sopenharmony_ci kw_write_reg(reg_ier, 0); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci /* Request chip interrupt. We set IRQF_NO_SUSPEND because we don't 55062306a36Sopenharmony_ci * want that interrupt disabled between the 2 passes of driver 55162306a36Sopenharmony_ci * suspend or we'll have issues running the pfuncs 55262306a36Sopenharmony_ci */ 55362306a36Sopenharmony_ci if (request_irq(host->irq, kw_i2c_irq, IRQF_NO_SUSPEND, 55462306a36Sopenharmony_ci "keywest i2c", host)) 55562306a36Sopenharmony_ci host->irq = 0; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci printk(KERN_INFO "KeyWest i2c @0x%08x irq %d %pOF\n", 55862306a36Sopenharmony_ci *addrp, host->irq, np); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci return host; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic void __init kw_i2c_add(struct pmac_i2c_host_kw *host, 56562306a36Sopenharmony_ci struct device_node *controller, 56662306a36Sopenharmony_ci struct device_node *busnode, 56762306a36Sopenharmony_ci int channel) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci struct pmac_i2c_bus *bus; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci bus = kzalloc(sizeof(struct pmac_i2c_bus), GFP_KERNEL); 57262306a36Sopenharmony_ci if (bus == NULL) 57362306a36Sopenharmony_ci return; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci bus->controller = of_node_get(controller); 57662306a36Sopenharmony_ci bus->busnode = of_node_get(busnode); 57762306a36Sopenharmony_ci bus->type = pmac_i2c_bus_keywest; 57862306a36Sopenharmony_ci bus->hostdata = host; 57962306a36Sopenharmony_ci bus->channel = channel; 58062306a36Sopenharmony_ci bus->mode = pmac_i2c_mode_std; 58162306a36Sopenharmony_ci bus->open = kw_i2c_open; 58262306a36Sopenharmony_ci bus->close = kw_i2c_close; 58362306a36Sopenharmony_ci bus->xfer = kw_i2c_xfer; 58462306a36Sopenharmony_ci mutex_init(&bus->mutex); 58562306a36Sopenharmony_ci lockdep_register_key(&bus->lock_key); 58662306a36Sopenharmony_ci lockdep_set_class(&bus->mutex, &bus->lock_key); 58762306a36Sopenharmony_ci if (controller == busnode) 58862306a36Sopenharmony_ci bus->flags = pmac_i2c_multibus; 58962306a36Sopenharmony_ci list_add(&bus->link, &pmac_i2c_busses); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci printk(KERN_INFO " channel %d bus %s\n", channel, 59262306a36Sopenharmony_ci (controller == busnode) ? "<multibus>" : busnode->full_name); 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic void __init kw_i2c_probe(void) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci struct device_node *np, *child, *parent; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci /* Probe keywest-i2c busses */ 60062306a36Sopenharmony_ci for_each_compatible_node(np, "i2c","keywest-i2c") { 60162306a36Sopenharmony_ci struct pmac_i2c_host_kw *host; 60262306a36Sopenharmony_ci int multibus; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci /* Found one, init a host structure */ 60562306a36Sopenharmony_ci host = kw_i2c_host_init(np); 60662306a36Sopenharmony_ci if (host == NULL) 60762306a36Sopenharmony_ci continue; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci /* Now check if we have a multibus setup (old style) or if we 61062306a36Sopenharmony_ci * have proper bus nodes. Note that the "new" way (proper bus 61162306a36Sopenharmony_ci * nodes) might cause us to not create some busses that are 61262306a36Sopenharmony_ci * kept hidden in the device-tree. In the future, we might 61362306a36Sopenharmony_ci * want to work around that by creating busses without a node 61462306a36Sopenharmony_ci * but not for now 61562306a36Sopenharmony_ci */ 61662306a36Sopenharmony_ci child = of_get_next_child(np, NULL); 61762306a36Sopenharmony_ci multibus = !of_node_name_eq(child, "i2c-bus"); 61862306a36Sopenharmony_ci of_node_put(child); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* For a multibus setup, we get the bus count based on the 62162306a36Sopenharmony_ci * parent type 62262306a36Sopenharmony_ci */ 62362306a36Sopenharmony_ci if (multibus) { 62462306a36Sopenharmony_ci int chans, i; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci parent = of_get_parent(np); 62762306a36Sopenharmony_ci if (parent == NULL) 62862306a36Sopenharmony_ci continue; 62962306a36Sopenharmony_ci chans = parent->name[0] == 'u' ? 2 : 1; 63062306a36Sopenharmony_ci of_node_put(parent); 63162306a36Sopenharmony_ci for (i = 0; i < chans; i++) 63262306a36Sopenharmony_ci kw_i2c_add(host, np, np, i); 63362306a36Sopenharmony_ci } else { 63462306a36Sopenharmony_ci for_each_child_of_node(np, child) { 63562306a36Sopenharmony_ci const u32 *reg = of_get_property(child, 63662306a36Sopenharmony_ci "reg", NULL); 63762306a36Sopenharmony_ci if (reg == NULL) 63862306a36Sopenharmony_ci continue; 63962306a36Sopenharmony_ci kw_i2c_add(host, np, child, *reg); 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci/* 64762306a36Sopenharmony_ci * 64862306a36Sopenharmony_ci * PMU implementation 64962306a36Sopenharmony_ci * 65062306a36Sopenharmony_ci */ 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci#ifdef CONFIG_ADB_PMU 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci/* 65562306a36Sopenharmony_ci * i2c command block to the PMU 65662306a36Sopenharmony_ci */ 65762306a36Sopenharmony_cistruct pmu_i2c_hdr { 65862306a36Sopenharmony_ci u8 bus; 65962306a36Sopenharmony_ci u8 mode; 66062306a36Sopenharmony_ci u8 bus2; 66162306a36Sopenharmony_ci u8 address; 66262306a36Sopenharmony_ci u8 sub_addr; 66362306a36Sopenharmony_ci u8 comb_addr; 66462306a36Sopenharmony_ci u8 count; 66562306a36Sopenharmony_ci u8 data[]; 66662306a36Sopenharmony_ci}; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic void pmu_i2c_complete(struct adb_request *req) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci complete(req->arg); 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic int pmu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, 67462306a36Sopenharmony_ci u32 subaddr, u8 *data, int len) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci struct adb_request *req = bus->hostdata; 67762306a36Sopenharmony_ci struct pmu_i2c_hdr *hdr = (struct pmu_i2c_hdr *)&req->data[1]; 67862306a36Sopenharmony_ci struct completion comp; 67962306a36Sopenharmony_ci int read = addrdir & 1; 68062306a36Sopenharmony_ci int retry; 68162306a36Sopenharmony_ci int rc = 0; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci /* For now, limit ourselves to 16 bytes transfers */ 68462306a36Sopenharmony_ci if (len > 16) 68562306a36Sopenharmony_ci return -EINVAL; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci init_completion(&comp); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci for (retry = 0; retry < 16; retry++) { 69062306a36Sopenharmony_ci memset(req, 0, sizeof(struct adb_request)); 69162306a36Sopenharmony_ci hdr->bus = bus->channel; 69262306a36Sopenharmony_ci hdr->count = len; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci switch(bus->mode) { 69562306a36Sopenharmony_ci case pmac_i2c_mode_std: 69662306a36Sopenharmony_ci if (subsize != 0) 69762306a36Sopenharmony_ci return -EINVAL; 69862306a36Sopenharmony_ci hdr->address = addrdir; 69962306a36Sopenharmony_ci hdr->mode = PMU_I2C_MODE_SIMPLE; 70062306a36Sopenharmony_ci break; 70162306a36Sopenharmony_ci case pmac_i2c_mode_stdsub: 70262306a36Sopenharmony_ci case pmac_i2c_mode_combined: 70362306a36Sopenharmony_ci if (subsize != 1) 70462306a36Sopenharmony_ci return -EINVAL; 70562306a36Sopenharmony_ci hdr->address = addrdir & 0xfe; 70662306a36Sopenharmony_ci hdr->comb_addr = addrdir; 70762306a36Sopenharmony_ci hdr->sub_addr = subaddr; 70862306a36Sopenharmony_ci if (bus->mode == pmac_i2c_mode_stdsub) 70962306a36Sopenharmony_ci hdr->mode = PMU_I2C_MODE_STDSUB; 71062306a36Sopenharmony_ci else 71162306a36Sopenharmony_ci hdr->mode = PMU_I2C_MODE_COMBINED; 71262306a36Sopenharmony_ci break; 71362306a36Sopenharmony_ci default: 71462306a36Sopenharmony_ci return -EINVAL; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci reinit_completion(&comp); 71862306a36Sopenharmony_ci req->data[0] = PMU_I2C_CMD; 71962306a36Sopenharmony_ci req->reply[0] = 0xff; 72062306a36Sopenharmony_ci req->nbytes = sizeof(struct pmu_i2c_hdr) + 1; 72162306a36Sopenharmony_ci req->done = pmu_i2c_complete; 72262306a36Sopenharmony_ci req->arg = ∁ 72362306a36Sopenharmony_ci if (!read && len) { 72462306a36Sopenharmony_ci memcpy(hdr->data, data, len); 72562306a36Sopenharmony_ci req->nbytes += len; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci rc = pmu_queue_request(req); 72862306a36Sopenharmony_ci if (rc) 72962306a36Sopenharmony_ci return rc; 73062306a36Sopenharmony_ci wait_for_completion(&comp); 73162306a36Sopenharmony_ci if (req->reply[0] == PMU_I2C_STATUS_OK) 73262306a36Sopenharmony_ci break; 73362306a36Sopenharmony_ci msleep(15); 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci if (req->reply[0] != PMU_I2C_STATUS_OK) 73662306a36Sopenharmony_ci return -EIO; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci for (retry = 0; retry < 16; retry++) { 73962306a36Sopenharmony_ci memset(req, 0, sizeof(struct adb_request)); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci /* I know that looks like a lot, slow as hell, but darwin 74262306a36Sopenharmony_ci * does it so let's be on the safe side for now 74362306a36Sopenharmony_ci */ 74462306a36Sopenharmony_ci msleep(15); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci hdr->bus = PMU_I2C_BUS_STATUS; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci reinit_completion(&comp); 74962306a36Sopenharmony_ci req->data[0] = PMU_I2C_CMD; 75062306a36Sopenharmony_ci req->reply[0] = 0xff; 75162306a36Sopenharmony_ci req->nbytes = 2; 75262306a36Sopenharmony_ci req->done = pmu_i2c_complete; 75362306a36Sopenharmony_ci req->arg = ∁ 75462306a36Sopenharmony_ci rc = pmu_queue_request(req); 75562306a36Sopenharmony_ci if (rc) 75662306a36Sopenharmony_ci return rc; 75762306a36Sopenharmony_ci wait_for_completion(&comp); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (req->reply[0] == PMU_I2C_STATUS_OK && !read) 76062306a36Sopenharmony_ci return 0; 76162306a36Sopenharmony_ci if (req->reply[0] == PMU_I2C_STATUS_DATAREAD && read) { 76262306a36Sopenharmony_ci int rlen = req->reply_len - 1; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (rlen != len) { 76562306a36Sopenharmony_ci printk(KERN_WARNING "low_i2c: PMU returned %d" 76662306a36Sopenharmony_ci " bytes, expected %d !\n", rlen, len); 76762306a36Sopenharmony_ci return -EIO; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci if (len) 77062306a36Sopenharmony_ci memcpy(data, &req->reply[1], len); 77162306a36Sopenharmony_ci return 0; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci return -EIO; 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic void __init pmu_i2c_probe(void) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci struct pmac_i2c_bus *bus; 78062306a36Sopenharmony_ci struct device_node *busnode; 78162306a36Sopenharmony_ci int channel, sz; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci if (!pmu_present()) 78462306a36Sopenharmony_ci return; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci /* There might or might not be a "pmu-i2c" node, we use that 78762306a36Sopenharmony_ci * or via-pmu itself, whatever we find. I haven't seen a machine 78862306a36Sopenharmony_ci * with separate bus nodes, so we assume a multibus setup 78962306a36Sopenharmony_ci */ 79062306a36Sopenharmony_ci busnode = of_find_node_by_name(NULL, "pmu-i2c"); 79162306a36Sopenharmony_ci if (busnode == NULL) 79262306a36Sopenharmony_ci busnode = of_find_node_by_name(NULL, "via-pmu"); 79362306a36Sopenharmony_ci if (busnode == NULL) 79462306a36Sopenharmony_ci return; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci printk(KERN_INFO "PMU i2c %pOF\n", busnode); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci /* 79962306a36Sopenharmony_ci * We add bus 1 and 2 only for now, bus 0 is "special" 80062306a36Sopenharmony_ci */ 80162306a36Sopenharmony_ci for (channel = 1; channel <= 2; channel++) { 80262306a36Sopenharmony_ci sz = sizeof(struct pmac_i2c_bus) + sizeof(struct adb_request); 80362306a36Sopenharmony_ci bus = kzalloc(sz, GFP_KERNEL); 80462306a36Sopenharmony_ci if (bus == NULL) 80562306a36Sopenharmony_ci return; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci bus->controller = busnode; 80862306a36Sopenharmony_ci bus->busnode = busnode; 80962306a36Sopenharmony_ci bus->type = pmac_i2c_bus_pmu; 81062306a36Sopenharmony_ci bus->channel = channel; 81162306a36Sopenharmony_ci bus->mode = pmac_i2c_mode_std; 81262306a36Sopenharmony_ci bus->hostdata = bus + 1; 81362306a36Sopenharmony_ci bus->xfer = pmu_i2c_xfer; 81462306a36Sopenharmony_ci mutex_init(&bus->mutex); 81562306a36Sopenharmony_ci lockdep_register_key(&bus->lock_key); 81662306a36Sopenharmony_ci lockdep_set_class(&bus->mutex, &bus->lock_key); 81762306a36Sopenharmony_ci bus->flags = pmac_i2c_multibus; 81862306a36Sopenharmony_ci list_add(&bus->link, &pmac_i2c_busses); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci printk(KERN_INFO " channel %d bus <multibus>\n", channel); 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci#endif /* CONFIG_ADB_PMU */ 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci/* 82862306a36Sopenharmony_ci * 82962306a36Sopenharmony_ci * SMU implementation 83062306a36Sopenharmony_ci * 83162306a36Sopenharmony_ci */ 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci#ifdef CONFIG_PMAC_SMU 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_cistatic void smu_i2c_complete(struct smu_i2c_cmd *cmd, void *misc) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci complete(misc); 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic int smu_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, 84162306a36Sopenharmony_ci u32 subaddr, u8 *data, int len) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci struct smu_i2c_cmd *cmd = bus->hostdata; 84462306a36Sopenharmony_ci struct completion comp; 84562306a36Sopenharmony_ci int read = addrdir & 1; 84662306a36Sopenharmony_ci int rc = 0; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci if ((read && len > SMU_I2C_READ_MAX) || 84962306a36Sopenharmony_ci ((!read) && len > SMU_I2C_WRITE_MAX)) 85062306a36Sopenharmony_ci return -EINVAL; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci memset(cmd, 0, sizeof(struct smu_i2c_cmd)); 85362306a36Sopenharmony_ci cmd->info.bus = bus->channel; 85462306a36Sopenharmony_ci cmd->info.devaddr = addrdir; 85562306a36Sopenharmony_ci cmd->info.datalen = len; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci switch(bus->mode) { 85862306a36Sopenharmony_ci case pmac_i2c_mode_std: 85962306a36Sopenharmony_ci if (subsize != 0) 86062306a36Sopenharmony_ci return -EINVAL; 86162306a36Sopenharmony_ci cmd->info.type = SMU_I2C_TRANSFER_SIMPLE; 86262306a36Sopenharmony_ci break; 86362306a36Sopenharmony_ci case pmac_i2c_mode_stdsub: 86462306a36Sopenharmony_ci case pmac_i2c_mode_combined: 86562306a36Sopenharmony_ci if (subsize > 3 || subsize < 1) 86662306a36Sopenharmony_ci return -EINVAL; 86762306a36Sopenharmony_ci cmd->info.sublen = subsize; 86862306a36Sopenharmony_ci /* that's big-endian only but heh ! */ 86962306a36Sopenharmony_ci memcpy(&cmd->info.subaddr, ((char *)&subaddr) + (4 - subsize), 87062306a36Sopenharmony_ci subsize); 87162306a36Sopenharmony_ci if (bus->mode == pmac_i2c_mode_stdsub) 87262306a36Sopenharmony_ci cmd->info.type = SMU_I2C_TRANSFER_STDSUB; 87362306a36Sopenharmony_ci else 87462306a36Sopenharmony_ci cmd->info.type = SMU_I2C_TRANSFER_COMBINED; 87562306a36Sopenharmony_ci break; 87662306a36Sopenharmony_ci default: 87762306a36Sopenharmony_ci return -EINVAL; 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci if (!read && len) 88062306a36Sopenharmony_ci memcpy(cmd->info.data, data, len); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci init_completion(&comp); 88362306a36Sopenharmony_ci cmd->done = smu_i2c_complete; 88462306a36Sopenharmony_ci cmd->misc = ∁ 88562306a36Sopenharmony_ci rc = smu_queue_i2c(cmd); 88662306a36Sopenharmony_ci if (rc < 0) 88762306a36Sopenharmony_ci return rc; 88862306a36Sopenharmony_ci wait_for_completion(&comp); 88962306a36Sopenharmony_ci rc = cmd->status; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci if (read && len) 89262306a36Sopenharmony_ci memcpy(data, cmd->info.data, len); 89362306a36Sopenharmony_ci return rc < 0 ? rc : 0; 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_cistatic void __init smu_i2c_probe(void) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci struct device_node *controller, *busnode; 89962306a36Sopenharmony_ci struct pmac_i2c_bus *bus; 90062306a36Sopenharmony_ci const u32 *reg; 90162306a36Sopenharmony_ci int sz; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci if (!smu_present()) 90462306a36Sopenharmony_ci return; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci controller = of_find_node_by_name(NULL, "smu-i2c-control"); 90762306a36Sopenharmony_ci if (controller == NULL) 90862306a36Sopenharmony_ci controller = of_find_node_by_name(NULL, "smu"); 90962306a36Sopenharmony_ci if (controller == NULL) 91062306a36Sopenharmony_ci return; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci printk(KERN_INFO "SMU i2c %pOF\n", controller); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci /* Look for childs, note that they might not be of the right 91562306a36Sopenharmony_ci * type as older device trees mix i2c busses and other things 91662306a36Sopenharmony_ci * at the same level 91762306a36Sopenharmony_ci */ 91862306a36Sopenharmony_ci for_each_child_of_node(controller, busnode) { 91962306a36Sopenharmony_ci if (!of_node_is_type(busnode, "i2c") && 92062306a36Sopenharmony_ci !of_node_is_type(busnode, "i2c-bus")) 92162306a36Sopenharmony_ci continue; 92262306a36Sopenharmony_ci reg = of_get_property(busnode, "reg", NULL); 92362306a36Sopenharmony_ci if (reg == NULL) 92462306a36Sopenharmony_ci continue; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci sz = sizeof(struct pmac_i2c_bus) + sizeof(struct smu_i2c_cmd); 92762306a36Sopenharmony_ci bus = kzalloc(sz, GFP_KERNEL); 92862306a36Sopenharmony_ci if (bus == NULL) 92962306a36Sopenharmony_ci return; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci bus->controller = controller; 93262306a36Sopenharmony_ci bus->busnode = of_node_get(busnode); 93362306a36Sopenharmony_ci bus->type = pmac_i2c_bus_smu; 93462306a36Sopenharmony_ci bus->channel = *reg; 93562306a36Sopenharmony_ci bus->mode = pmac_i2c_mode_std; 93662306a36Sopenharmony_ci bus->hostdata = bus + 1; 93762306a36Sopenharmony_ci bus->xfer = smu_i2c_xfer; 93862306a36Sopenharmony_ci mutex_init(&bus->mutex); 93962306a36Sopenharmony_ci lockdep_register_key(&bus->lock_key); 94062306a36Sopenharmony_ci lockdep_set_class(&bus->mutex, &bus->lock_key); 94162306a36Sopenharmony_ci bus->flags = 0; 94262306a36Sopenharmony_ci list_add(&bus->link, &pmac_i2c_busses); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci printk(KERN_INFO " channel %x bus %pOF\n", 94562306a36Sopenharmony_ci bus->channel, busnode); 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci#endif /* CONFIG_PMAC_SMU */ 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci/* 95262306a36Sopenharmony_ci * 95362306a36Sopenharmony_ci * Core code 95462306a36Sopenharmony_ci * 95562306a36Sopenharmony_ci */ 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_cistruct pmac_i2c_bus *pmac_i2c_find_bus(struct device_node *node) 95962306a36Sopenharmony_ci{ 96062306a36Sopenharmony_ci struct device_node *p = of_node_get(node); 96162306a36Sopenharmony_ci struct device_node *prev = NULL; 96262306a36Sopenharmony_ci struct pmac_i2c_bus *bus; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci while(p) { 96562306a36Sopenharmony_ci list_for_each_entry(bus, &pmac_i2c_busses, link) { 96662306a36Sopenharmony_ci if (p == bus->busnode) { 96762306a36Sopenharmony_ci if (prev && bus->flags & pmac_i2c_multibus) { 96862306a36Sopenharmony_ci const u32 *reg; 96962306a36Sopenharmony_ci reg = of_get_property(prev, "reg", 97062306a36Sopenharmony_ci NULL); 97162306a36Sopenharmony_ci if (!reg) 97262306a36Sopenharmony_ci continue; 97362306a36Sopenharmony_ci if (((*reg) >> 8) != bus->channel) 97462306a36Sopenharmony_ci continue; 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci of_node_put(p); 97762306a36Sopenharmony_ci of_node_put(prev); 97862306a36Sopenharmony_ci return bus; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci of_node_put(prev); 98262306a36Sopenharmony_ci prev = p; 98362306a36Sopenharmony_ci p = of_get_parent(p); 98462306a36Sopenharmony_ci } 98562306a36Sopenharmony_ci return NULL; 98662306a36Sopenharmony_ci} 98762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmac_i2c_find_bus); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ciu8 pmac_i2c_get_dev_addr(struct device_node *device) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci const u32 *reg = of_get_property(device, "reg", NULL); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci if (reg == NULL) 99462306a36Sopenharmony_ci return 0; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci return (*reg) & 0xff; 99762306a36Sopenharmony_ci} 99862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmac_i2c_get_dev_addr); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_cistruct device_node *pmac_i2c_get_controller(struct pmac_i2c_bus *bus) 100162306a36Sopenharmony_ci{ 100262306a36Sopenharmony_ci return bus->controller; 100362306a36Sopenharmony_ci} 100462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmac_i2c_get_controller); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_cistruct device_node *pmac_i2c_get_bus_node(struct pmac_i2c_bus *bus) 100762306a36Sopenharmony_ci{ 100862306a36Sopenharmony_ci return bus->busnode; 100962306a36Sopenharmony_ci} 101062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmac_i2c_get_bus_node); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ciint pmac_i2c_get_type(struct pmac_i2c_bus *bus) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci return bus->type; 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmac_i2c_get_type); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ciint pmac_i2c_get_flags(struct pmac_i2c_bus *bus) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci return bus->flags; 102162306a36Sopenharmony_ci} 102262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmac_i2c_get_flags); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ciint pmac_i2c_get_channel(struct pmac_i2c_bus *bus) 102562306a36Sopenharmony_ci{ 102662306a36Sopenharmony_ci return bus->channel; 102762306a36Sopenharmony_ci} 102862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmac_i2c_get_channel); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistruct i2c_adapter *pmac_i2c_get_adapter(struct pmac_i2c_bus *bus) 103262306a36Sopenharmony_ci{ 103362306a36Sopenharmony_ci return &bus->adapter; 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmac_i2c_get_adapter); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_cistruct pmac_i2c_bus *pmac_i2c_adapter_to_bus(struct i2c_adapter *adapter) 103862306a36Sopenharmony_ci{ 103962306a36Sopenharmony_ci struct pmac_i2c_bus *bus; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci list_for_each_entry(bus, &pmac_i2c_busses, link) 104262306a36Sopenharmony_ci if (&bus->adapter == adapter) 104362306a36Sopenharmony_ci return bus; 104462306a36Sopenharmony_ci return NULL; 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmac_i2c_adapter_to_bus); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ciint pmac_i2c_match_adapter(struct device_node *dev, struct i2c_adapter *adapter) 104962306a36Sopenharmony_ci{ 105062306a36Sopenharmony_ci struct pmac_i2c_bus *bus = pmac_i2c_find_bus(dev); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (bus == NULL) 105362306a36Sopenharmony_ci return 0; 105462306a36Sopenharmony_ci return (&bus->adapter == adapter); 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmac_i2c_match_adapter); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ciint pmac_low_i2c_lock(struct device_node *np) 105962306a36Sopenharmony_ci{ 106062306a36Sopenharmony_ci struct pmac_i2c_bus *bus, *found = NULL; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci list_for_each_entry(bus, &pmac_i2c_busses, link) { 106362306a36Sopenharmony_ci if (np == bus->controller) { 106462306a36Sopenharmony_ci found = bus; 106562306a36Sopenharmony_ci break; 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci if (!found) 106962306a36Sopenharmony_ci return -ENODEV; 107062306a36Sopenharmony_ci return pmac_i2c_open(bus, 0); 107162306a36Sopenharmony_ci} 107262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmac_low_i2c_lock); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ciint pmac_low_i2c_unlock(struct device_node *np) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci struct pmac_i2c_bus *bus, *found = NULL; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci list_for_each_entry(bus, &pmac_i2c_busses, link) { 107962306a36Sopenharmony_ci if (np == bus->controller) { 108062306a36Sopenharmony_ci found = bus; 108162306a36Sopenharmony_ci break; 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci if (!found) 108562306a36Sopenharmony_ci return -ENODEV; 108662306a36Sopenharmony_ci pmac_i2c_close(bus); 108762306a36Sopenharmony_ci return 0; 108862306a36Sopenharmony_ci} 108962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmac_low_i2c_unlock); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ciint pmac_i2c_open(struct pmac_i2c_bus *bus, int polled) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci int rc; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci mutex_lock(&bus->mutex); 109762306a36Sopenharmony_ci bus->polled = polled || pmac_i2c_force_poll; 109862306a36Sopenharmony_ci bus->opened = 1; 109962306a36Sopenharmony_ci bus->mode = pmac_i2c_mode_std; 110062306a36Sopenharmony_ci if (bus->open && (rc = bus->open(bus)) != 0) { 110162306a36Sopenharmony_ci bus->opened = 0; 110262306a36Sopenharmony_ci mutex_unlock(&bus->mutex); 110362306a36Sopenharmony_ci return rc; 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci return 0; 110662306a36Sopenharmony_ci} 110762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmac_i2c_open); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_civoid pmac_i2c_close(struct pmac_i2c_bus *bus) 111062306a36Sopenharmony_ci{ 111162306a36Sopenharmony_ci WARN_ON(!bus->opened); 111262306a36Sopenharmony_ci if (bus->close) 111362306a36Sopenharmony_ci bus->close(bus); 111462306a36Sopenharmony_ci bus->opened = 0; 111562306a36Sopenharmony_ci mutex_unlock(&bus->mutex); 111662306a36Sopenharmony_ci} 111762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmac_i2c_close); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ciint pmac_i2c_setmode(struct pmac_i2c_bus *bus, int mode) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci WARN_ON(!bus->opened); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci /* Report me if you see the error below as there might be a new 112462306a36Sopenharmony_ci * "combined4" mode that I need to implement for the SMU bus 112562306a36Sopenharmony_ci */ 112662306a36Sopenharmony_ci if (mode < pmac_i2c_mode_dumb || mode > pmac_i2c_mode_combined) { 112762306a36Sopenharmony_ci printk(KERN_ERR "low_i2c: Invalid mode %d requested on" 112862306a36Sopenharmony_ci " bus %pOF !\n", mode, bus->busnode); 112962306a36Sopenharmony_ci return -EINVAL; 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci bus->mode = mode; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci return 0; 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmac_i2c_setmode); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ciint pmac_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, 113862306a36Sopenharmony_ci u32 subaddr, u8 *data, int len) 113962306a36Sopenharmony_ci{ 114062306a36Sopenharmony_ci int rc; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci WARN_ON(!bus->opened); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci DBG("xfer() chan=%d, addrdir=0x%x, mode=%d, subsize=%d, subaddr=0x%x," 114562306a36Sopenharmony_ci " %d bytes, bus %pOF\n", bus->channel, addrdir, bus->mode, subsize, 114662306a36Sopenharmony_ci subaddr, len, bus->busnode); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci rc = bus->xfer(bus, addrdir, subsize, subaddr, data, len); 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci#ifdef DEBUG 115162306a36Sopenharmony_ci if (rc) 115262306a36Sopenharmony_ci DBG("xfer error %d\n", rc); 115362306a36Sopenharmony_ci#endif 115462306a36Sopenharmony_ci return rc; 115562306a36Sopenharmony_ci} 115662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmac_i2c_xfer); 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci/* some quirks for platform function decoding */ 115962306a36Sopenharmony_cienum { 116062306a36Sopenharmony_ci pmac_i2c_quirk_invmask = 0x00000001u, 116162306a36Sopenharmony_ci pmac_i2c_quirk_skip = 0x00000002u, 116262306a36Sopenharmony_ci}; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_cistatic void pmac_i2c_devscan(void (*callback)(struct device_node *dev, 116562306a36Sopenharmony_ci int quirks)) 116662306a36Sopenharmony_ci{ 116762306a36Sopenharmony_ci struct pmac_i2c_bus *bus; 116862306a36Sopenharmony_ci struct device_node *np; 116962306a36Sopenharmony_ci static struct whitelist_ent { 117062306a36Sopenharmony_ci char *name; 117162306a36Sopenharmony_ci char *compatible; 117262306a36Sopenharmony_ci int quirks; 117362306a36Sopenharmony_ci } whitelist[] = { 117462306a36Sopenharmony_ci /* XXX Study device-tree's & apple drivers are get the quirks 117562306a36Sopenharmony_ci * right ! 117662306a36Sopenharmony_ci */ 117762306a36Sopenharmony_ci /* Workaround: It seems that running the clockspreading 117862306a36Sopenharmony_ci * properties on the eMac will cause lockups during boot. 117962306a36Sopenharmony_ci * The machine seems to work fine without that. So for now, 118062306a36Sopenharmony_ci * let's make sure i2c-hwclock doesn't match about "imic" 118162306a36Sopenharmony_ci * clocks and we'll figure out if we really need to do 118262306a36Sopenharmony_ci * something special about those later. 118362306a36Sopenharmony_ci */ 118462306a36Sopenharmony_ci { "i2c-hwclock", "imic5002", pmac_i2c_quirk_skip }, 118562306a36Sopenharmony_ci { "i2c-hwclock", "imic5003", pmac_i2c_quirk_skip }, 118662306a36Sopenharmony_ci { "i2c-hwclock", NULL, pmac_i2c_quirk_invmask }, 118762306a36Sopenharmony_ci { "i2c-cpu-voltage", NULL, 0}, 118862306a36Sopenharmony_ci { "temp-monitor", NULL, 0 }, 118962306a36Sopenharmony_ci { "supply-monitor", NULL, 0 }, 119062306a36Sopenharmony_ci { NULL, NULL, 0 }, 119162306a36Sopenharmony_ci }; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci /* Only some devices need to have platform functions instantiated 119462306a36Sopenharmony_ci * here. For now, we have a table. Others, like 9554 i2c GPIOs used 119562306a36Sopenharmony_ci * on Xserve, if we ever do a driver for them, will use their own 119662306a36Sopenharmony_ci * platform function instance 119762306a36Sopenharmony_ci */ 119862306a36Sopenharmony_ci list_for_each_entry(bus, &pmac_i2c_busses, link) { 119962306a36Sopenharmony_ci for_each_child_of_node(bus->busnode, np) { 120062306a36Sopenharmony_ci struct whitelist_ent *p; 120162306a36Sopenharmony_ci /* If multibus, check if device is on that bus */ 120262306a36Sopenharmony_ci if (bus->flags & pmac_i2c_multibus) 120362306a36Sopenharmony_ci if (bus != pmac_i2c_find_bus(np)) 120462306a36Sopenharmony_ci continue; 120562306a36Sopenharmony_ci for (p = whitelist; p->name != NULL; p++) { 120662306a36Sopenharmony_ci if (!of_node_name_eq(np, p->name)) 120762306a36Sopenharmony_ci continue; 120862306a36Sopenharmony_ci if (p->compatible && 120962306a36Sopenharmony_ci !of_device_is_compatible(np, p->compatible)) 121062306a36Sopenharmony_ci continue; 121162306a36Sopenharmony_ci if (p->quirks & pmac_i2c_quirk_skip) 121262306a36Sopenharmony_ci break; 121362306a36Sopenharmony_ci callback(np, p->quirks); 121462306a36Sopenharmony_ci break; 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci } 121762306a36Sopenharmony_ci } 121862306a36Sopenharmony_ci} 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci#define MAX_I2C_DATA 64 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_cistruct pmac_i2c_pf_inst 122362306a36Sopenharmony_ci{ 122462306a36Sopenharmony_ci struct pmac_i2c_bus *bus; 122562306a36Sopenharmony_ci u8 addr; 122662306a36Sopenharmony_ci u8 buffer[MAX_I2C_DATA]; 122762306a36Sopenharmony_ci u8 scratch[MAX_I2C_DATA]; 122862306a36Sopenharmony_ci int bytes; 122962306a36Sopenharmony_ci int quirks; 123062306a36Sopenharmony_ci}; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_cistatic void* pmac_i2c_do_begin(struct pmf_function *func, struct pmf_args *args) 123362306a36Sopenharmony_ci{ 123462306a36Sopenharmony_ci struct pmac_i2c_pf_inst *inst; 123562306a36Sopenharmony_ci struct pmac_i2c_bus *bus; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci bus = pmac_i2c_find_bus(func->node); 123862306a36Sopenharmony_ci if (bus == NULL) { 123962306a36Sopenharmony_ci printk(KERN_ERR "low_i2c: Can't find bus for %pOF (pfunc)\n", 124062306a36Sopenharmony_ci func->node); 124162306a36Sopenharmony_ci return NULL; 124262306a36Sopenharmony_ci } 124362306a36Sopenharmony_ci if (pmac_i2c_open(bus, 0)) { 124462306a36Sopenharmony_ci printk(KERN_ERR "low_i2c: Can't open i2c bus for %pOF (pfunc)\n", 124562306a36Sopenharmony_ci func->node); 124662306a36Sopenharmony_ci return NULL; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci /* XXX might need GFP_ATOMIC when called during the suspend process, 125062306a36Sopenharmony_ci * but then, there are already lots of issues with suspending when 125162306a36Sopenharmony_ci * near OOM that need to be resolved, the allocator itself should 125262306a36Sopenharmony_ci * probably make GFP_NOIO implicit during suspend 125362306a36Sopenharmony_ci */ 125462306a36Sopenharmony_ci inst = kzalloc(sizeof(struct pmac_i2c_pf_inst), GFP_KERNEL); 125562306a36Sopenharmony_ci if (inst == NULL) { 125662306a36Sopenharmony_ci pmac_i2c_close(bus); 125762306a36Sopenharmony_ci return NULL; 125862306a36Sopenharmony_ci } 125962306a36Sopenharmony_ci inst->bus = bus; 126062306a36Sopenharmony_ci inst->addr = pmac_i2c_get_dev_addr(func->node); 126162306a36Sopenharmony_ci inst->quirks = (int)(long)func->driver_data; 126262306a36Sopenharmony_ci return inst; 126362306a36Sopenharmony_ci} 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_cistatic void pmac_i2c_do_end(struct pmf_function *func, void *instdata) 126662306a36Sopenharmony_ci{ 126762306a36Sopenharmony_ci struct pmac_i2c_pf_inst *inst = instdata; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (inst == NULL) 127062306a36Sopenharmony_ci return; 127162306a36Sopenharmony_ci pmac_i2c_close(inst->bus); 127262306a36Sopenharmony_ci kfree(inst); 127362306a36Sopenharmony_ci} 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_cistatic int pmac_i2c_do_read(PMF_STD_ARGS, u32 len) 127662306a36Sopenharmony_ci{ 127762306a36Sopenharmony_ci struct pmac_i2c_pf_inst *inst = instdata; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci inst->bytes = len; 128062306a36Sopenharmony_ci return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_read, 0, 0, 128162306a36Sopenharmony_ci inst->buffer, len); 128262306a36Sopenharmony_ci} 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_cistatic int pmac_i2c_do_write(PMF_STD_ARGS, u32 len, const u8 *data) 128562306a36Sopenharmony_ci{ 128662306a36Sopenharmony_ci struct pmac_i2c_pf_inst *inst = instdata; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 0, 0, 128962306a36Sopenharmony_ci (u8 *)data, len); 129062306a36Sopenharmony_ci} 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci/* This function is used to do the masking & OR'ing for the "rmw" type 129362306a36Sopenharmony_ci * callbacks. Ze should apply the mask and OR in the values in the 129462306a36Sopenharmony_ci * buffer before writing back. The problem is that it seems that 129562306a36Sopenharmony_ci * various darwin drivers implement the mask/or differently, thus 129662306a36Sopenharmony_ci * we need to check the quirks first 129762306a36Sopenharmony_ci */ 129862306a36Sopenharmony_cistatic void pmac_i2c_do_apply_rmw(struct pmac_i2c_pf_inst *inst, 129962306a36Sopenharmony_ci u32 len, const u8 *mask, const u8 *val) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci int i; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci if (inst->quirks & pmac_i2c_quirk_invmask) { 130462306a36Sopenharmony_ci for (i = 0; i < len; i ++) 130562306a36Sopenharmony_ci inst->scratch[i] = (inst->buffer[i] & mask[i]) | val[i]; 130662306a36Sopenharmony_ci } else { 130762306a36Sopenharmony_ci for (i = 0; i < len; i ++) 130862306a36Sopenharmony_ci inst->scratch[i] = (inst->buffer[i] & ~mask[i]) 130962306a36Sopenharmony_ci | (val[i] & mask[i]); 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci} 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_cistatic int pmac_i2c_do_rmw(PMF_STD_ARGS, u32 masklen, u32 valuelen, 131462306a36Sopenharmony_ci u32 totallen, const u8 *maskdata, 131562306a36Sopenharmony_ci const u8 *valuedata) 131662306a36Sopenharmony_ci{ 131762306a36Sopenharmony_ci struct pmac_i2c_pf_inst *inst = instdata; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci if (masklen > inst->bytes || valuelen > inst->bytes || 132062306a36Sopenharmony_ci totallen > inst->bytes || valuelen > masklen) 132162306a36Sopenharmony_ci return -EINVAL; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci pmac_i2c_do_apply_rmw(inst, masklen, maskdata, valuedata); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 0, 0, 132662306a36Sopenharmony_ci inst->scratch, totallen); 132762306a36Sopenharmony_ci} 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_cistatic int pmac_i2c_do_read_sub(PMF_STD_ARGS, u8 subaddr, u32 len) 133062306a36Sopenharmony_ci{ 133162306a36Sopenharmony_ci struct pmac_i2c_pf_inst *inst = instdata; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci inst->bytes = len; 133462306a36Sopenharmony_ci return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_read, 1, subaddr, 133562306a36Sopenharmony_ci inst->buffer, len); 133662306a36Sopenharmony_ci} 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_cistatic int pmac_i2c_do_write_sub(PMF_STD_ARGS, u8 subaddr, u32 len, 133962306a36Sopenharmony_ci const u8 *data) 134062306a36Sopenharmony_ci{ 134162306a36Sopenharmony_ci struct pmac_i2c_pf_inst *inst = instdata; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 1, 134462306a36Sopenharmony_ci subaddr, (u8 *)data, len); 134562306a36Sopenharmony_ci} 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_cistatic int pmac_i2c_do_set_mode(PMF_STD_ARGS, int mode) 134862306a36Sopenharmony_ci{ 134962306a36Sopenharmony_ci struct pmac_i2c_pf_inst *inst = instdata; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci return pmac_i2c_setmode(inst->bus, mode); 135262306a36Sopenharmony_ci} 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_cistatic int pmac_i2c_do_rmw_sub(PMF_STD_ARGS, u8 subaddr, u32 masklen, 135562306a36Sopenharmony_ci u32 valuelen, u32 totallen, const u8 *maskdata, 135662306a36Sopenharmony_ci const u8 *valuedata) 135762306a36Sopenharmony_ci{ 135862306a36Sopenharmony_ci struct pmac_i2c_pf_inst *inst = instdata; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci if (masklen > inst->bytes || valuelen > inst->bytes || 136162306a36Sopenharmony_ci totallen > inst->bytes || valuelen > masklen) 136262306a36Sopenharmony_ci return -EINVAL; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci pmac_i2c_do_apply_rmw(inst, masklen, maskdata, valuedata); 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci return pmac_i2c_xfer(inst->bus, inst->addr | pmac_i2c_write, 1, 136762306a36Sopenharmony_ci subaddr, inst->scratch, totallen); 136862306a36Sopenharmony_ci} 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_cistatic int pmac_i2c_do_mask_and_comp(PMF_STD_ARGS, u32 len, 137162306a36Sopenharmony_ci const u8 *maskdata, 137262306a36Sopenharmony_ci const u8 *valuedata) 137362306a36Sopenharmony_ci{ 137462306a36Sopenharmony_ci struct pmac_i2c_pf_inst *inst = instdata; 137562306a36Sopenharmony_ci int i, match; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci /* Get return value pointer, it's assumed to be a u32 */ 137862306a36Sopenharmony_ci if (!args || !args->count || !args->u[0].p) 137962306a36Sopenharmony_ci return -EINVAL; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci /* Check buffer */ 138262306a36Sopenharmony_ci if (len > inst->bytes) 138362306a36Sopenharmony_ci return -EINVAL; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci for (i = 0, match = 1; match && i < len; i ++) 138662306a36Sopenharmony_ci if ((inst->buffer[i] & maskdata[i]) != valuedata[i]) 138762306a36Sopenharmony_ci match = 0; 138862306a36Sopenharmony_ci *args->u[0].p = match; 138962306a36Sopenharmony_ci return 0; 139062306a36Sopenharmony_ci} 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_cistatic int pmac_i2c_do_delay(PMF_STD_ARGS, u32 duration) 139362306a36Sopenharmony_ci{ 139462306a36Sopenharmony_ci msleep((duration + 999) / 1000); 139562306a36Sopenharmony_ci return 0; 139662306a36Sopenharmony_ci} 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_cistatic struct pmf_handlers pmac_i2c_pfunc_handlers = { 140062306a36Sopenharmony_ci .begin = pmac_i2c_do_begin, 140162306a36Sopenharmony_ci .end = pmac_i2c_do_end, 140262306a36Sopenharmony_ci .read_i2c = pmac_i2c_do_read, 140362306a36Sopenharmony_ci .write_i2c = pmac_i2c_do_write, 140462306a36Sopenharmony_ci .rmw_i2c = pmac_i2c_do_rmw, 140562306a36Sopenharmony_ci .read_i2c_sub = pmac_i2c_do_read_sub, 140662306a36Sopenharmony_ci .write_i2c_sub = pmac_i2c_do_write_sub, 140762306a36Sopenharmony_ci .rmw_i2c_sub = pmac_i2c_do_rmw_sub, 140862306a36Sopenharmony_ci .set_i2c_mode = pmac_i2c_do_set_mode, 140962306a36Sopenharmony_ci .mask_and_compare = pmac_i2c_do_mask_and_comp, 141062306a36Sopenharmony_ci .delay = pmac_i2c_do_delay, 141162306a36Sopenharmony_ci}; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_cistatic void __init pmac_i2c_dev_create(struct device_node *np, int quirks) 141462306a36Sopenharmony_ci{ 141562306a36Sopenharmony_ci DBG("dev_create(%pOF)\n", np); 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci pmf_register_driver(np, &pmac_i2c_pfunc_handlers, 141862306a36Sopenharmony_ci (void *)(long)quirks); 141962306a36Sopenharmony_ci} 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_cistatic void __init pmac_i2c_dev_init(struct device_node *np, int quirks) 142262306a36Sopenharmony_ci{ 142362306a36Sopenharmony_ci DBG("dev_create(%pOF)\n", np); 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci pmf_do_functions(np, NULL, 0, PMF_FLAGS_ON_INIT, NULL); 142662306a36Sopenharmony_ci} 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_cistatic void pmac_i2c_dev_suspend(struct device_node *np, int quirks) 142962306a36Sopenharmony_ci{ 143062306a36Sopenharmony_ci DBG("dev_suspend(%pOF)\n", np); 143162306a36Sopenharmony_ci pmf_do_functions(np, NULL, 0, PMF_FLAGS_ON_SLEEP, NULL); 143262306a36Sopenharmony_ci} 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_cistatic void pmac_i2c_dev_resume(struct device_node *np, int quirks) 143562306a36Sopenharmony_ci{ 143662306a36Sopenharmony_ci DBG("dev_resume(%pOF)\n", np); 143762306a36Sopenharmony_ci pmf_do_functions(np, NULL, 0, PMF_FLAGS_ON_WAKE, NULL); 143862306a36Sopenharmony_ci} 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_civoid pmac_pfunc_i2c_suspend(void) 144162306a36Sopenharmony_ci{ 144262306a36Sopenharmony_ci pmac_i2c_devscan(pmac_i2c_dev_suspend); 144362306a36Sopenharmony_ci} 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_civoid pmac_pfunc_i2c_resume(void) 144662306a36Sopenharmony_ci{ 144762306a36Sopenharmony_ci pmac_i2c_devscan(pmac_i2c_dev_resume); 144862306a36Sopenharmony_ci} 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci/* 145162306a36Sopenharmony_ci * Initialize us: probe all i2c busses on the machine, instantiate 145262306a36Sopenharmony_ci * busses and platform functions as needed. 145362306a36Sopenharmony_ci */ 145462306a36Sopenharmony_ci/* This is non-static as it might be called early by smp code */ 145562306a36Sopenharmony_ciint __init pmac_i2c_init(void) 145662306a36Sopenharmony_ci{ 145762306a36Sopenharmony_ci static int i2c_inited; 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci if (i2c_inited) 146062306a36Sopenharmony_ci return 0; 146162306a36Sopenharmony_ci i2c_inited = 1; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci /* Probe keywest-i2c busses */ 146462306a36Sopenharmony_ci kw_i2c_probe(); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci#ifdef CONFIG_ADB_PMU 146762306a36Sopenharmony_ci /* Probe PMU i2c busses */ 146862306a36Sopenharmony_ci pmu_i2c_probe(); 146962306a36Sopenharmony_ci#endif 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci#ifdef CONFIG_PMAC_SMU 147262306a36Sopenharmony_ci /* Probe SMU i2c busses */ 147362306a36Sopenharmony_ci smu_i2c_probe(); 147462306a36Sopenharmony_ci#endif 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci /* Now add platform functions for some known devices */ 147762306a36Sopenharmony_ci pmac_i2c_devscan(pmac_i2c_dev_create); 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci return 0; 148062306a36Sopenharmony_ci} 148162306a36Sopenharmony_cimachine_arch_initcall(powermac, pmac_i2c_init); 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci/* Since pmac_i2c_init can be called too early for the platform device 148462306a36Sopenharmony_ci * registration, we need to do it at a later time. In our case, subsys 148562306a36Sopenharmony_ci * happens to fit well, though I agree it's a bit of a hack... 148662306a36Sopenharmony_ci */ 148762306a36Sopenharmony_cistatic int __init pmac_i2c_create_platform_devices(void) 148862306a36Sopenharmony_ci{ 148962306a36Sopenharmony_ci struct pmac_i2c_bus *bus; 149062306a36Sopenharmony_ci int i = 0; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci /* In the case where we are initialized from smp_init(), we must 149362306a36Sopenharmony_ci * not use the timer (and thus the irq). It's safe from now on 149462306a36Sopenharmony_ci * though 149562306a36Sopenharmony_ci */ 149662306a36Sopenharmony_ci pmac_i2c_force_poll = 0; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci /* Create platform devices */ 149962306a36Sopenharmony_ci list_for_each_entry(bus, &pmac_i2c_busses, link) { 150062306a36Sopenharmony_ci bus->platform_dev = 150162306a36Sopenharmony_ci platform_device_alloc("i2c-powermac", i++); 150262306a36Sopenharmony_ci if (bus->platform_dev == NULL) 150362306a36Sopenharmony_ci return -ENOMEM; 150462306a36Sopenharmony_ci bus->platform_dev->dev.platform_data = bus; 150562306a36Sopenharmony_ci bus->platform_dev->dev.of_node = bus->busnode; 150662306a36Sopenharmony_ci platform_device_add(bus->platform_dev); 150762306a36Sopenharmony_ci } 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci /* Now call platform "init" functions */ 151062306a36Sopenharmony_ci pmac_i2c_devscan(pmac_i2c_dev_init); 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci return 0; 151362306a36Sopenharmony_ci} 151462306a36Sopenharmony_cimachine_subsys_initcall(powermac, pmac_i2c_create_platform_devices); 1515