162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * drivers/i2c/busses/i2c-ibm_iic.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Support for the IIC peripheral on IBM PPC 4xx 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2003, 2004 Zultys Technologies. 862306a36Sopenharmony_ci * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Copyright (c) 2008 PIKA Technologies 1162306a36Sopenharmony_ci * Sean MacLennan <smaclennan@pikatech.com> 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Based on original work by 1462306a36Sopenharmony_ci * Ian DaSilva <idasilva@mvista.com> 1562306a36Sopenharmony_ci * Armin Kuster <akuster@mvista.com> 1662306a36Sopenharmony_ci * Matt Porter <mporter@mvista.com> 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Copyright 2000-2003 MontaVista Software Inc. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Original driver version was highly leveraged from i2c-elektor.c 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Copyright 1995-97 Simon G. Vogl 2362306a36Sopenharmony_ci * 1998-99 Hans Berglund 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> 2662306a36Sopenharmony_ci * and even Frodo Looijaard <frodol@dds.nl> 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <linux/module.h> 3062306a36Sopenharmony_ci#include <linux/kernel.h> 3162306a36Sopenharmony_ci#include <linux/ioport.h> 3262306a36Sopenharmony_ci#include <linux/delay.h> 3362306a36Sopenharmony_ci#include <linux/slab.h> 3462306a36Sopenharmony_ci#include <linux/interrupt.h> 3562306a36Sopenharmony_ci#include <linux/sched/signal.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <asm/irq.h> 3862306a36Sopenharmony_ci#include <linux/io.h> 3962306a36Sopenharmony_ci#include <linux/i2c.h> 4062306a36Sopenharmony_ci#include <linux/of.h> 4162306a36Sopenharmony_ci#include <linux/of_address.h> 4262306a36Sopenharmony_ci#include <linux/of_irq.h> 4362306a36Sopenharmony_ci#include <linux/platform_device.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include "i2c-ibm_iic.h" 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define DRIVER_VERSION "2.2" 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ciMODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION); 5062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic bool iic_force_poll; 5362306a36Sopenharmony_cimodule_param(iic_force_poll, bool, 0); 5462306a36Sopenharmony_ciMODULE_PARM_DESC(iic_force_poll, "Force polling mode"); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic bool iic_force_fast; 5762306a36Sopenharmony_cimodule_param(iic_force_fast, bool, 0); 5862306a36Sopenharmony_ciMODULE_PARM_DESC(iic_force_fast, "Force fast mode (400 kHz)"); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define DBG_LEVEL 0 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#ifdef DBG 6362306a36Sopenharmony_ci#undef DBG 6462306a36Sopenharmony_ci#endif 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#ifdef DBG2 6762306a36Sopenharmony_ci#undef DBG2 6862306a36Sopenharmony_ci#endif 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#if DBG_LEVEL > 0 7162306a36Sopenharmony_ci# define DBG(f,x...) printk(KERN_DEBUG "ibm-iic" f, ##x) 7262306a36Sopenharmony_ci#else 7362306a36Sopenharmony_ci# define DBG(f,x...) ((void)0) 7462306a36Sopenharmony_ci#endif 7562306a36Sopenharmony_ci#if DBG_LEVEL > 1 7662306a36Sopenharmony_ci# define DBG2(f,x...) DBG(f, ##x) 7762306a36Sopenharmony_ci#else 7862306a36Sopenharmony_ci# define DBG2(f,x...) ((void)0) 7962306a36Sopenharmony_ci#endif 8062306a36Sopenharmony_ci#if DBG_LEVEL > 2 8162306a36Sopenharmony_cistatic void dump_iic_regs(const char* header, struct ibm_iic_private* dev) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci volatile struct iic_regs __iomem *iic = dev->vaddr; 8462306a36Sopenharmony_ci printk(KERN_DEBUG "ibm-iic%d: %s\n", dev->idx, header); 8562306a36Sopenharmony_ci printk(KERN_DEBUG 8662306a36Sopenharmony_ci " cntl = 0x%02x, mdcntl = 0x%02x\n" 8762306a36Sopenharmony_ci " sts = 0x%02x, extsts = 0x%02x\n" 8862306a36Sopenharmony_ci " clkdiv = 0x%02x, xfrcnt = 0x%02x\n" 8962306a36Sopenharmony_ci " xtcntlss = 0x%02x, directcntl = 0x%02x\n", 9062306a36Sopenharmony_ci in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts), 9162306a36Sopenharmony_ci in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt), 9262306a36Sopenharmony_ci in_8(&iic->xtcntlss), in_8(&iic->directcntl)); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci# define DUMP_REGS(h,dev) dump_iic_regs((h),(dev)) 9562306a36Sopenharmony_ci#else 9662306a36Sopenharmony_ci# define DUMP_REGS(h,dev) ((void)0) 9762306a36Sopenharmony_ci#endif 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* Bus timings (in ns) for bit-banging */ 10062306a36Sopenharmony_cistatic struct ibm_iic_timings { 10162306a36Sopenharmony_ci unsigned int hd_sta; 10262306a36Sopenharmony_ci unsigned int su_sto; 10362306a36Sopenharmony_ci unsigned int low; 10462306a36Sopenharmony_ci unsigned int high; 10562306a36Sopenharmony_ci unsigned int buf; 10662306a36Sopenharmony_ci} timings [] = { 10762306a36Sopenharmony_ci/* Standard mode (100 KHz) */ 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci .hd_sta = 4000, 11062306a36Sopenharmony_ci .su_sto = 4000, 11162306a36Sopenharmony_ci .low = 4700, 11262306a36Sopenharmony_ci .high = 4000, 11362306a36Sopenharmony_ci .buf = 4700, 11462306a36Sopenharmony_ci}, 11562306a36Sopenharmony_ci/* Fast mode (400 KHz) */ 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci .hd_sta = 600, 11862306a36Sopenharmony_ci .su_sto = 600, 11962306a36Sopenharmony_ci .low = 1300, 12062306a36Sopenharmony_ci .high = 600, 12162306a36Sopenharmony_ci .buf = 1300, 12262306a36Sopenharmony_ci}}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/* Enable/disable interrupt generation */ 12562306a36Sopenharmony_cistatic inline void iic_interrupt_mode(struct ibm_iic_private* dev, int enable) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci out_8(&dev->vaddr->intmsk, enable ? INTRMSK_EIMTC : 0); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* 13162306a36Sopenharmony_ci * Initialize IIC interface. 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_cistatic void iic_dev_init(struct ibm_iic_private* dev) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci volatile struct iic_regs __iomem *iic = dev->vaddr; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci DBG("%d: init\n", dev->idx); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* Clear master address */ 14062306a36Sopenharmony_ci out_8(&iic->lmadr, 0); 14162306a36Sopenharmony_ci out_8(&iic->hmadr, 0); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* Clear slave address */ 14462306a36Sopenharmony_ci out_8(&iic->lsadr, 0); 14562306a36Sopenharmony_ci out_8(&iic->hsadr, 0); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* Clear status & extended status */ 14862306a36Sopenharmony_ci out_8(&iic->sts, STS_SCMP | STS_IRQA); 14962306a36Sopenharmony_ci out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | EXTSTS_LA 15062306a36Sopenharmony_ci | EXTSTS_ICT | EXTSTS_XFRA); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* Set clock divider */ 15362306a36Sopenharmony_ci out_8(&iic->clkdiv, dev->clckdiv); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* Clear transfer count */ 15662306a36Sopenharmony_ci out_8(&iic->xfrcnt, 0); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* Clear extended control and status */ 15962306a36Sopenharmony_ci out_8(&iic->xtcntlss, XTCNTLSS_SRC | XTCNTLSS_SRS | XTCNTLSS_SWC 16062306a36Sopenharmony_ci | XTCNTLSS_SWS); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* Clear control register */ 16362306a36Sopenharmony_ci out_8(&iic->cntl, 0); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Enable interrupts if possible */ 16662306a36Sopenharmony_ci iic_interrupt_mode(dev, dev->irq >= 0); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* Set mode control */ 16962306a36Sopenharmony_ci out_8(&iic->mdcntl, MDCNTL_FMDB | MDCNTL_EINT | MDCNTL_EUBS 17062306a36Sopenharmony_ci | (dev->fast_mode ? MDCNTL_FSM : 0)); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci DUMP_REGS("iic_init", dev); 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/* 17662306a36Sopenharmony_ci * Reset IIC interface 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_cistatic void iic_dev_reset(struct ibm_iic_private* dev) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci volatile struct iic_regs __iomem *iic = dev->vaddr; 18162306a36Sopenharmony_ci int i; 18262306a36Sopenharmony_ci u8 dc; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci DBG("%d: soft reset\n", dev->idx); 18562306a36Sopenharmony_ci DUMP_REGS("reset", dev); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* Place chip in the reset state */ 18862306a36Sopenharmony_ci out_8(&iic->xtcntlss, XTCNTLSS_SRST); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* Check if bus is free */ 19162306a36Sopenharmony_ci dc = in_8(&iic->directcntl); 19262306a36Sopenharmony_ci if (!DIRCTNL_FREE(dc)){ 19362306a36Sopenharmony_ci DBG("%d: trying to regain bus control\n", dev->idx); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* Try to set bus free state */ 19662306a36Sopenharmony_ci out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* Wait until we regain bus control */ 19962306a36Sopenharmony_ci for (i = 0; i < 100; ++i){ 20062306a36Sopenharmony_ci dc = in_8(&iic->directcntl); 20162306a36Sopenharmony_ci if (DIRCTNL_FREE(dc)) 20262306a36Sopenharmony_ci break; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* Toggle SCL line */ 20562306a36Sopenharmony_ci dc ^= DIRCNTL_SCC; 20662306a36Sopenharmony_ci out_8(&iic->directcntl, dc); 20762306a36Sopenharmony_ci udelay(10); 20862306a36Sopenharmony_ci dc ^= DIRCNTL_SCC; 20962306a36Sopenharmony_ci out_8(&iic->directcntl, dc); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* be nice */ 21262306a36Sopenharmony_ci cond_resched(); 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* Remove reset */ 21762306a36Sopenharmony_ci out_8(&iic->xtcntlss, 0); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* Reinitialize interface */ 22062306a36Sopenharmony_ci iic_dev_init(dev); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci/* 22462306a36Sopenharmony_ci * Do 0-length transaction using bit-banging through IIC_DIRECTCNTL register. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/* Wait for SCL and/or SDA to be high */ 22862306a36Sopenharmony_cistatic int iic_dc_wait(volatile struct iic_regs __iomem *iic, u8 mask) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci unsigned long x = jiffies + HZ / 28 + 2; 23162306a36Sopenharmony_ci while ((in_8(&iic->directcntl) & mask) != mask){ 23262306a36Sopenharmony_ci if (unlikely(time_after(jiffies, x))) 23362306a36Sopenharmony_ci return -1; 23462306a36Sopenharmony_ci cond_resched(); 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int iic_smbus_quick(struct ibm_iic_private* dev, const struct i2c_msg* p) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci volatile struct iic_regs __iomem *iic = dev->vaddr; 24262306a36Sopenharmony_ci const struct ibm_iic_timings *t = &timings[dev->fast_mode ? 1 : 0]; 24362306a36Sopenharmony_ci u8 mask, v, sda; 24462306a36Sopenharmony_ci int i, res; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* Only 7-bit addresses are supported */ 24762306a36Sopenharmony_ci if (unlikely(p->flags & I2C_M_TEN)){ 24862306a36Sopenharmony_ci DBG("%d: smbus_quick - 10 bit addresses are not supported\n", 24962306a36Sopenharmony_ci dev->idx); 25062306a36Sopenharmony_ci return -EINVAL; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci DBG("%d: smbus_quick(0x%02x)\n", dev->idx, p->addr); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* Reset IIC interface */ 25662306a36Sopenharmony_ci out_8(&iic->xtcntlss, XTCNTLSS_SRST); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Wait for bus to become free */ 25962306a36Sopenharmony_ci out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC); 26062306a36Sopenharmony_ci if (unlikely(iic_dc_wait(iic, DIRCNTL_MSDA | DIRCNTL_MSC))) 26162306a36Sopenharmony_ci goto err; 26262306a36Sopenharmony_ci ndelay(t->buf); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* START */ 26562306a36Sopenharmony_ci out_8(&iic->directcntl, DIRCNTL_SCC); 26662306a36Sopenharmony_ci sda = 0; 26762306a36Sopenharmony_ci ndelay(t->hd_sta); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* Send address */ 27062306a36Sopenharmony_ci v = i2c_8bit_addr_from_msg(p); 27162306a36Sopenharmony_ci for (i = 0, mask = 0x80; i < 8; ++i, mask >>= 1){ 27262306a36Sopenharmony_ci out_8(&iic->directcntl, sda); 27362306a36Sopenharmony_ci ndelay(t->low / 2); 27462306a36Sopenharmony_ci sda = (v & mask) ? DIRCNTL_SDAC : 0; 27562306a36Sopenharmony_ci out_8(&iic->directcntl, sda); 27662306a36Sopenharmony_ci ndelay(t->low / 2); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci out_8(&iic->directcntl, DIRCNTL_SCC | sda); 27962306a36Sopenharmony_ci if (unlikely(iic_dc_wait(iic, DIRCNTL_MSC))) 28062306a36Sopenharmony_ci goto err; 28162306a36Sopenharmony_ci ndelay(t->high); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* ACK */ 28562306a36Sopenharmony_ci out_8(&iic->directcntl, sda); 28662306a36Sopenharmony_ci ndelay(t->low / 2); 28762306a36Sopenharmony_ci out_8(&iic->directcntl, DIRCNTL_SDAC); 28862306a36Sopenharmony_ci ndelay(t->low / 2); 28962306a36Sopenharmony_ci out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC); 29062306a36Sopenharmony_ci if (unlikely(iic_dc_wait(iic, DIRCNTL_MSC))) 29162306a36Sopenharmony_ci goto err; 29262306a36Sopenharmony_ci res = (in_8(&iic->directcntl) & DIRCNTL_MSDA) ? -EREMOTEIO : 1; 29362306a36Sopenharmony_ci ndelay(t->high); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* STOP */ 29662306a36Sopenharmony_ci out_8(&iic->directcntl, 0); 29762306a36Sopenharmony_ci ndelay(t->low); 29862306a36Sopenharmony_ci out_8(&iic->directcntl, DIRCNTL_SCC); 29962306a36Sopenharmony_ci if (unlikely(iic_dc_wait(iic, DIRCNTL_MSC))) 30062306a36Sopenharmony_ci goto err; 30162306a36Sopenharmony_ci ndelay(t->su_sto); 30262306a36Sopenharmony_ci out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci ndelay(t->buf); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci DBG("%d: smbus_quick -> %s\n", dev->idx, res ? "NACK" : "ACK"); 30762306a36Sopenharmony_ciout: 30862306a36Sopenharmony_ci /* Remove reset */ 30962306a36Sopenharmony_ci out_8(&iic->xtcntlss, 0); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* Reinitialize interface */ 31262306a36Sopenharmony_ci iic_dev_init(dev); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return res; 31562306a36Sopenharmony_cierr: 31662306a36Sopenharmony_ci DBG("%d: smbus_quick - bus is stuck\n", dev->idx); 31762306a36Sopenharmony_ci res = -EREMOTEIO; 31862306a36Sopenharmony_ci goto out; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci/* 32262306a36Sopenharmony_ci * IIC interrupt handler 32362306a36Sopenharmony_ci */ 32462306a36Sopenharmony_cistatic irqreturn_t iic_handler(int irq, void *dev_id) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id; 32762306a36Sopenharmony_ci volatile struct iic_regs __iomem *iic = dev->vaddr; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n", 33062306a36Sopenharmony_ci dev->idx, in_8(&iic->sts), in_8(&iic->extsts)); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* Acknowledge IRQ and wakeup iic_wait_for_tc */ 33362306a36Sopenharmony_ci out_8(&iic->sts, STS_IRQA | STS_SCMP); 33462306a36Sopenharmony_ci wake_up_interruptible(&dev->wq); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci return IRQ_HANDLED; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci/* 34062306a36Sopenharmony_ci * Get master transfer result and clear errors if any. 34162306a36Sopenharmony_ci * Returns the number of actually transferred bytes or error (<0) 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_cistatic int iic_xfer_result(struct ibm_iic_private* dev) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci volatile struct iic_regs __iomem *iic = dev->vaddr; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (unlikely(in_8(&iic->sts) & STS_ERR)){ 34862306a36Sopenharmony_ci DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx, 34962306a36Sopenharmony_ci in_8(&iic->extsts)); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* Clear errors and possible pending IRQs */ 35262306a36Sopenharmony_ci out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | 35362306a36Sopenharmony_ci EXTSTS_LA | EXTSTS_ICT | EXTSTS_XFRA); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* Flush master data buffer */ 35662306a36Sopenharmony_ci out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* Is bus free? 35962306a36Sopenharmony_ci * If error happened during combined xfer 36062306a36Sopenharmony_ci * IIC interface is usually stuck in some strange 36162306a36Sopenharmony_ci * state, the only way out - soft reset. 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_ci if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){ 36462306a36Sopenharmony_ci DBG("%d: bus is stuck, resetting\n", dev->idx); 36562306a36Sopenharmony_ci iic_dev_reset(dev); 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci return -EREMOTEIO; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci else 37062306a36Sopenharmony_ci return in_8(&iic->xfrcnt) & XFRCNT_MTC_MASK; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci/* 37462306a36Sopenharmony_ci * Try to abort active transfer. 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_cistatic void iic_abort_xfer(struct ibm_iic_private* dev) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci volatile struct iic_regs __iomem *iic = dev->vaddr; 37962306a36Sopenharmony_ci unsigned long x; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci DBG("%d: iic_abort_xfer\n", dev->idx); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci out_8(&iic->cntl, CNTL_HMT); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* 38662306a36Sopenharmony_ci * Wait for the abort command to complete. 38762306a36Sopenharmony_ci * It's not worth to be optimized, just poll (timeout >= 1 tick) 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_ci x = jiffies + 2; 39062306a36Sopenharmony_ci while ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){ 39162306a36Sopenharmony_ci if (time_after(jiffies, x)){ 39262306a36Sopenharmony_ci DBG("%d: abort timeout, resetting...\n", dev->idx); 39362306a36Sopenharmony_ci iic_dev_reset(dev); 39462306a36Sopenharmony_ci return; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci schedule(); 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* Just to clear errors */ 40062306a36Sopenharmony_ci iic_xfer_result(dev); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci/* 40462306a36Sopenharmony_ci * Wait for master transfer to complete. 40562306a36Sopenharmony_ci * It puts current process to sleep until we get interrupt or timeout expires. 40662306a36Sopenharmony_ci * Returns the number of transferred bytes or error (<0) 40762306a36Sopenharmony_ci */ 40862306a36Sopenharmony_cistatic int iic_wait_for_tc(struct ibm_iic_private* dev){ 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci volatile struct iic_regs __iomem *iic = dev->vaddr; 41162306a36Sopenharmony_ci int ret = 0; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (dev->irq >= 0){ 41462306a36Sopenharmony_ci /* Interrupt mode */ 41562306a36Sopenharmony_ci ret = wait_event_interruptible_timeout(dev->wq, 41662306a36Sopenharmony_ci !(in_8(&iic->sts) & STS_PT), dev->adap.timeout); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (unlikely(ret < 0)) 41962306a36Sopenharmony_ci DBG("%d: wait interrupted\n", dev->idx); 42062306a36Sopenharmony_ci else if (unlikely(in_8(&iic->sts) & STS_PT)){ 42162306a36Sopenharmony_ci DBG("%d: wait timeout\n", dev->idx); 42262306a36Sopenharmony_ci ret = -ETIMEDOUT; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci else { 42662306a36Sopenharmony_ci /* Polling mode */ 42762306a36Sopenharmony_ci unsigned long x = jiffies + dev->adap.timeout; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci while (in_8(&iic->sts) & STS_PT){ 43062306a36Sopenharmony_ci if (unlikely(time_after(jiffies, x))){ 43162306a36Sopenharmony_ci DBG("%d: poll timeout\n", dev->idx); 43262306a36Sopenharmony_ci ret = -ETIMEDOUT; 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (signal_pending(current)){ 43762306a36Sopenharmony_ci DBG("%d: poll interrupted\n", dev->idx); 43862306a36Sopenharmony_ci ret = -ERESTARTSYS; 43962306a36Sopenharmony_ci break; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci schedule(); 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (unlikely(ret < 0)) 44662306a36Sopenharmony_ci iic_abort_xfer(dev); 44762306a36Sopenharmony_ci else 44862306a36Sopenharmony_ci ret = iic_xfer_result(dev); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci DBG2("%d: iic_wait_for_tc -> %d\n", dev->idx, ret); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return ret; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci/* 45662306a36Sopenharmony_ci * Low level master transfer routine 45762306a36Sopenharmony_ci */ 45862306a36Sopenharmony_cistatic int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm, 45962306a36Sopenharmony_ci int combined_xfer) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci volatile struct iic_regs __iomem *iic = dev->vaddr; 46262306a36Sopenharmony_ci char* buf = pm->buf; 46362306a36Sopenharmony_ci int i, j, loops, ret = 0; 46462306a36Sopenharmony_ci int len = pm->len; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci u8 cntl = (in_8(&iic->cntl) & CNTL_AMD) | CNTL_PT; 46762306a36Sopenharmony_ci if (pm->flags & I2C_M_RD) 46862306a36Sopenharmony_ci cntl |= CNTL_RW; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci loops = (len + 3) / 4; 47162306a36Sopenharmony_ci for (i = 0; i < loops; ++i, len -= 4){ 47262306a36Sopenharmony_ci int count = len > 4 ? 4 : len; 47362306a36Sopenharmony_ci u8 cmd = cntl | ((count - 1) << CNTL_TCT_SHIFT); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (!(cntl & CNTL_RW)) 47662306a36Sopenharmony_ci for (j = 0; j < count; ++j) 47762306a36Sopenharmony_ci out_8((void __iomem *)&iic->mdbuf, *buf++); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (i < loops - 1) 48062306a36Sopenharmony_ci cmd |= CNTL_CHT; 48162306a36Sopenharmony_ci else if (combined_xfer) 48262306a36Sopenharmony_ci cmd |= CNTL_RPST; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci DBG2("%d: xfer_bytes, %d, CNTL = 0x%02x\n", dev->idx, count, cmd); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* Start transfer */ 48762306a36Sopenharmony_ci out_8(&iic->cntl, cmd); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* Wait for completion */ 49062306a36Sopenharmony_ci ret = iic_wait_for_tc(dev); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (unlikely(ret < 0)) 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci else if (unlikely(ret != count)){ 49562306a36Sopenharmony_ci DBG("%d: xfer_bytes, requested %d, transferred %d\n", 49662306a36Sopenharmony_ci dev->idx, count, ret); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* If it's not a last part of xfer, abort it */ 49962306a36Sopenharmony_ci if (combined_xfer || (i < loops - 1)) 50062306a36Sopenharmony_ci iic_abort_xfer(dev); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci ret = -EREMOTEIO; 50362306a36Sopenharmony_ci break; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (cntl & CNTL_RW) 50762306a36Sopenharmony_ci for (j = 0; j < count; ++j) 50862306a36Sopenharmony_ci *buf++ = in_8((void __iomem *)&iic->mdbuf); 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci return ret > 0 ? 0 : ret; 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci/* 51562306a36Sopenharmony_ci * Set target slave address for master transfer 51662306a36Sopenharmony_ci */ 51762306a36Sopenharmony_cistatic inline void iic_address(struct ibm_iic_private* dev, struct i2c_msg* msg) 51862306a36Sopenharmony_ci{ 51962306a36Sopenharmony_ci volatile struct iic_regs __iomem *iic = dev->vaddr; 52062306a36Sopenharmony_ci u16 addr = msg->addr; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx, 52362306a36Sopenharmony_ci addr, msg->flags & I2C_M_TEN ? 10 : 7); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (msg->flags & I2C_M_TEN){ 52662306a36Sopenharmony_ci out_8(&iic->cntl, CNTL_AMD); 52762306a36Sopenharmony_ci out_8(&iic->lmadr, addr); 52862306a36Sopenharmony_ci out_8(&iic->hmadr, 0xf0 | ((addr >> 7) & 0x06)); 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci else { 53162306a36Sopenharmony_ci out_8(&iic->cntl, 0); 53262306a36Sopenharmony_ci out_8(&iic->lmadr, addr << 1); 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic inline int iic_invalid_address(const struct i2c_msg* p) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci return (p->addr > 0x3ff) || (!(p->flags & I2C_M_TEN) && (p->addr > 0x7f)); 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic inline int iic_address_neq(const struct i2c_msg* p1, 54262306a36Sopenharmony_ci const struct i2c_msg* p2) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci return (p1->addr != p2->addr) 54562306a36Sopenharmony_ci || ((p1->flags & I2C_M_TEN) != (p2->flags & I2C_M_TEN)); 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci/* 54962306a36Sopenharmony_ci * Generic master transfer entrypoint. 55062306a36Sopenharmony_ci * Returns the number of processed messages or error (<0) 55162306a36Sopenharmony_ci */ 55262306a36Sopenharmony_cistatic int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci struct ibm_iic_private* dev = (struct ibm_iic_private*)(i2c_get_adapdata(adap)); 55562306a36Sopenharmony_ci volatile struct iic_regs __iomem *iic = dev->vaddr; 55662306a36Sopenharmony_ci int i, ret = 0; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci DBG2("%d: iic_xfer, %d msg(s)\n", dev->idx, num); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* Check the sanity of the passed messages. 56162306a36Sopenharmony_ci * Uhh, generic i2c layer is more suitable place for such code... 56262306a36Sopenharmony_ci */ 56362306a36Sopenharmony_ci if (unlikely(iic_invalid_address(&msgs[0]))){ 56462306a36Sopenharmony_ci DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx, 56562306a36Sopenharmony_ci msgs[0].addr, msgs[0].flags & I2C_M_TEN ? 10 : 7); 56662306a36Sopenharmony_ci return -EINVAL; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci for (i = 0; i < num; ++i){ 56962306a36Sopenharmony_ci if (unlikely(msgs[i].len <= 0)){ 57062306a36Sopenharmony_ci if (num == 1 && !msgs[0].len){ 57162306a36Sopenharmony_ci /* Special case for I2C_SMBUS_QUICK emulation. 57262306a36Sopenharmony_ci * IBM IIC doesn't support 0-length transactions 57362306a36Sopenharmony_ci * so we have to emulate them using bit-banging. 57462306a36Sopenharmony_ci */ 57562306a36Sopenharmony_ci return iic_smbus_quick(dev, &msgs[0]); 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci DBG("%d: invalid len %d in msg[%d]\n", dev->idx, 57862306a36Sopenharmony_ci msgs[i].len, i); 57962306a36Sopenharmony_ci return -EINVAL; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci if (unlikely(iic_address_neq(&msgs[0], &msgs[i]))){ 58262306a36Sopenharmony_ci DBG("%d: invalid addr in msg[%d]\n", dev->idx, i); 58362306a36Sopenharmony_ci return -EINVAL; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* Check bus state */ 58862306a36Sopenharmony_ci if (unlikely((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE)){ 58962306a36Sopenharmony_ci DBG("%d: iic_xfer, bus is not free\n", dev->idx); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* Usually it means something serious has happened. 59262306a36Sopenharmony_ci * We *cannot* have unfinished previous transfer 59362306a36Sopenharmony_ci * so it doesn't make any sense to try to stop it. 59462306a36Sopenharmony_ci * Probably we were not able to recover from the 59562306a36Sopenharmony_ci * previous error. 59662306a36Sopenharmony_ci * The only *reasonable* thing I can think of here 59762306a36Sopenharmony_ci * is soft reset. --ebs 59862306a36Sopenharmony_ci */ 59962306a36Sopenharmony_ci iic_dev_reset(dev); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){ 60262306a36Sopenharmony_ci DBG("%d: iic_xfer, bus is still not free\n", dev->idx); 60362306a36Sopenharmony_ci return -EREMOTEIO; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci else { 60762306a36Sopenharmony_ci /* Flush master data buffer (just in case) */ 60862306a36Sopenharmony_ci out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB); 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci /* Load slave address */ 61262306a36Sopenharmony_ci iic_address(dev, &msgs[0]); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci /* Do real transfer */ 61562306a36Sopenharmony_ci for (i = 0; i < num && !ret; ++i) 61662306a36Sopenharmony_ci ret = iic_xfer_bytes(dev, &msgs[i], i < num - 1); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci return ret < 0 ? ret : num; 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic u32 iic_func(struct i2c_adapter *adap) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic const struct i2c_algorithm iic_algo = { 62762306a36Sopenharmony_ci .master_xfer = iic_xfer, 62862306a36Sopenharmony_ci .functionality = iic_func 62962306a36Sopenharmony_ci}; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci/* 63262306a36Sopenharmony_ci * Calculates IICx_CLCKDIV value for a specific OPB clock frequency 63362306a36Sopenharmony_ci */ 63462306a36Sopenharmony_cistatic inline u8 iic_clckdiv(unsigned int opb) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci /* Compatibility kludge, should go away after all cards 63762306a36Sopenharmony_ci * are fixed to fill correct value for opbfreq. 63862306a36Sopenharmony_ci * Previous driver version used hardcoded divider value 4, 63962306a36Sopenharmony_ci * it corresponds to OPB frequency from the range (40, 50] MHz 64062306a36Sopenharmony_ci */ 64162306a36Sopenharmony_ci if (!opb){ 64262306a36Sopenharmony_ci printk(KERN_WARNING "ibm-iic: using compatibility value for OPB freq," 64362306a36Sopenharmony_ci " fix your board specific setup\n"); 64462306a36Sopenharmony_ci opb = 50000000; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci /* Convert to MHz */ 64862306a36Sopenharmony_ci opb /= 1000000; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if (opb < 20 || opb > 150){ 65162306a36Sopenharmony_ci printk(KERN_WARNING "ibm-iic: invalid OPB clock frequency %u MHz\n", 65262306a36Sopenharmony_ci opb); 65362306a36Sopenharmony_ci opb = opb < 20 ? 20 : 150; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci return (u8)((opb + 9) / 10 - 1); 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic int iic_request_irq(struct platform_device *ofdev, 65962306a36Sopenharmony_ci struct ibm_iic_private *dev) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci struct device_node *np = ofdev->dev.of_node; 66262306a36Sopenharmony_ci int irq; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (iic_force_poll) 66562306a36Sopenharmony_ci return 0; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci irq = irq_of_parse_and_map(np, 0); 66862306a36Sopenharmony_ci if (!irq) { 66962306a36Sopenharmony_ci dev_err(&ofdev->dev, "irq_of_parse_and_map failed\n"); 67062306a36Sopenharmony_ci return 0; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci /* Disable interrupts until we finish initialization, assumes 67462306a36Sopenharmony_ci * level-sensitive IRQ setup... 67562306a36Sopenharmony_ci */ 67662306a36Sopenharmony_ci iic_interrupt_mode(dev, 0); 67762306a36Sopenharmony_ci if (request_irq(irq, iic_handler, 0, "IBM IIC", dev)) { 67862306a36Sopenharmony_ci dev_err(&ofdev->dev, "request_irq %d failed\n", irq); 67962306a36Sopenharmony_ci /* Fallback to the polling mode */ 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci return irq; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci/* 68762306a36Sopenharmony_ci * Register single IIC interface 68862306a36Sopenharmony_ci */ 68962306a36Sopenharmony_cistatic int iic_probe(struct platform_device *ofdev) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci struct device_node *np = ofdev->dev.of_node; 69262306a36Sopenharmony_ci struct ibm_iic_private *dev; 69362306a36Sopenharmony_ci struct i2c_adapter *adap; 69462306a36Sopenharmony_ci const u32 *freq; 69562306a36Sopenharmony_ci int ret; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci dev = kzalloc(sizeof(*dev), GFP_KERNEL); 69862306a36Sopenharmony_ci if (!dev) 69962306a36Sopenharmony_ci return -ENOMEM; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci platform_set_drvdata(ofdev, dev); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci dev->vaddr = of_iomap(np, 0); 70462306a36Sopenharmony_ci if (dev->vaddr == NULL) { 70562306a36Sopenharmony_ci dev_err(&ofdev->dev, "failed to iomap device\n"); 70662306a36Sopenharmony_ci ret = -ENXIO; 70762306a36Sopenharmony_ci goto error_cleanup; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci init_waitqueue_head(&dev->wq); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci dev->irq = iic_request_irq(ofdev, dev); 71362306a36Sopenharmony_ci if (!dev->irq) 71462306a36Sopenharmony_ci dev_warn(&ofdev->dev, "using polling mode\n"); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci /* Board specific settings */ 71762306a36Sopenharmony_ci if (iic_force_fast || of_get_property(np, "fast-mode", NULL)) 71862306a36Sopenharmony_ci dev->fast_mode = 1; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci freq = of_get_property(np, "clock-frequency", NULL); 72162306a36Sopenharmony_ci if (freq == NULL) { 72262306a36Sopenharmony_ci freq = of_get_property(np->parent, "clock-frequency", NULL); 72362306a36Sopenharmony_ci if (freq == NULL) { 72462306a36Sopenharmony_ci dev_err(&ofdev->dev, "Unable to get bus frequency\n"); 72562306a36Sopenharmony_ci ret = -EINVAL; 72662306a36Sopenharmony_ci goto error_cleanup; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci dev->clckdiv = iic_clckdiv(*freq); 73162306a36Sopenharmony_ci dev_dbg(&ofdev->dev, "clckdiv = %d\n", dev->clckdiv); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci /* Initialize IIC interface */ 73462306a36Sopenharmony_ci iic_dev_init(dev); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* Register it with i2c layer */ 73762306a36Sopenharmony_ci adap = &dev->adap; 73862306a36Sopenharmony_ci adap->dev.parent = &ofdev->dev; 73962306a36Sopenharmony_ci adap->dev.of_node = of_node_get(np); 74062306a36Sopenharmony_ci strscpy(adap->name, "IBM IIC", sizeof(adap->name)); 74162306a36Sopenharmony_ci i2c_set_adapdata(adap, dev); 74262306a36Sopenharmony_ci adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; 74362306a36Sopenharmony_ci adap->algo = &iic_algo; 74462306a36Sopenharmony_ci adap->timeout = HZ; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci ret = i2c_add_adapter(adap); 74762306a36Sopenharmony_ci if (ret < 0) 74862306a36Sopenharmony_ci goto error_cleanup; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci dev_info(&ofdev->dev, "using %s mode\n", 75162306a36Sopenharmony_ci dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)"); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci return 0; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cierror_cleanup: 75662306a36Sopenharmony_ci if (dev->irq) { 75762306a36Sopenharmony_ci iic_interrupt_mode(dev, 0); 75862306a36Sopenharmony_ci free_irq(dev->irq, dev); 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (dev->vaddr) 76262306a36Sopenharmony_ci iounmap(dev->vaddr); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci kfree(dev); 76562306a36Sopenharmony_ci return ret; 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci/* 76962306a36Sopenharmony_ci * Cleanup initialized IIC interface 77062306a36Sopenharmony_ci */ 77162306a36Sopenharmony_cistatic void iic_remove(struct platform_device *ofdev) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci struct ibm_iic_private *dev = platform_get_drvdata(ofdev); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci i2c_del_adapter(&dev->adap); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (dev->irq) { 77862306a36Sopenharmony_ci iic_interrupt_mode(dev, 0); 77962306a36Sopenharmony_ci free_irq(dev->irq, dev); 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci iounmap(dev->vaddr); 78362306a36Sopenharmony_ci kfree(dev); 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cistatic const struct of_device_id ibm_iic_match[] = { 78762306a36Sopenharmony_ci { .compatible = "ibm,iic", }, 78862306a36Sopenharmony_ci {} 78962306a36Sopenharmony_ci}; 79062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ibm_iic_match); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_cistatic struct platform_driver ibm_iic_driver = { 79362306a36Sopenharmony_ci .driver = { 79462306a36Sopenharmony_ci .name = "ibm-iic", 79562306a36Sopenharmony_ci .of_match_table = ibm_iic_match, 79662306a36Sopenharmony_ci }, 79762306a36Sopenharmony_ci .probe = iic_probe, 79862306a36Sopenharmony_ci .remove_new = iic_remove, 79962306a36Sopenharmony_ci}; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cimodule_platform_driver(ibm_iic_driver); 802