// SPDX-License-Identifier: GPL-2.0 /* * This is a combined i2c adapter and algorithm driver for the * MPC107/Tsi107 PowerPC northbridge and processors that include * the same I2C unit (8240, 8245, 85xx). * * Copyright (C) 2003-2004 Humboldt Solutions Ltd, adrian@humboldt.co.uk * Copyright (C) 2021 Allied Telesis Labs
*/
/* Sometimes 9th clock pulse isn't generated, and target doesn't release * the bus, because it wants to send ACK. * Following sequence of enabling/disabling and sending start/stop generates * the 9 pulses, each with a START then ending with STOP, so it's all OK.
*/ staticvoid mpc_i2c_fixup(struct mpc_i2c *i2c)
{ int k; unsignedlong flags;
for (k = 9; k; k--) {
writeccr(i2c, 0);
writeb(0, i2c->base + MPC_I2C_SR); /* clear any status bits */
writeccr(i2c, CCR_MEN | CCR_MSTA); /* START */
readb(i2c->base + MPC_I2C_DR); /* init xfer */
udelay(15); /* let it hit the bus */
local_irq_save(flags); /* should not be delayed further */
writeccr(i2c, CCR_MEN | CCR_MSTA | CCR_RSTA); /* delay SDA */
readb(i2c->base + MPC_I2C_DR); if (k != 1)
udelay(5);
local_irq_restore(flags);
}
writeccr(i2c, CCR_MEN); /* Initiate STOP */
readb(i2c->base + MPC_I2C_DR);
udelay(15); /* Let STOP propagate */
writeccr(i2c, 0);
}
return readb_poll_timeout(addr, val, val & mask, 0, 100);
}
/* * Workaround for Erratum A004447. From the P2040CE Rev Q * * 1. Set up the frequency divider and sampling rate. * 2. I2CCR - a0h * 3. Poll for I2CSR[MBB] to get set. * 4. If I2CSR[MAL] is set (an indication that SDA is stuck low), then go to * step 5. If MAL is not set, then go to step 13. * 5. I2CCR - 00h * 6. I2CCR - 22h * 7. I2CCR - a2h * 8. Poll for I2CSR[MBB] to get set. * 9. Issue read to I2CDR. * 10. Poll for I2CSR[MIF] to be set. * 11. I2CCR - 82h * 12. Workaround complete. Skip the next steps. * 13. Issue read to I2CDR. * 14. Poll for I2CSR[MIF] to be set. * 15. I2CCR - 80h
*/ staticvoid mpc_i2c_fixup_A004447(struct mpc_i2c *i2c)
{ int ret;
u32 val;
writeccr(i2c, CCR_MEN | CCR_MSTA);
ret = i2c_mpc_wait_sr(i2c, CSR_MBB); if (ret) {
dev_err(i2c->dev, "timeout waiting for CSR_MBB\n"); return;
}
val = readb(i2c->base + MPC_I2C_SR);
if (val & CSR_MAL) {
writeccr(i2c, 0x00);
writeccr(i2c, CCR_MSTA | CCR_RSVD);
writeccr(i2c, CCR_MEN | CCR_MSTA | CCR_RSVD);
ret = i2c_mpc_wait_sr(i2c, CSR_MBB); if (ret) {
dev_err(i2c->dev, "timeout waiting for CSR_MBB\n"); return;
}
val = readb(i2c->base + MPC_I2C_DR);
ret = i2c_mpc_wait_sr(i2c, CSR_MIF); if (ret) {
dev_err(i2c->dev, "timeout waiting for CSR_MIF\n"); return;
}
writeccr(i2c, CCR_MEN | CCR_RSVD);
} else {
val = readb(i2c->base + MPC_I2C_DR);
ret = i2c_mpc_wait_sr(i2c, CSR_MIF); if (ret) {
dev_err(i2c->dev, "timeout waiting for CSR_MIF\n"); return;
}
writeccr(i2c, CCR_MEN);
}
}
if (clock == MPC_I2C_CLOCK_LEGACY) { /* see below - default fdr = 0x3f -> div = 2048 */
*real_clk = mpc5xxx_fwnode_get_bus_frequency(fwnode) / 2048; return -EINVAL;
}
/* Determine divider value */
divider = mpc5xxx_fwnode_get_bus_frequency(fwnode) / clock;
/* * We want to choose an FDR/DFSR that generates an I2C bus speed that * is equal to or lower than the requested speed.
*/ for (i = 0; i < ARRAY_SIZE(mpc_i2c_dividers_52xx); i++) {
div = &mpc_i2c_dividers_52xx[i]; /* Old MPC5200 rev A CPUs do not support the high bits */ if (div->fdr & 0xc0 && pvr == 0x80822011) continue; if (div->divider >= divider) break;
}
/* The clock setup for the 52xx works also fine for the 512x */
mpc_i2c_setup_52xx(node, i2c, clock);
} #else/* CONFIG_PPC_MPC512x */ staticvoid mpc_i2c_setup_512x(struct device_node *node, struct mpc_i2c *i2c,
u32 clock)
{
} #endif/* CONFIG_PPC_MPC512x */
struct device_node *node __free(device_node) =
of_find_node_by_name(NULL, "global-utilities"); if (node) { const u32 *prop = of_get_property(node, "reg", NULL); if (prop) { /* * Map and check POR Device Status Register 2 * (PORDEVSR2) at 0xE0014. Note than while MPC8533 * and MPC8544 indicate SEC frequency ratio * configuration as bit 26 in PORDEVSR2, other MPC8xxx * parts may store it differently or may not have it * at all.
*/
reg = ioremap(get_immrbase() + *prop + 0x14, 0x4); if (!reg)
printk(KERN_ERR "Error: couldn't map PORDEVSR2\n"); else
val = in_be32(reg) & 0x00000020; /* sec-cfg */
iounmap(reg);
}
}
return val;
}
static u32 mpc_i2c_get_prescaler_8xxx(void)
{ /* * According to the AN2919 all MPC824x have prescaler 1, while MPC83xx * may have prescaler 1, 2, or 3, depending on the power-on * configuration.
*/
u32 prescaler = 1;
/* * We want to choose an FDR/DFSR that generates an I2C bus speed that * is equal to or lower than the requested speed.
*/ for (i = 0; i < ARRAY_SIZE(mpc_i2c_dividers_8xxx); i++) {
div = &mpc_i2c_dividers_8xxx[i]; if (div->divider >= divider) break;
}
case MPC_I2C_ACTION_READ_BYTE: if (i2c->byte_posn || !recv_len) { /* Generate Tx ACK on next to last byte */ if (i2c->byte_posn == msg->len - 2)
i2c->cntl_bits |= CCR_TXAK; /* Do not generate stop on last byte */ if (i2c->byte_posn == msg->len - 1)
i2c->cntl_bits |= CCR_MTX;
writeccr(i2c, i2c->cntl_bits);
}
byte = readb(i2c->base + MPC_I2C_DR);
if (i2c->byte_posn == 0 && recv_len) { if (byte == 0 || byte > I2C_SMBUS_BLOCK_MAX) {
mpc_i2c_finish(i2c, -EPROTO); return;
}
msg->len += byte; /* * For block reads, generate Tx ACK here if data length * is 1 byte (total length is 2 bytes).
*/ if (msg->len == 2) {
i2c->cntl_bits |= CCR_TXAK;
writeccr(i2c, i2c->cntl_bits);
}
}
if (i2c->curr_msg == i2c->num_msgs) {
i2c->action = MPC_I2C_ACTION_STOP; /* * We don't get another interrupt on read so * finish the transfer now
*/ if (dir)
mpc_i2c_finish(i2c, 0);
} else {
i2c->action = MPC_I2C_ACTION_RESTART;
}
}
}
orig_jiffies = jiffies; /* Wait until STOP is seen, allow up to 1 s */ while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) { if (time_after(jiffies, orig_jiffies + HZ)) {
u8 status = readb(i2c->base + MPC_I2C_SR);
i2c->base = devm_platform_ioremap_resource(op, 0); if (IS_ERR(i2c->base)) return PTR_ERR(i2c->base);
i2c->irq = platform_get_irq(op, 0); if (i2c->irq < 0) return i2c->irq;
result = devm_request_irq(&op->dev, i2c->irq, mpc_i2c_isr,
IRQF_SHARED, "i2c-mpc", i2c); if (result < 0) {
dev_err(i2c->dev, "failed to attach interrupt\n"); return result;
}
/* * enable clock for the I2C peripheral (non fatal), * keep a reference upon successful allocation
*/
clk = devm_clk_get_optional_enabled(&op->dev, NULL); if (IS_ERR(clk)) {
dev_err(&op->dev, "failed to enable clock\n"); return PTR_ERR(clk);
}
if (of_property_read_bool(op->dev.of_node, "fsl,preserve-clocking")) {
clock = MPC_I2C_CLOCK_PRESERVE;
} else {
result = of_property_read_u32(op->dev.of_node, "clock-frequency", &clock); if (result)
clock = MPC_I2C_CLOCK_LEGACY;
}
data = device_get_match_data(&op->dev); if (data) {
data->setup(op->dev.of_node, i2c, clock);
} else { /* Backwards compatibility */ if (of_property_read_bool(op->dev.of_node, "dfsrr"))
mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock);
}
/* Sadly, we have to support two deprecated bindings here */
result = of_property_read_u32(op->dev.of_node, "i2c-transfer-timeout-us",
&mpc_ops.timeout); if (result == -EINVAL)
result = of_property_read_u32(op->dev.of_node, "i2c-scl-clk-low-timeout-us",
&mpc_ops.timeout); if (result == -EINVAL)
result = of_property_read_u32(op->dev.of_node, "fsl,timeout", &mpc_ops.timeout);
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.