18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * (C) Copyright 2003-2004 38c2ecf20Sopenharmony_ci * Humboldt Solutions Ltd, adrian@humboldt.co.uk. 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci * This is a combined i2c adapter and algorithm driver for the 68c2ecf20Sopenharmony_ci * MPC107/Tsi107 PowerPC northbridge and processors that include 78c2ecf20Sopenharmony_ci * the same I2C unit (8240, 8245, 85xx). 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Release 0.8 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public 128c2ecf20Sopenharmony_ci * License version 2. This program is licensed "as is" without any 138c2ecf20Sopenharmony_ci * warranty of any kind, whether express or implied. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 198c2ecf20Sopenharmony_ci#include <linux/of_address.h> 208c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 218c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 228c2ecf20Sopenharmony_ci#include <linux/slab.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/clk.h> 258c2ecf20Sopenharmony_ci#include <linux/io.h> 268c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 278c2ecf20Sopenharmony_ci#include <linux/fsl_devices.h> 288c2ecf20Sopenharmony_ci#include <linux/i2c.h> 298c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 308c2ecf20Sopenharmony_ci#include <linux/delay.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include <asm/mpc52xx.h> 338c2ecf20Sopenharmony_ci#include <asm/mpc85xx.h> 348c2ecf20Sopenharmony_ci#include <sysdev/fsl_soc.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define DRV_NAME "mpc-i2c" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define MPC_I2C_CLOCK_LEGACY 0 398c2ecf20Sopenharmony_ci#define MPC_I2C_CLOCK_PRESERVE (~0U) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define MPC_I2C_FDR 0x04 428c2ecf20Sopenharmony_ci#define MPC_I2C_CR 0x08 438c2ecf20Sopenharmony_ci#define MPC_I2C_SR 0x0c 448c2ecf20Sopenharmony_ci#define MPC_I2C_DR 0x10 458c2ecf20Sopenharmony_ci#define MPC_I2C_DFSRR 0x14 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define CCR_MEN 0x80 488c2ecf20Sopenharmony_ci#define CCR_MIEN 0x40 498c2ecf20Sopenharmony_ci#define CCR_MSTA 0x20 508c2ecf20Sopenharmony_ci#define CCR_MTX 0x10 518c2ecf20Sopenharmony_ci#define CCR_TXAK 0x08 528c2ecf20Sopenharmony_ci#define CCR_RSTA 0x04 538c2ecf20Sopenharmony_ci#define CCR_RSVD 0x02 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define CSR_MCF 0x80 568c2ecf20Sopenharmony_ci#define CSR_MAAS 0x40 578c2ecf20Sopenharmony_ci#define CSR_MBB 0x20 588c2ecf20Sopenharmony_ci#define CSR_MAL 0x10 598c2ecf20Sopenharmony_ci#define CSR_SRW 0x04 608c2ecf20Sopenharmony_ci#define CSR_MIF 0x02 618c2ecf20Sopenharmony_ci#define CSR_RXAK 0x01 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistruct mpc_i2c { 648c2ecf20Sopenharmony_ci struct device *dev; 658c2ecf20Sopenharmony_ci void __iomem *base; 668c2ecf20Sopenharmony_ci u32 interrupt; 678c2ecf20Sopenharmony_ci wait_queue_head_t queue; 688c2ecf20Sopenharmony_ci struct i2c_adapter adap; 698c2ecf20Sopenharmony_ci int irq; 708c2ecf20Sopenharmony_ci u32 real_clk; 718c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 728c2ecf20Sopenharmony_ci u8 fdr, dfsrr; 738c2ecf20Sopenharmony_ci#endif 748c2ecf20Sopenharmony_ci struct clk *clk_per; 758c2ecf20Sopenharmony_ci bool has_errata_A004447; 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistruct mpc_i2c_divider { 798c2ecf20Sopenharmony_ci u16 divider; 808c2ecf20Sopenharmony_ci u16 fdr; /* including dfsrr */ 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistruct mpc_i2c_data { 848c2ecf20Sopenharmony_ci void (*setup)(struct device_node *node, struct mpc_i2c *i2c, u32 clock); 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic inline void writeccr(struct mpc_i2c *i2c, u32 x) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci writeb(x, i2c->base + MPC_I2C_CR); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic irqreturn_t mpc_i2c_isr(int irq, void *dev_id) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci struct mpc_i2c *i2c = dev_id; 958c2ecf20Sopenharmony_ci if (readb(i2c->base + MPC_I2C_SR) & CSR_MIF) { 968c2ecf20Sopenharmony_ci /* Read again to allow register to stabilise */ 978c2ecf20Sopenharmony_ci i2c->interrupt = readb(i2c->base + MPC_I2C_SR); 988c2ecf20Sopenharmony_ci writeb(0, i2c->base + MPC_I2C_SR); 998c2ecf20Sopenharmony_ci wake_up(&i2c->queue); 1008c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci return IRQ_NONE; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* Sometimes 9th clock pulse isn't generated, and slave doesn't release 1068c2ecf20Sopenharmony_ci * the bus, because it wants to send ACK. 1078c2ecf20Sopenharmony_ci * Following sequence of enabling/disabling and sending start/stop generates 1088c2ecf20Sopenharmony_ci * the 9 pulses, each with a START then ending with STOP, so it's all OK. 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_cistatic void mpc_i2c_fixup(struct mpc_i2c *i2c) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci int k; 1138c2ecf20Sopenharmony_ci unsigned long flags; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci for (k = 9; k; k--) { 1168c2ecf20Sopenharmony_ci writeccr(i2c, 0); 1178c2ecf20Sopenharmony_ci writeb(0, i2c->base + MPC_I2C_SR); /* clear any status bits */ 1188c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MEN | CCR_MSTA); /* START */ 1198c2ecf20Sopenharmony_ci readb(i2c->base + MPC_I2C_DR); /* init xfer */ 1208c2ecf20Sopenharmony_ci udelay(15); /* let it hit the bus */ 1218c2ecf20Sopenharmony_ci local_irq_save(flags); /* should not be delayed further */ 1228c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MEN | CCR_MSTA | CCR_RSTA); /* delay SDA */ 1238c2ecf20Sopenharmony_ci readb(i2c->base + MPC_I2C_DR); 1248c2ecf20Sopenharmony_ci if (k != 1) 1258c2ecf20Sopenharmony_ci udelay(5); 1268c2ecf20Sopenharmony_ci local_irq_restore(flags); 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MEN); /* Initiate STOP */ 1298c2ecf20Sopenharmony_ci readb(i2c->base + MPC_I2C_DR); 1308c2ecf20Sopenharmony_ci udelay(15); /* Let STOP propagate */ 1318c2ecf20Sopenharmony_ci writeccr(i2c, 0); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci unsigned long orig_jiffies = jiffies; 1378c2ecf20Sopenharmony_ci u32 cmd_err; 1388c2ecf20Sopenharmony_ci int result = 0; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (!i2c->irq) { 1418c2ecf20Sopenharmony_ci while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) { 1428c2ecf20Sopenharmony_ci schedule(); 1438c2ecf20Sopenharmony_ci if (time_after(jiffies, orig_jiffies + timeout)) { 1448c2ecf20Sopenharmony_ci dev_dbg(i2c->dev, "timeout\n"); 1458c2ecf20Sopenharmony_ci writeccr(i2c, 0); 1468c2ecf20Sopenharmony_ci result = -ETIMEDOUT; 1478c2ecf20Sopenharmony_ci break; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci cmd_err = readb(i2c->base + MPC_I2C_SR); 1518c2ecf20Sopenharmony_ci writeb(0, i2c->base + MPC_I2C_SR); 1528c2ecf20Sopenharmony_ci } else { 1538c2ecf20Sopenharmony_ci /* Interrupt mode */ 1548c2ecf20Sopenharmony_ci result = wait_event_timeout(i2c->queue, 1558c2ecf20Sopenharmony_ci (i2c->interrupt & CSR_MIF), timeout); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (unlikely(!(i2c->interrupt & CSR_MIF))) { 1588c2ecf20Sopenharmony_ci dev_dbg(i2c->dev, "wait timeout\n"); 1598c2ecf20Sopenharmony_ci writeccr(i2c, 0); 1608c2ecf20Sopenharmony_ci result = -ETIMEDOUT; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci cmd_err = i2c->interrupt; 1648c2ecf20Sopenharmony_ci i2c->interrupt = 0; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (result < 0) 1688c2ecf20Sopenharmony_ci return result; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (!(cmd_err & CSR_MCF)) { 1718c2ecf20Sopenharmony_ci dev_dbg(i2c->dev, "unfinished\n"); 1728c2ecf20Sopenharmony_ci return -EIO; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (cmd_err & CSR_MAL) { 1768c2ecf20Sopenharmony_ci dev_dbg(i2c->dev, "MAL\n"); 1778c2ecf20Sopenharmony_ci return -EAGAIN; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (writing && (cmd_err & CSR_RXAK)) { 1818c2ecf20Sopenharmony_ci dev_dbg(i2c->dev, "No RXAK\n"); 1828c2ecf20Sopenharmony_ci /* generate stop */ 1838c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MEN); 1848c2ecf20Sopenharmony_ci return -ENXIO; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic int i2c_mpc_wait_sr(struct mpc_i2c *i2c, int mask) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci void __iomem *addr = i2c->base + MPC_I2C_SR; 1928c2ecf20Sopenharmony_ci u8 val; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return readb_poll_timeout(addr, val, val & mask, 0, 100); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci/* 1988c2ecf20Sopenharmony_ci * Workaround for Erratum A004447. From the P2040CE Rev Q 1998c2ecf20Sopenharmony_ci * 2008c2ecf20Sopenharmony_ci * 1. Set up the frequency divider and sampling rate. 2018c2ecf20Sopenharmony_ci * 2. I2CCR - a0h 2028c2ecf20Sopenharmony_ci * 3. Poll for I2CSR[MBB] to get set. 2038c2ecf20Sopenharmony_ci * 4. If I2CSR[MAL] is set (an indication that SDA is stuck low), then go to 2048c2ecf20Sopenharmony_ci * step 5. If MAL is not set, then go to step 13. 2058c2ecf20Sopenharmony_ci * 5. I2CCR - 00h 2068c2ecf20Sopenharmony_ci * 6. I2CCR - 22h 2078c2ecf20Sopenharmony_ci * 7. I2CCR - a2h 2088c2ecf20Sopenharmony_ci * 8. Poll for I2CSR[MBB] to get set. 2098c2ecf20Sopenharmony_ci * 9. Issue read to I2CDR. 2108c2ecf20Sopenharmony_ci * 10. Poll for I2CSR[MIF] to be set. 2118c2ecf20Sopenharmony_ci * 11. I2CCR - 82h 2128c2ecf20Sopenharmony_ci * 12. Workaround complete. Skip the next steps. 2138c2ecf20Sopenharmony_ci * 13. Issue read to I2CDR. 2148c2ecf20Sopenharmony_ci * 14. Poll for I2CSR[MIF] to be set. 2158c2ecf20Sopenharmony_ci * 15. I2CCR - 80h 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_cistatic void mpc_i2c_fixup_A004447(struct mpc_i2c *i2c) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci int ret; 2208c2ecf20Sopenharmony_ci u32 val; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MEN | CCR_MSTA); 2238c2ecf20Sopenharmony_ci ret = i2c_mpc_wait_sr(i2c, CSR_MBB); 2248c2ecf20Sopenharmony_ci if (ret) { 2258c2ecf20Sopenharmony_ci dev_err(i2c->dev, "timeout waiting for CSR_MBB\n"); 2268c2ecf20Sopenharmony_ci return; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci val = readb(i2c->base + MPC_I2C_SR); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (val & CSR_MAL) { 2328c2ecf20Sopenharmony_ci writeccr(i2c, 0x00); 2338c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MSTA | CCR_RSVD); 2348c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MEN | CCR_MSTA | CCR_RSVD); 2358c2ecf20Sopenharmony_ci ret = i2c_mpc_wait_sr(i2c, CSR_MBB); 2368c2ecf20Sopenharmony_ci if (ret) { 2378c2ecf20Sopenharmony_ci dev_err(i2c->dev, "timeout waiting for CSR_MBB\n"); 2388c2ecf20Sopenharmony_ci return; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci val = readb(i2c->base + MPC_I2C_DR); 2418c2ecf20Sopenharmony_ci ret = i2c_mpc_wait_sr(i2c, CSR_MIF); 2428c2ecf20Sopenharmony_ci if (ret) { 2438c2ecf20Sopenharmony_ci dev_err(i2c->dev, "timeout waiting for CSR_MIF\n"); 2448c2ecf20Sopenharmony_ci return; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MEN | CCR_RSVD); 2478c2ecf20Sopenharmony_ci } else { 2488c2ecf20Sopenharmony_ci val = readb(i2c->base + MPC_I2C_DR); 2498c2ecf20Sopenharmony_ci ret = i2c_mpc_wait_sr(i2c, CSR_MIF); 2508c2ecf20Sopenharmony_ci if (ret) { 2518c2ecf20Sopenharmony_ci dev_err(i2c->dev, "timeout waiting for CSR_MIF\n"); 2528c2ecf20Sopenharmony_ci return; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MEN); 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci#if defined(CONFIG_PPC_MPC52xx) || defined(CONFIG_PPC_MPC512x) 2598c2ecf20Sopenharmony_cistatic const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = { 2608c2ecf20Sopenharmony_ci {20, 0x20}, {22, 0x21}, {24, 0x22}, {26, 0x23}, 2618c2ecf20Sopenharmony_ci {28, 0x24}, {30, 0x01}, {32, 0x25}, {34, 0x02}, 2628c2ecf20Sopenharmony_ci {36, 0x26}, {40, 0x27}, {44, 0x04}, {48, 0x28}, 2638c2ecf20Sopenharmony_ci {52, 0x63}, {56, 0x29}, {60, 0x41}, {64, 0x2a}, 2648c2ecf20Sopenharmony_ci {68, 0x07}, {72, 0x2b}, {80, 0x2c}, {88, 0x09}, 2658c2ecf20Sopenharmony_ci {96, 0x2d}, {104, 0x0a}, {112, 0x2e}, {120, 0x81}, 2668c2ecf20Sopenharmony_ci {128, 0x2f}, {136, 0x47}, {144, 0x0c}, {160, 0x30}, 2678c2ecf20Sopenharmony_ci {176, 0x49}, {192, 0x31}, {208, 0x4a}, {224, 0x32}, 2688c2ecf20Sopenharmony_ci {240, 0x0f}, {256, 0x33}, {272, 0x87}, {288, 0x10}, 2698c2ecf20Sopenharmony_ci {320, 0x34}, {352, 0x89}, {384, 0x35}, {416, 0x8a}, 2708c2ecf20Sopenharmony_ci {448, 0x36}, {480, 0x13}, {512, 0x37}, {576, 0x14}, 2718c2ecf20Sopenharmony_ci {640, 0x38}, {768, 0x39}, {896, 0x3a}, {960, 0x17}, 2728c2ecf20Sopenharmony_ci {1024, 0x3b}, {1152, 0x18}, {1280, 0x3c}, {1536, 0x3d}, 2738c2ecf20Sopenharmony_ci {1792, 0x3e}, {1920, 0x1b}, {2048, 0x3f}, {2304, 0x1c}, 2748c2ecf20Sopenharmony_ci {2560, 0x1d}, {3072, 0x1e}, {3584, 0x7e}, {3840, 0x1f}, 2758c2ecf20Sopenharmony_ci {4096, 0x7f}, {4608, 0x5c}, {5120, 0x5d}, {6144, 0x5e}, 2768c2ecf20Sopenharmony_ci {7168, 0xbe}, {7680, 0x5f}, {8192, 0xbf}, {9216, 0x9c}, 2778c2ecf20Sopenharmony_ci {10240, 0x9d}, {12288, 0x9e}, {15360, 0x9f} 2788c2ecf20Sopenharmony_ci}; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, 2818c2ecf20Sopenharmony_ci u32 *real_clk) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci const struct mpc_i2c_divider *div = NULL; 2848c2ecf20Sopenharmony_ci unsigned int pvr = mfspr(SPRN_PVR); 2858c2ecf20Sopenharmony_ci u32 divider; 2868c2ecf20Sopenharmony_ci int i; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (clock == MPC_I2C_CLOCK_LEGACY) { 2898c2ecf20Sopenharmony_ci /* see below - default fdr = 0x3f -> div = 2048 */ 2908c2ecf20Sopenharmony_ci *real_clk = mpc5xxx_get_bus_frequency(node) / 2048; 2918c2ecf20Sopenharmony_ci return -EINVAL; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* Determine divider value */ 2958c2ecf20Sopenharmony_ci divider = mpc5xxx_get_bus_frequency(node) / clock; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* 2988c2ecf20Sopenharmony_ci * We want to choose an FDR/DFSR that generates an I2C bus speed that 2998c2ecf20Sopenharmony_ci * is equal to or lower than the requested speed. 3008c2ecf20Sopenharmony_ci */ 3018c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mpc_i2c_dividers_52xx); i++) { 3028c2ecf20Sopenharmony_ci div = &mpc_i2c_dividers_52xx[i]; 3038c2ecf20Sopenharmony_ci /* Old MPC5200 rev A CPUs do not support the high bits */ 3048c2ecf20Sopenharmony_ci if (div->fdr & 0xc0 && pvr == 0x80822011) 3058c2ecf20Sopenharmony_ci continue; 3068c2ecf20Sopenharmony_ci if (div->divider >= divider) 3078c2ecf20Sopenharmony_ci break; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci *real_clk = mpc5xxx_get_bus_frequency(node) / div->divider; 3118c2ecf20Sopenharmony_ci return (int)div->fdr; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic void mpc_i2c_setup_52xx(struct device_node *node, 3158c2ecf20Sopenharmony_ci struct mpc_i2c *i2c, 3168c2ecf20Sopenharmony_ci u32 clock) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci int ret, fdr; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (clock == MPC_I2C_CLOCK_PRESERVE) { 3218c2ecf20Sopenharmony_ci dev_dbg(i2c->dev, "using fdr %d\n", 3228c2ecf20Sopenharmony_ci readb(i2c->base + MPC_I2C_FDR)); 3238c2ecf20Sopenharmony_ci return; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci ret = mpc_i2c_get_fdr_52xx(node, clock, &i2c->real_clk); 3278c2ecf20Sopenharmony_ci fdr = (ret >= 0) ? ret : 0x3f; /* backward compatibility */ 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (ret >= 0) 3328c2ecf20Sopenharmony_ci dev_info(i2c->dev, "clock %u Hz (fdr=%d)\n", i2c->real_clk, 3338c2ecf20Sopenharmony_ci fdr); 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci#else /* !(CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x) */ 3368c2ecf20Sopenharmony_cistatic void mpc_i2c_setup_52xx(struct device_node *node, 3378c2ecf20Sopenharmony_ci struct mpc_i2c *i2c, 3388c2ecf20Sopenharmony_ci u32 clock) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x */ 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_MPC512x 3448c2ecf20Sopenharmony_cistatic void mpc_i2c_setup_512x(struct device_node *node, 3458c2ecf20Sopenharmony_ci struct mpc_i2c *i2c, 3468c2ecf20Sopenharmony_ci u32 clock) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct device_node *node_ctrl; 3498c2ecf20Sopenharmony_ci void __iomem *ctrl; 3508c2ecf20Sopenharmony_ci const u32 *pval; 3518c2ecf20Sopenharmony_ci u32 idx; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* Enable I2C interrupts for mpc5121 */ 3548c2ecf20Sopenharmony_ci node_ctrl = of_find_compatible_node(NULL, NULL, 3558c2ecf20Sopenharmony_ci "fsl,mpc5121-i2c-ctrl"); 3568c2ecf20Sopenharmony_ci if (node_ctrl) { 3578c2ecf20Sopenharmony_ci ctrl = of_iomap(node_ctrl, 0); 3588c2ecf20Sopenharmony_ci if (ctrl) { 3598c2ecf20Sopenharmony_ci /* Interrupt enable bits for i2c-0/1/2: bit 24/26/28 */ 3608c2ecf20Sopenharmony_ci pval = of_get_property(node, "reg", NULL); 3618c2ecf20Sopenharmony_ci idx = (*pval & 0xff) / 0x20; 3628c2ecf20Sopenharmony_ci setbits32(ctrl, 1 << (24 + idx * 2)); 3638c2ecf20Sopenharmony_ci iounmap(ctrl); 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci of_node_put(node_ctrl); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* The clock setup for the 52xx works also fine for the 512x */ 3698c2ecf20Sopenharmony_ci mpc_i2c_setup_52xx(node, i2c, clock); 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci#else /* CONFIG_PPC_MPC512x */ 3728c2ecf20Sopenharmony_cistatic void mpc_i2c_setup_512x(struct device_node *node, 3738c2ecf20Sopenharmony_ci struct mpc_i2c *i2c, 3748c2ecf20Sopenharmony_ci u32 clock) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_MPC512x */ 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_SOC 3808c2ecf20Sopenharmony_cistatic const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = { 3818c2ecf20Sopenharmony_ci {160, 0x0120}, {192, 0x0121}, {224, 0x0122}, {256, 0x0123}, 3828c2ecf20Sopenharmony_ci {288, 0x0100}, {320, 0x0101}, {352, 0x0601}, {384, 0x0102}, 3838c2ecf20Sopenharmony_ci {416, 0x0602}, {448, 0x0126}, {480, 0x0103}, {512, 0x0127}, 3848c2ecf20Sopenharmony_ci {544, 0x0b03}, {576, 0x0104}, {608, 0x1603}, {640, 0x0105}, 3858c2ecf20Sopenharmony_ci {672, 0x2003}, {704, 0x0b05}, {736, 0x2b03}, {768, 0x0106}, 3868c2ecf20Sopenharmony_ci {800, 0x3603}, {832, 0x0b06}, {896, 0x012a}, {960, 0x0107}, 3878c2ecf20Sopenharmony_ci {1024, 0x012b}, {1088, 0x1607}, {1152, 0x0108}, {1216, 0x2b07}, 3888c2ecf20Sopenharmony_ci {1280, 0x0109}, {1408, 0x1609}, {1536, 0x010a}, {1664, 0x160a}, 3898c2ecf20Sopenharmony_ci {1792, 0x012e}, {1920, 0x010b}, {2048, 0x012f}, {2176, 0x2b0b}, 3908c2ecf20Sopenharmony_ci {2304, 0x010c}, {2560, 0x010d}, {2816, 0x2b0d}, {3072, 0x010e}, 3918c2ecf20Sopenharmony_ci {3328, 0x2b0e}, {3584, 0x0132}, {3840, 0x010f}, {4096, 0x0133}, 3928c2ecf20Sopenharmony_ci {4608, 0x0110}, {5120, 0x0111}, {6144, 0x0112}, {7168, 0x0136}, 3938c2ecf20Sopenharmony_ci {7680, 0x0113}, {8192, 0x0137}, {9216, 0x0114}, {10240, 0x0115}, 3948c2ecf20Sopenharmony_ci {12288, 0x0116}, {14336, 0x013a}, {15360, 0x0117}, {16384, 0x013b}, 3958c2ecf20Sopenharmony_ci {18432, 0x0118}, {20480, 0x0119}, {24576, 0x011a}, {28672, 0x013e}, 3968c2ecf20Sopenharmony_ci {30720, 0x011b}, {32768, 0x013f}, {36864, 0x011c}, {40960, 0x011d}, 3978c2ecf20Sopenharmony_ci {49152, 0x011e}, {61440, 0x011f} 3988c2ecf20Sopenharmony_ci}; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic u32 mpc_i2c_get_sec_cfg_8xxx(void) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct device_node *node; 4038c2ecf20Sopenharmony_ci u32 __iomem *reg; 4048c2ecf20Sopenharmony_ci u32 val = 0; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci node = of_find_node_by_name(NULL, "global-utilities"); 4078c2ecf20Sopenharmony_ci if (node) { 4088c2ecf20Sopenharmony_ci const u32 *prop = of_get_property(node, "reg", NULL); 4098c2ecf20Sopenharmony_ci if (prop) { 4108c2ecf20Sopenharmony_ci /* 4118c2ecf20Sopenharmony_ci * Map and check POR Device Status Register 2 4128c2ecf20Sopenharmony_ci * (PORDEVSR2) at 0xE0014. Note than while MPC8533 4138c2ecf20Sopenharmony_ci * and MPC8544 indicate SEC frequency ratio 4148c2ecf20Sopenharmony_ci * configuration as bit 26 in PORDEVSR2, other MPC8xxx 4158c2ecf20Sopenharmony_ci * parts may store it differently or may not have it 4168c2ecf20Sopenharmony_ci * at all. 4178c2ecf20Sopenharmony_ci */ 4188c2ecf20Sopenharmony_ci reg = ioremap(get_immrbase() + *prop + 0x14, 0x4); 4198c2ecf20Sopenharmony_ci if (!reg) 4208c2ecf20Sopenharmony_ci printk(KERN_ERR 4218c2ecf20Sopenharmony_ci "Error: couldn't map PORDEVSR2\n"); 4228c2ecf20Sopenharmony_ci else 4238c2ecf20Sopenharmony_ci val = in_be32(reg) & 0x00000020; /* sec-cfg */ 4248c2ecf20Sopenharmony_ci iounmap(reg); 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci of_node_put(node); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci return val; 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic u32 mpc_i2c_get_prescaler_8xxx(void) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci /* 4358c2ecf20Sopenharmony_ci * According to the AN2919 all MPC824x have prescaler 1, while MPC83xx 4368c2ecf20Sopenharmony_ci * may have prescaler 1, 2, or 3, depending on the power-on 4378c2ecf20Sopenharmony_ci * configuration. 4388c2ecf20Sopenharmony_ci */ 4398c2ecf20Sopenharmony_ci u32 prescaler = 1; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* mpc85xx */ 4428c2ecf20Sopenharmony_ci if (pvr_version_is(PVR_VER_E500V1) || pvr_version_is(PVR_VER_E500V2) 4438c2ecf20Sopenharmony_ci || pvr_version_is(PVR_VER_E500MC) 4448c2ecf20Sopenharmony_ci || pvr_version_is(PVR_VER_E5500) 4458c2ecf20Sopenharmony_ci || pvr_version_is(PVR_VER_E6500)) { 4468c2ecf20Sopenharmony_ci unsigned int svr = mfspr(SPRN_SVR); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if ((SVR_SOC_VER(svr) == SVR_8540) 4498c2ecf20Sopenharmony_ci || (SVR_SOC_VER(svr) == SVR_8541) 4508c2ecf20Sopenharmony_ci || (SVR_SOC_VER(svr) == SVR_8560) 4518c2ecf20Sopenharmony_ci || (SVR_SOC_VER(svr) == SVR_8555) 4528c2ecf20Sopenharmony_ci || (SVR_SOC_VER(svr) == SVR_8610)) 4538c2ecf20Sopenharmony_ci /* the above 85xx SoCs have prescaler 1 */ 4548c2ecf20Sopenharmony_ci prescaler = 1; 4558c2ecf20Sopenharmony_ci else if ((SVR_SOC_VER(svr) == SVR_8533) 4568c2ecf20Sopenharmony_ci || (SVR_SOC_VER(svr) == SVR_8544)) 4578c2ecf20Sopenharmony_ci /* the above 85xx SoCs have prescaler 3 or 2 */ 4588c2ecf20Sopenharmony_ci prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2; 4598c2ecf20Sopenharmony_ci else 4608c2ecf20Sopenharmony_ci /* all the other 85xx have prescaler 2 */ 4618c2ecf20Sopenharmony_ci prescaler = 2; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci return prescaler; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, 4688c2ecf20Sopenharmony_ci u32 *real_clk) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci const struct mpc_i2c_divider *div = NULL; 4718c2ecf20Sopenharmony_ci u32 prescaler = mpc_i2c_get_prescaler_8xxx(); 4728c2ecf20Sopenharmony_ci u32 divider; 4738c2ecf20Sopenharmony_ci int i; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (clock == MPC_I2C_CLOCK_LEGACY) { 4768c2ecf20Sopenharmony_ci /* see below - default fdr = 0x1031 -> div = 16 * 3072 */ 4778c2ecf20Sopenharmony_ci *real_clk = fsl_get_sys_freq() / prescaler / (16 * 3072); 4788c2ecf20Sopenharmony_ci return -EINVAL; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci divider = fsl_get_sys_freq() / clock / prescaler; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci pr_debug("I2C: src_clock=%d clock=%d divider=%d\n", 4848c2ecf20Sopenharmony_ci fsl_get_sys_freq(), clock, divider); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci /* 4878c2ecf20Sopenharmony_ci * We want to choose an FDR/DFSR that generates an I2C bus speed that 4888c2ecf20Sopenharmony_ci * is equal to or lower than the requested speed. 4898c2ecf20Sopenharmony_ci */ 4908c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mpc_i2c_dividers_8xxx); i++) { 4918c2ecf20Sopenharmony_ci div = &mpc_i2c_dividers_8xxx[i]; 4928c2ecf20Sopenharmony_ci if (div->divider >= divider) 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci *real_clk = fsl_get_sys_freq() / prescaler / div->divider; 4978c2ecf20Sopenharmony_ci return div ? (int)div->fdr : -EINVAL; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic void mpc_i2c_setup_8xxx(struct device_node *node, 5018c2ecf20Sopenharmony_ci struct mpc_i2c *i2c, 5028c2ecf20Sopenharmony_ci u32 clock) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci int ret, fdr; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (clock == MPC_I2C_CLOCK_PRESERVE) { 5078c2ecf20Sopenharmony_ci dev_dbg(i2c->dev, "using dfsrr %d, fdr %d\n", 5088c2ecf20Sopenharmony_ci readb(i2c->base + MPC_I2C_DFSRR), 5098c2ecf20Sopenharmony_ci readb(i2c->base + MPC_I2C_FDR)); 5108c2ecf20Sopenharmony_ci return; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci ret = mpc_i2c_get_fdr_8xxx(node, clock, &i2c->real_clk); 5148c2ecf20Sopenharmony_ci fdr = (ret >= 0) ? ret : 0x1031; /* backward compatibility */ 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR); 5178c2ecf20Sopenharmony_ci writeb((fdr >> 8) & 0xff, i2c->base + MPC_I2C_DFSRR); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (ret >= 0) 5208c2ecf20Sopenharmony_ci dev_info(i2c->dev, "clock %d Hz (dfsrr=%d fdr=%d)\n", 5218c2ecf20Sopenharmony_ci i2c->real_clk, fdr >> 8, fdr & 0xff); 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci#else /* !CONFIG_FSL_SOC */ 5258c2ecf20Sopenharmony_cistatic void mpc_i2c_setup_8xxx(struct device_node *node, 5268c2ecf20Sopenharmony_ci struct mpc_i2c *i2c, 5278c2ecf20Sopenharmony_ci u32 clock) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci#endif /* CONFIG_FSL_SOC */ 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic void mpc_i2c_start(struct mpc_i2c *i2c) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci /* Clear arbitration */ 5358c2ecf20Sopenharmony_ci writeb(0, i2c->base + MPC_I2C_SR); 5368c2ecf20Sopenharmony_ci /* Start with MEN */ 5378c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MEN); 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic void mpc_i2c_stop(struct mpc_i2c *i2c) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MEN); 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic int mpc_write(struct mpc_i2c *i2c, int target, 5468c2ecf20Sopenharmony_ci const u8 *data, int length, int restart) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci int i, result; 5498c2ecf20Sopenharmony_ci unsigned timeout = i2c->adap.timeout; 5508c2ecf20Sopenharmony_ci u32 flags = restart ? CCR_RSTA : 0; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci /* Start as master */ 5538c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags); 5548c2ecf20Sopenharmony_ci /* Write target byte */ 5558c2ecf20Sopenharmony_ci writeb((target << 1), i2c->base + MPC_I2C_DR); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci result = i2c_wait(i2c, timeout, 1); 5588c2ecf20Sopenharmony_ci if (result < 0) 5598c2ecf20Sopenharmony_ci return result; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci for (i = 0; i < length; i++) { 5628c2ecf20Sopenharmony_ci /* Write data byte */ 5638c2ecf20Sopenharmony_ci writeb(data[i], i2c->base + MPC_I2C_DR); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci result = i2c_wait(i2c, timeout, 1); 5668c2ecf20Sopenharmony_ci if (result < 0) 5678c2ecf20Sopenharmony_ci return result; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci return 0; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic int mpc_read(struct mpc_i2c *i2c, int target, 5748c2ecf20Sopenharmony_ci u8 *data, int length, int restart, bool recv_len) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci unsigned timeout = i2c->adap.timeout; 5778c2ecf20Sopenharmony_ci int i, result; 5788c2ecf20Sopenharmony_ci u32 flags = restart ? CCR_RSTA : 0; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci /* Switch to read - restart */ 5818c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags); 5828c2ecf20Sopenharmony_ci /* Write target address byte - this time with the read flag set */ 5838c2ecf20Sopenharmony_ci writeb((target << 1) | 1, i2c->base + MPC_I2C_DR); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci result = i2c_wait(i2c, timeout, 1); 5868c2ecf20Sopenharmony_ci if (result < 0) 5878c2ecf20Sopenharmony_ci return result; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (length) { 5908c2ecf20Sopenharmony_ci if (length == 1 && !recv_len) 5918c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK); 5928c2ecf20Sopenharmony_ci else 5938c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA); 5948c2ecf20Sopenharmony_ci /* Dummy read */ 5958c2ecf20Sopenharmony_ci readb(i2c->base + MPC_I2C_DR); 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci for (i = 0; i < length; i++) { 5998c2ecf20Sopenharmony_ci u8 byte; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci result = i2c_wait(i2c, timeout, 0); 6028c2ecf20Sopenharmony_ci if (result < 0) 6038c2ecf20Sopenharmony_ci return result; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* 6068c2ecf20Sopenharmony_ci * For block reads, we have to know the total length (1st byte) 6078c2ecf20Sopenharmony_ci * before we can determine if we are done. 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_ci if (i || !recv_len) { 6108c2ecf20Sopenharmony_ci /* Generate txack on next to last byte */ 6118c2ecf20Sopenharmony_ci if (i == length - 2) 6128c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA 6138c2ecf20Sopenharmony_ci | CCR_TXAK); 6148c2ecf20Sopenharmony_ci /* Do not generate stop on last byte */ 6158c2ecf20Sopenharmony_ci if (i == length - 1) 6168c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA 6178c2ecf20Sopenharmony_ci | CCR_MTX); 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci byte = readb(i2c->base + MPC_I2C_DR); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci /* 6238c2ecf20Sopenharmony_ci * Adjust length if first received byte is length. 6248c2ecf20Sopenharmony_ci * The length is 1 length byte plus actually data length 6258c2ecf20Sopenharmony_ci */ 6268c2ecf20Sopenharmony_ci if (i == 0 && recv_len) { 6278c2ecf20Sopenharmony_ci if (byte == 0 || byte > I2C_SMBUS_BLOCK_MAX) 6288c2ecf20Sopenharmony_ci return -EPROTO; 6298c2ecf20Sopenharmony_ci length += byte; 6308c2ecf20Sopenharmony_ci /* 6318c2ecf20Sopenharmony_ci * For block reads, generate txack here if data length 6328c2ecf20Sopenharmony_ci * is 1 byte (total length is 2 bytes). 6338c2ecf20Sopenharmony_ci */ 6348c2ecf20Sopenharmony_ci if (length == 2) 6358c2ecf20Sopenharmony_ci writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA 6368c2ecf20Sopenharmony_ci | CCR_TXAK); 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci data[i] = byte; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci return length; 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci struct i2c_msg *pmsg; 6478c2ecf20Sopenharmony_ci int i; 6488c2ecf20Sopenharmony_ci int ret = 0; 6498c2ecf20Sopenharmony_ci unsigned long orig_jiffies = jiffies; 6508c2ecf20Sopenharmony_ci struct mpc_i2c *i2c = i2c_get_adapdata(adap); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci mpc_i2c_start(i2c); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci /* Allow bus up to 1s to become not busy */ 6558c2ecf20Sopenharmony_ci while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) { 6568c2ecf20Sopenharmony_ci if (signal_pending(current)) { 6578c2ecf20Sopenharmony_ci dev_dbg(i2c->dev, "Interrupted\n"); 6588c2ecf20Sopenharmony_ci writeccr(i2c, 0); 6598c2ecf20Sopenharmony_ci return -EINTR; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci if (time_after(jiffies, orig_jiffies + HZ)) { 6628c2ecf20Sopenharmony_ci u8 status = readb(i2c->base + MPC_I2C_SR); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci dev_dbg(i2c->dev, "timeout\n"); 6658c2ecf20Sopenharmony_ci if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) != 0) { 6668c2ecf20Sopenharmony_ci writeb(status & ~CSR_MAL, 6678c2ecf20Sopenharmony_ci i2c->base + MPC_I2C_SR); 6688c2ecf20Sopenharmony_ci i2c_recover_bus(&i2c->adap); 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci return -EIO; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci schedule(); 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci for (i = 0; ret >= 0 && i < num; i++) { 6768c2ecf20Sopenharmony_ci pmsg = &msgs[i]; 6778c2ecf20Sopenharmony_ci dev_dbg(i2c->dev, 6788c2ecf20Sopenharmony_ci "Doing %s %d bytes to 0x%02x - %d of %d messages\n", 6798c2ecf20Sopenharmony_ci pmsg->flags & I2C_M_RD ? "read" : "write", 6808c2ecf20Sopenharmony_ci pmsg->len, pmsg->addr, i + 1, num); 6818c2ecf20Sopenharmony_ci if (pmsg->flags & I2C_M_RD) { 6828c2ecf20Sopenharmony_ci bool recv_len = pmsg->flags & I2C_M_RECV_LEN; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci ret = mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i, 6858c2ecf20Sopenharmony_ci recv_len); 6868c2ecf20Sopenharmony_ci if (recv_len && ret > 0) 6878c2ecf20Sopenharmony_ci pmsg->len = ret; 6888c2ecf20Sopenharmony_ci } else { 6898c2ecf20Sopenharmony_ci ret = 6908c2ecf20Sopenharmony_ci mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i); 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci mpc_i2c_stop(i2c); /* Initiate STOP */ 6948c2ecf20Sopenharmony_ci orig_jiffies = jiffies; 6958c2ecf20Sopenharmony_ci /* Wait until STOP is seen, allow up to 1 s */ 6968c2ecf20Sopenharmony_ci while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) { 6978c2ecf20Sopenharmony_ci if (time_after(jiffies, orig_jiffies + HZ)) { 6988c2ecf20Sopenharmony_ci u8 status = readb(i2c->base + MPC_I2C_SR); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci dev_dbg(i2c->dev, "timeout\n"); 7018c2ecf20Sopenharmony_ci if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) != 0) { 7028c2ecf20Sopenharmony_ci writeb(status & ~CSR_MAL, 7038c2ecf20Sopenharmony_ci i2c->base + MPC_I2C_SR); 7048c2ecf20Sopenharmony_ci i2c_recover_bus(&i2c->adap); 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci return -EIO; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci cond_resched(); 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci return (ret < 0) ? ret : num; 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cistatic u32 mpc_functionality(struct i2c_adapter *adap) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL 7168c2ecf20Sopenharmony_ci | I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL; 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic int fsl_i2c_bus_recovery(struct i2c_adapter *adap) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci struct mpc_i2c *i2c = i2c_get_adapdata(adap); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci if (i2c->has_errata_A004447) 7248c2ecf20Sopenharmony_ci mpc_i2c_fixup_A004447(i2c); 7258c2ecf20Sopenharmony_ci else 7268c2ecf20Sopenharmony_ci mpc_i2c_fixup(i2c); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci return 0; 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistatic const struct i2c_algorithm mpc_algo = { 7328c2ecf20Sopenharmony_ci .master_xfer = mpc_xfer, 7338c2ecf20Sopenharmony_ci .functionality = mpc_functionality, 7348c2ecf20Sopenharmony_ci}; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic struct i2c_adapter mpc_ops = { 7378c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7388c2ecf20Sopenharmony_ci .algo = &mpc_algo, 7398c2ecf20Sopenharmony_ci .timeout = HZ, 7408c2ecf20Sopenharmony_ci}; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic struct i2c_bus_recovery_info fsl_i2c_recovery_info = { 7438c2ecf20Sopenharmony_ci .recover_bus = fsl_i2c_bus_recovery, 7448c2ecf20Sopenharmony_ci}; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_cistatic const struct of_device_id mpc_i2c_of_match[]; 7478c2ecf20Sopenharmony_cistatic int fsl_i2c_probe(struct platform_device *op) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci const struct of_device_id *match; 7508c2ecf20Sopenharmony_ci struct mpc_i2c *i2c; 7518c2ecf20Sopenharmony_ci const u32 *prop; 7528c2ecf20Sopenharmony_ci u32 clock = MPC_I2C_CLOCK_LEGACY; 7538c2ecf20Sopenharmony_ci int result = 0; 7548c2ecf20Sopenharmony_ci int plen; 7558c2ecf20Sopenharmony_ci struct resource res; 7568c2ecf20Sopenharmony_ci struct clk *clk; 7578c2ecf20Sopenharmony_ci int err; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci match = of_match_device(mpc_i2c_of_match, &op->dev); 7608c2ecf20Sopenharmony_ci if (!match) 7618c2ecf20Sopenharmony_ci return -EINVAL; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); 7648c2ecf20Sopenharmony_ci if (!i2c) 7658c2ecf20Sopenharmony_ci return -ENOMEM; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci i2c->dev = &op->dev; /* for debug and error output */ 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci init_waitqueue_head(&i2c->queue); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci i2c->base = of_iomap(op->dev.of_node, 0); 7728c2ecf20Sopenharmony_ci if (!i2c->base) { 7738c2ecf20Sopenharmony_ci dev_err(i2c->dev, "failed to map controller\n"); 7748c2ecf20Sopenharmony_ci result = -ENOMEM; 7758c2ecf20Sopenharmony_ci goto fail_map; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci i2c->irq = irq_of_parse_and_map(op->dev.of_node, 0); 7798c2ecf20Sopenharmony_ci if (i2c->irq) { /* no i2c->irq implies polling */ 7808c2ecf20Sopenharmony_ci result = request_irq(i2c->irq, mpc_i2c_isr, 7818c2ecf20Sopenharmony_ci IRQF_SHARED, "i2c-mpc", i2c); 7828c2ecf20Sopenharmony_ci if (result < 0) { 7838c2ecf20Sopenharmony_ci dev_err(i2c->dev, "failed to attach interrupt\n"); 7848c2ecf20Sopenharmony_ci goto fail_request; 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci /* 7898c2ecf20Sopenharmony_ci * enable clock for the I2C peripheral (non fatal), 7908c2ecf20Sopenharmony_ci * keep a reference upon successful allocation 7918c2ecf20Sopenharmony_ci */ 7928c2ecf20Sopenharmony_ci clk = devm_clk_get(&op->dev, NULL); 7938c2ecf20Sopenharmony_ci if (!IS_ERR(clk)) { 7948c2ecf20Sopenharmony_ci err = clk_prepare_enable(clk); 7958c2ecf20Sopenharmony_ci if (err) { 7968c2ecf20Sopenharmony_ci dev_err(&op->dev, "failed to enable clock\n"); 7978c2ecf20Sopenharmony_ci goto fail_request; 7988c2ecf20Sopenharmony_ci } else { 7998c2ecf20Sopenharmony_ci i2c->clk_per = clk; 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (of_property_read_bool(op->dev.of_node, "fsl,preserve-clocking")) { 8048c2ecf20Sopenharmony_ci clock = MPC_I2C_CLOCK_PRESERVE; 8058c2ecf20Sopenharmony_ci } else { 8068c2ecf20Sopenharmony_ci prop = of_get_property(op->dev.of_node, "clock-frequency", 8078c2ecf20Sopenharmony_ci &plen); 8088c2ecf20Sopenharmony_ci if (prop && plen == sizeof(u32)) 8098c2ecf20Sopenharmony_ci clock = *prop; 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci if (match->data) { 8138c2ecf20Sopenharmony_ci const struct mpc_i2c_data *data = match->data; 8148c2ecf20Sopenharmony_ci data->setup(op->dev.of_node, i2c, clock); 8158c2ecf20Sopenharmony_ci } else { 8168c2ecf20Sopenharmony_ci /* Backwards compatibility */ 8178c2ecf20Sopenharmony_ci if (of_get_property(op->dev.of_node, "dfsrr", NULL)) 8188c2ecf20Sopenharmony_ci mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock); 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci prop = of_get_property(op->dev.of_node, "fsl,timeout", &plen); 8228c2ecf20Sopenharmony_ci if (prop && plen == sizeof(u32)) { 8238c2ecf20Sopenharmony_ci mpc_ops.timeout = *prop * HZ / 1000000; 8248c2ecf20Sopenharmony_ci if (mpc_ops.timeout < 5) 8258c2ecf20Sopenharmony_ci mpc_ops.timeout = 5; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 1000000 / HZ); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci platform_set_drvdata(op, i2c); 8308c2ecf20Sopenharmony_ci if (of_property_read_bool(op->dev.of_node, "fsl,i2c-erratum-a004447")) 8318c2ecf20Sopenharmony_ci i2c->has_errata_A004447 = true; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci i2c->adap = mpc_ops; 8348c2ecf20Sopenharmony_ci of_address_to_resource(op->dev.of_node, 0, &res); 8358c2ecf20Sopenharmony_ci scnprintf(i2c->adap.name, sizeof(i2c->adap.name), 8368c2ecf20Sopenharmony_ci "MPC adapter at 0x%llx", (unsigned long long)res.start); 8378c2ecf20Sopenharmony_ci i2c_set_adapdata(&i2c->adap, i2c); 8388c2ecf20Sopenharmony_ci i2c->adap.dev.parent = &op->dev; 8398c2ecf20Sopenharmony_ci i2c->adap.dev.of_node = of_node_get(op->dev.of_node); 8408c2ecf20Sopenharmony_ci i2c->adap.bus_recovery_info = &fsl_i2c_recovery_info; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci result = i2c_add_adapter(&i2c->adap); 8438c2ecf20Sopenharmony_ci if (result < 0) 8448c2ecf20Sopenharmony_ci goto fail_add; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci return result; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci fail_add: 8498c2ecf20Sopenharmony_ci if (i2c->clk_per) 8508c2ecf20Sopenharmony_ci clk_disable_unprepare(i2c->clk_per); 8518c2ecf20Sopenharmony_ci free_irq(i2c->irq, i2c); 8528c2ecf20Sopenharmony_ci fail_request: 8538c2ecf20Sopenharmony_ci irq_dispose_mapping(i2c->irq); 8548c2ecf20Sopenharmony_ci iounmap(i2c->base); 8558c2ecf20Sopenharmony_ci fail_map: 8568c2ecf20Sopenharmony_ci kfree(i2c); 8578c2ecf20Sopenharmony_ci return result; 8588c2ecf20Sopenharmony_ci}; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic int fsl_i2c_remove(struct platform_device *op) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci struct mpc_i2c *i2c = platform_get_drvdata(op); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci i2c_del_adapter(&i2c->adap); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (i2c->clk_per) 8678c2ecf20Sopenharmony_ci clk_disable_unprepare(i2c->clk_per); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci if (i2c->irq) 8708c2ecf20Sopenharmony_ci free_irq(i2c->irq, i2c); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci irq_dispose_mapping(i2c->irq); 8738c2ecf20Sopenharmony_ci iounmap(i2c->base); 8748c2ecf20Sopenharmony_ci kfree(i2c); 8758c2ecf20Sopenharmony_ci return 0; 8768c2ecf20Sopenharmony_ci}; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 8798c2ecf20Sopenharmony_cistatic int mpc_i2c_suspend(struct device *dev) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci struct mpc_i2c *i2c = dev_get_drvdata(dev); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci i2c->fdr = readb(i2c->base + MPC_I2C_FDR); 8848c2ecf20Sopenharmony_ci i2c->dfsrr = readb(i2c->base + MPC_I2C_DFSRR); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci return 0; 8878c2ecf20Sopenharmony_ci} 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_cistatic int mpc_i2c_resume(struct device *dev) 8908c2ecf20Sopenharmony_ci{ 8918c2ecf20Sopenharmony_ci struct mpc_i2c *i2c = dev_get_drvdata(dev); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci writeb(i2c->fdr, i2c->base + MPC_I2C_FDR); 8948c2ecf20Sopenharmony_ci writeb(i2c->dfsrr, i2c->base + MPC_I2C_DFSRR); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci return 0; 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(mpc_i2c_pm_ops, mpc_i2c_suspend, mpc_i2c_resume); 9008c2ecf20Sopenharmony_ci#define MPC_I2C_PM_OPS (&mpc_i2c_pm_ops) 9018c2ecf20Sopenharmony_ci#else 9028c2ecf20Sopenharmony_ci#define MPC_I2C_PM_OPS NULL 9038c2ecf20Sopenharmony_ci#endif 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistatic const struct mpc_i2c_data mpc_i2c_data_512x = { 9068c2ecf20Sopenharmony_ci .setup = mpc_i2c_setup_512x, 9078c2ecf20Sopenharmony_ci}; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_cistatic const struct mpc_i2c_data mpc_i2c_data_52xx = { 9108c2ecf20Sopenharmony_ci .setup = mpc_i2c_setup_52xx, 9118c2ecf20Sopenharmony_ci}; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_cistatic const struct mpc_i2c_data mpc_i2c_data_8313 = { 9148c2ecf20Sopenharmony_ci .setup = mpc_i2c_setup_8xxx, 9158c2ecf20Sopenharmony_ci}; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_cistatic const struct mpc_i2c_data mpc_i2c_data_8543 = { 9188c2ecf20Sopenharmony_ci .setup = mpc_i2c_setup_8xxx, 9198c2ecf20Sopenharmony_ci}; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_cistatic const struct mpc_i2c_data mpc_i2c_data_8544 = { 9228c2ecf20Sopenharmony_ci .setup = mpc_i2c_setup_8xxx, 9238c2ecf20Sopenharmony_ci}; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_cistatic const struct of_device_id mpc_i2c_of_match[] = { 9268c2ecf20Sopenharmony_ci {.compatible = "mpc5200-i2c", .data = &mpc_i2c_data_52xx, }, 9278c2ecf20Sopenharmony_ci {.compatible = "fsl,mpc5200b-i2c", .data = &mpc_i2c_data_52xx, }, 9288c2ecf20Sopenharmony_ci {.compatible = "fsl,mpc5200-i2c", .data = &mpc_i2c_data_52xx, }, 9298c2ecf20Sopenharmony_ci {.compatible = "fsl,mpc5121-i2c", .data = &mpc_i2c_data_512x, }, 9308c2ecf20Sopenharmony_ci {.compatible = "fsl,mpc8313-i2c", .data = &mpc_i2c_data_8313, }, 9318c2ecf20Sopenharmony_ci {.compatible = "fsl,mpc8543-i2c", .data = &mpc_i2c_data_8543, }, 9328c2ecf20Sopenharmony_ci {.compatible = "fsl,mpc8544-i2c", .data = &mpc_i2c_data_8544, }, 9338c2ecf20Sopenharmony_ci /* Backward compatibility */ 9348c2ecf20Sopenharmony_ci {.compatible = "fsl-i2c", }, 9358c2ecf20Sopenharmony_ci {}, 9368c2ecf20Sopenharmony_ci}; 9378c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mpc_i2c_of_match); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci/* Structure for a device driver */ 9408c2ecf20Sopenharmony_cistatic struct platform_driver mpc_i2c_driver = { 9418c2ecf20Sopenharmony_ci .probe = fsl_i2c_probe, 9428c2ecf20Sopenharmony_ci .remove = fsl_i2c_remove, 9438c2ecf20Sopenharmony_ci .driver = { 9448c2ecf20Sopenharmony_ci .name = DRV_NAME, 9458c2ecf20Sopenharmony_ci .of_match_table = mpc_i2c_of_match, 9468c2ecf20Sopenharmony_ci .pm = MPC_I2C_PM_OPS, 9478c2ecf20Sopenharmony_ci }, 9488c2ecf20Sopenharmony_ci}; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cimodule_platform_driver(mpc_i2c_driver); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ciMODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>"); 9538c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and " 9548c2ecf20Sopenharmony_ci "MPC824x/83xx/85xx/86xx/512x/52xx processors"); 9558c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 956