// SPDX-License-Identifier: GPL-2.0-or-later /* * drivers/i2c/busses/i2c-ibm_iic.c * * Support for the IIC peripheral on IBM PPC 4xx * * Copyright (c) 2003, 2004 Zultys Technologies. * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> * * Copyright (c) 2008 PIKA Technologies * Sean MacLennan <smaclennan@pikatech.com> * * Based on original work by * Ian DaSilva <idasilva@mvista.com> * Armin Kuster <akuster@mvista.com> * Matt Porter <mporter@mvista.com> * * Copyright 2000-2003 MontaVista Software Inc. * * Original driver version was highly leveraged from i2c-elektor.c * * Copyright 1995-97 Simon G. Vogl * 1998-99 Hans Berglund * * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> * and even Frodo Looijaard <frodol@dds.nl>
*/
/* Only 7-bit addresses are supported */ if (unlikely(p->flags & I2C_M_TEN)){
DBG("%d: smbus_quick - 10 bit addresses are not supported\n",
dev->idx); return -EINVAL;
}
/* Wait for bus to become free */
out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC); if (unlikely(iic_dc_wait(iic, DIRCNTL_MSDA | DIRCNTL_MSC))) goto err;
ndelay(t->buf);
/* * Get controller transfer result and clear errors if any. * Returns the number of actually transferred bytes or error (<0)
*/ staticint iic_xfer_result(struct ibm_iic_private* dev)
{ volatilestruct iic_regs __iomem *iic = dev->vaddr;
/* Clear errors and possible pending IRQs */
out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD |
EXTSTS_LA | EXTSTS_ICT | EXTSTS_XFRA);
/* Flush controller data buffer */
out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
/* Is bus free? * If error happened during combined xfer * IIC interface is usually stuck in some strange * state, the only way out - soft reset.
*/ if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
DBG("%d: bus is stuck, resetting\n", dev->idx);
iic_dev_reset(dev);
} return -EREMOTEIO;
} else return in_8(&iic->xfrcnt) & XFRCNT_MTC_MASK;
}
/* * Wait for the abort command to complete. * It's not worth to be optimized, just poll (timeout >= 1 tick)
*/
x = jiffies + 2; while ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){ if (time_after(jiffies, x)){
DBG("%d: abort timeout, resetting...\n", dev->idx);
iic_dev_reset(dev); return;
}
schedule();
}
/* Just to clear errors */
iic_xfer_result(dev);
}
/* * Wait for controller transfer to complete. * It puts current process to sleep until we get interrupt or timeout expires. * Returns the number of transferred bytes or error (<0)
*/ staticint iic_wait_for_tc(struct ibm_iic_private* dev){
volatilestruct iic_regs __iomem *iic = dev->vaddr; int ret = 0;
if (dev->irq >= 0){ /* Interrupt mode */
ret = wait_event_interruptible_timeout(dev->wq,
!(in_8(&iic->sts) & STS_PT), dev->adap.timeout);
/* * Generic transfer entrypoint. * Returns the number of processed messages or error (<0)
*/ staticint iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{ struct ibm_iic_private* dev = (struct ibm_iic_private*)(i2c_get_adapdata(adap)); volatilestruct iic_regs __iomem *iic = dev->vaddr; int i, ret = 0;
DBG2("%d: iic_xfer, %d msg(s)\n", dev->idx, num);
/* Check the sanity of the passed messages. * Uhh, generic i2c layer is more suitable place for such code...
*/ if (unlikely(iic_invalid_address(&msgs[0]))){
DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx,
msgs[0].addr, msgs[0].flags & I2C_M_TEN ? 10 : 7); return -EINVAL;
} for (i = 0; i < num; ++i){ if (unlikely(msgs[i].len <= 0)){ if (num == 1 && !msgs[0].len){ /* Special case for I2C_SMBUS_QUICK emulation. * IBM IIC doesn't support 0-length transactions * so we have to emulate them using bit-banging.
*/ return iic_smbus_quick(dev, &msgs[0]);
}
DBG("%d: invalid len %d in msg[%d]\n", dev->idx,
msgs[i].len, i); return -EINVAL;
} if (unlikely(iic_address_neq(&msgs[0], &msgs[i]))){
DBG("%d: invalid addr in msg[%d]\n", dev->idx, i); return -EINVAL;
}
}
/* Check bus state */ if (unlikely((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE)){
DBG("%d: iic_xfer, bus is not free\n", dev->idx);
/* Usually it means something serious has happened. * We *cannot* have unfinished previous transfer * so it doesn't make any sense to try to stop it. * Probably we were not able to recover from the * previous error. * The only *reasonable* thing I can think of here * is soft reset. --ebs
*/
iic_dev_reset(dev);
if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
DBG("%d: iic_xfer, bus is still not free\n", dev->idx); return -EREMOTEIO;
}
} else { /* Flush controller data buffer (just in case) */
out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
}
/* * Calculates IICx_CLCKDIV value for a specific OPB clock frequency
*/ staticinline u8 iic_clckdiv(unsignedint opb)
{ /* Compatibility kludge, should go away after all cards * are fixed to fill correct value for opbfreq. * Previous driver version used hardcoded divider value 4, * it corresponds to OPB frequency from the range (40, 50] MHz
*/ if (!opb){
printk(KERN_WARNING "ibm-iic: using compatibility value for OPB freq," " fix your board specific setup\n");
opb = 50000000;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.