162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Freescale CPM1/CPM2 I2C interface. 462306a36Sopenharmony_ci * Copyright (c) 1999 Dan Malek (dmalek@jlc.net). 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * moved into proper i2c interface; 762306a36Sopenharmony_ci * Brad Parker (brad@heeltoe.com) 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Parts from dbox2_i2c.c (cvs.tuxbox.org) 1062306a36Sopenharmony_ci * (C) 2000-2001 Felix Domke (tmbinc@gmx.net), Gillem (htoa@gmx.net) 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * (C) 2007 Montavista Software, Inc. 1362306a36Sopenharmony_ci * Vitaly Bordug <vitb@kernel.crashing.org> 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Converted to of_platform_device. Renamed to i2c-cpm.c. 1662306a36Sopenharmony_ci * (C) 2007,2008 Jochen Friedrich <jochen@scram.de> 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/delay.h> 2262306a36Sopenharmony_ci#include <linux/slab.h> 2362306a36Sopenharmony_ci#include <linux/interrupt.h> 2462306a36Sopenharmony_ci#include <linux/errno.h> 2562306a36Sopenharmony_ci#include <linux/stddef.h> 2662306a36Sopenharmony_ci#include <linux/i2c.h> 2762306a36Sopenharmony_ci#include <linux/io.h> 2862306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2962306a36Sopenharmony_ci#include <linux/of.h> 3062306a36Sopenharmony_ci#include <linux/of_address.h> 3162306a36Sopenharmony_ci#include <linux/of_irq.h> 3262306a36Sopenharmony_ci#include <linux/platform_device.h> 3362306a36Sopenharmony_ci#include <sysdev/fsl_soc.h> 3462306a36Sopenharmony_ci#include <asm/cpm.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* Try to define this if you have an older CPU (earlier than rev D4) */ 3762306a36Sopenharmony_ci/* However, better use a GPIO based bitbang driver in this case :/ */ 3862306a36Sopenharmony_ci#undef I2C_CHIP_ERRATA 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define CPM_MAX_READ 513 4162306a36Sopenharmony_ci#define CPM_MAXBD 4 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define I2C_EB (0x10) /* Big endian mode */ 4462306a36Sopenharmony_ci#define I2C_EB_CPM2 (0x30) /* Big endian mode, memory snoop */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define DPRAM_BASE ((u8 __iomem __force *)cpm_muram_addr(0)) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* I2C parameter RAM. */ 4962306a36Sopenharmony_cistruct i2c_ram { 5062306a36Sopenharmony_ci ushort rbase; /* Rx Buffer descriptor base address */ 5162306a36Sopenharmony_ci ushort tbase; /* Tx Buffer descriptor base address */ 5262306a36Sopenharmony_ci u_char rfcr; /* Rx function code */ 5362306a36Sopenharmony_ci u_char tfcr; /* Tx function code */ 5462306a36Sopenharmony_ci ushort mrblr; /* Max receive buffer length */ 5562306a36Sopenharmony_ci uint rstate; /* Internal */ 5662306a36Sopenharmony_ci uint rdp; /* Internal */ 5762306a36Sopenharmony_ci ushort rbptr; /* Rx Buffer descriptor pointer */ 5862306a36Sopenharmony_ci ushort rbc; /* Internal */ 5962306a36Sopenharmony_ci uint rxtmp; /* Internal */ 6062306a36Sopenharmony_ci uint tstate; /* Internal */ 6162306a36Sopenharmony_ci uint tdp; /* Internal */ 6262306a36Sopenharmony_ci ushort tbptr; /* Tx Buffer descriptor pointer */ 6362306a36Sopenharmony_ci ushort tbc; /* Internal */ 6462306a36Sopenharmony_ci uint txtmp; /* Internal */ 6562306a36Sopenharmony_ci char res1[4]; /* Reserved */ 6662306a36Sopenharmony_ci ushort rpbase; /* Relocation pointer */ 6762306a36Sopenharmony_ci char res2[2]; /* Reserved */ 6862306a36Sopenharmony_ci /* The following elements are only for CPM2 */ 6962306a36Sopenharmony_ci char res3[4]; /* Reserved */ 7062306a36Sopenharmony_ci uint sdmatmp; /* Internal */ 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define I2COM_START 0x80 7462306a36Sopenharmony_ci#define I2COM_MASTER 0x01 7562306a36Sopenharmony_ci#define I2CER_TXE 0x10 7662306a36Sopenharmony_ci#define I2CER_BUSY 0x04 7762306a36Sopenharmony_ci#define I2CER_TXB 0x02 7862306a36Sopenharmony_ci#define I2CER_RXB 0x01 7962306a36Sopenharmony_ci#define I2MOD_EN 0x01 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* I2C Registers */ 8262306a36Sopenharmony_cistruct i2c_reg { 8362306a36Sopenharmony_ci u8 i2mod; 8462306a36Sopenharmony_ci u8 res1[3]; 8562306a36Sopenharmony_ci u8 i2add; 8662306a36Sopenharmony_ci u8 res2[3]; 8762306a36Sopenharmony_ci u8 i2brg; 8862306a36Sopenharmony_ci u8 res3[3]; 8962306a36Sopenharmony_ci u8 i2com; 9062306a36Sopenharmony_ci u8 res4[3]; 9162306a36Sopenharmony_ci u8 i2cer; 9262306a36Sopenharmony_ci u8 res5[3]; 9362306a36Sopenharmony_ci u8 i2cmr; 9462306a36Sopenharmony_ci}; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistruct cpm_i2c { 9762306a36Sopenharmony_ci char *base; 9862306a36Sopenharmony_ci struct platform_device *ofdev; 9962306a36Sopenharmony_ci struct i2c_adapter adap; 10062306a36Sopenharmony_ci uint dp_addr; 10162306a36Sopenharmony_ci int version; /* CPM1=1, CPM2=2 */ 10262306a36Sopenharmony_ci int irq; 10362306a36Sopenharmony_ci int cp_command; 10462306a36Sopenharmony_ci int freq; 10562306a36Sopenharmony_ci struct i2c_reg __iomem *i2c_reg; 10662306a36Sopenharmony_ci struct i2c_ram __iomem *i2c_ram; 10762306a36Sopenharmony_ci u16 i2c_addr; 10862306a36Sopenharmony_ci wait_queue_head_t i2c_wait; 10962306a36Sopenharmony_ci cbd_t __iomem *tbase; 11062306a36Sopenharmony_ci cbd_t __iomem *rbase; 11162306a36Sopenharmony_ci u_char *txbuf[CPM_MAXBD]; 11262306a36Sopenharmony_ci u_char *rxbuf[CPM_MAXBD]; 11362306a36Sopenharmony_ci dma_addr_t txdma[CPM_MAXBD]; 11462306a36Sopenharmony_ci dma_addr_t rxdma[CPM_MAXBD]; 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic irqreturn_t cpm_i2c_interrupt(int irq, void *dev_id) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct cpm_i2c *cpm; 12062306a36Sopenharmony_ci struct i2c_reg __iomem *i2c_reg; 12162306a36Sopenharmony_ci struct i2c_adapter *adap = dev_id; 12262306a36Sopenharmony_ci int i; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci cpm = i2c_get_adapdata(dev_id); 12562306a36Sopenharmony_ci i2c_reg = cpm->i2c_reg; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* Clear interrupt. */ 12862306a36Sopenharmony_ci i = in_8(&i2c_reg->i2cer); 12962306a36Sopenharmony_ci out_8(&i2c_reg->i2cer, i); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci dev_dbg(&adap->dev, "Interrupt: %x\n", i); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci wake_up(&cpm->i2c_wait); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return i ? IRQ_HANDLED : IRQ_NONE; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic void cpm_reset_i2c_params(struct cpm_i2c *cpm) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* Set up the I2C parameters in the parameter ram. */ 14362306a36Sopenharmony_ci out_be16(&i2c_ram->tbase, (u8 __iomem *)cpm->tbase - DPRAM_BASE); 14462306a36Sopenharmony_ci out_be16(&i2c_ram->rbase, (u8 __iomem *)cpm->rbase - DPRAM_BASE); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (cpm->version == 1) { 14762306a36Sopenharmony_ci out_8(&i2c_ram->tfcr, I2C_EB); 14862306a36Sopenharmony_ci out_8(&i2c_ram->rfcr, I2C_EB); 14962306a36Sopenharmony_ci } else { 15062306a36Sopenharmony_ci out_8(&i2c_ram->tfcr, I2C_EB_CPM2); 15162306a36Sopenharmony_ci out_8(&i2c_ram->rfcr, I2C_EB_CPM2); 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci out_be16(&i2c_ram->mrblr, CPM_MAX_READ); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci out_be32(&i2c_ram->rstate, 0); 15762306a36Sopenharmony_ci out_be32(&i2c_ram->rdp, 0); 15862306a36Sopenharmony_ci out_be16(&i2c_ram->rbptr, 0); 15962306a36Sopenharmony_ci out_be16(&i2c_ram->rbc, 0); 16062306a36Sopenharmony_ci out_be32(&i2c_ram->rxtmp, 0); 16162306a36Sopenharmony_ci out_be32(&i2c_ram->tstate, 0); 16262306a36Sopenharmony_ci out_be32(&i2c_ram->tdp, 0); 16362306a36Sopenharmony_ci out_be16(&i2c_ram->tbptr, 0); 16462306a36Sopenharmony_ci out_be16(&i2c_ram->tbc, 0); 16562306a36Sopenharmony_ci out_be32(&i2c_ram->txtmp, 0); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic void cpm_i2c_force_close(struct i2c_adapter *adap) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct cpm_i2c *cpm = i2c_get_adapdata(adap); 17162306a36Sopenharmony_ci struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci dev_dbg(&adap->dev, "cpm_i2c_force_close()\n"); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci cpm_command(cpm->cp_command, CPM_CR_CLOSE_RX_BD); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci out_8(&i2c_reg->i2cmr, 0x00); /* Disable all interrupts */ 17862306a36Sopenharmony_ci out_8(&i2c_reg->i2cer, 0xff); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic void cpm_i2c_parse_message(struct i2c_adapter *adap, 18262306a36Sopenharmony_ci struct i2c_msg *pmsg, int num, int tx, int rx) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci cbd_t __iomem *tbdf; 18562306a36Sopenharmony_ci cbd_t __iomem *rbdf; 18662306a36Sopenharmony_ci u_char addr; 18762306a36Sopenharmony_ci u_char *tb; 18862306a36Sopenharmony_ci u_char *rb; 18962306a36Sopenharmony_ci struct cpm_i2c *cpm = i2c_get_adapdata(adap); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci tbdf = cpm->tbase + tx; 19262306a36Sopenharmony_ci rbdf = cpm->rbase + rx; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci addr = i2c_8bit_addr_from_msg(pmsg); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci tb = cpm->txbuf[tx]; 19762306a36Sopenharmony_ci rb = cpm->rxbuf[rx]; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* Align read buffer */ 20062306a36Sopenharmony_ci rb = (u_char *) (((ulong) rb + 1) & ~1); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci tb[0] = addr; /* Device address byte w/rw flag */ 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci out_be16(&tbdf->cbd_datlen, pmsg->len + 1); 20562306a36Sopenharmony_ci out_be16(&tbdf->cbd_sc, 0); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (!(pmsg->flags & I2C_M_NOSTART)) 20862306a36Sopenharmony_ci setbits16(&tbdf->cbd_sc, BD_I2C_START); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (tx + 1 == num) 21162306a36Sopenharmony_ci setbits16(&tbdf->cbd_sc, BD_SC_LAST | BD_SC_WRAP); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (pmsg->flags & I2C_M_RD) { 21462306a36Sopenharmony_ci /* 21562306a36Sopenharmony_ci * To read, we need an empty buffer of the proper length. 21662306a36Sopenharmony_ci * All that is used is the first byte for address, the remainder 21762306a36Sopenharmony_ci * is just used for timing (and doesn't really have to exist). 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci dev_dbg(&adap->dev, "cpm_i2c_read(abyte=0x%x)\n", addr); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci out_be16(&rbdf->cbd_datlen, 0); 22362306a36Sopenharmony_ci out_be16(&rbdf->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (rx + 1 == CPM_MAXBD) 22662306a36Sopenharmony_ci setbits16(&rbdf->cbd_sc, BD_SC_WRAP); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci eieio(); 22962306a36Sopenharmony_ci setbits16(&tbdf->cbd_sc, BD_SC_READY); 23062306a36Sopenharmony_ci } else { 23162306a36Sopenharmony_ci dev_dbg(&adap->dev, "cpm_i2c_write(abyte=0x%x)\n", addr); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci memcpy(tb+1, pmsg->buf, pmsg->len); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci eieio(); 23662306a36Sopenharmony_ci setbits16(&tbdf->cbd_sc, BD_SC_READY | BD_SC_INTRPT); 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic int cpm_i2c_check_message(struct i2c_adapter *adap, 24162306a36Sopenharmony_ci struct i2c_msg *pmsg, int tx, int rx) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci cbd_t __iomem *tbdf; 24462306a36Sopenharmony_ci cbd_t __iomem *rbdf; 24562306a36Sopenharmony_ci u_char *tb; 24662306a36Sopenharmony_ci u_char *rb; 24762306a36Sopenharmony_ci struct cpm_i2c *cpm = i2c_get_adapdata(adap); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci tbdf = cpm->tbase + tx; 25062306a36Sopenharmony_ci rbdf = cpm->rbase + rx; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci tb = cpm->txbuf[tx]; 25362306a36Sopenharmony_ci rb = cpm->rxbuf[rx]; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* Align read buffer */ 25662306a36Sopenharmony_ci rb = (u_char *) (((uint) rb + 1) & ~1); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci eieio(); 25962306a36Sopenharmony_ci if (pmsg->flags & I2C_M_RD) { 26062306a36Sopenharmony_ci dev_dbg(&adap->dev, "tx sc 0x%04x, rx sc 0x%04x\n", 26162306a36Sopenharmony_ci in_be16(&tbdf->cbd_sc), in_be16(&rbdf->cbd_sc)); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (in_be16(&tbdf->cbd_sc) & BD_SC_NAK) { 26462306a36Sopenharmony_ci dev_dbg(&adap->dev, "I2C read; No ack\n"); 26562306a36Sopenharmony_ci return -ENXIO; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci if (in_be16(&rbdf->cbd_sc) & BD_SC_EMPTY) { 26862306a36Sopenharmony_ci dev_err(&adap->dev, 26962306a36Sopenharmony_ci "I2C read; complete but rbuf empty\n"); 27062306a36Sopenharmony_ci return -EREMOTEIO; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci if (in_be16(&rbdf->cbd_sc) & BD_SC_OV) { 27362306a36Sopenharmony_ci dev_err(&adap->dev, "I2C read; Overrun\n"); 27462306a36Sopenharmony_ci return -EREMOTEIO; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci memcpy(pmsg->buf, rb, pmsg->len); 27762306a36Sopenharmony_ci } else { 27862306a36Sopenharmony_ci dev_dbg(&adap->dev, "tx sc %d 0x%04x\n", tx, 27962306a36Sopenharmony_ci in_be16(&tbdf->cbd_sc)); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (in_be16(&tbdf->cbd_sc) & BD_SC_NAK) { 28262306a36Sopenharmony_ci dev_dbg(&adap->dev, "I2C write; No ack\n"); 28362306a36Sopenharmony_ci return -ENXIO; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci if (in_be16(&tbdf->cbd_sc) & BD_SC_UN) { 28662306a36Sopenharmony_ci dev_err(&adap->dev, "I2C write; Underrun\n"); 28762306a36Sopenharmony_ci return -EIO; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci if (in_be16(&tbdf->cbd_sc) & BD_SC_CL) { 29062306a36Sopenharmony_ci dev_err(&adap->dev, "I2C write; Collision\n"); 29162306a36Sopenharmony_ci return -EIO; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci return 0; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct cpm_i2c *cpm = i2c_get_adapdata(adap); 30062306a36Sopenharmony_ci struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg; 30162306a36Sopenharmony_ci struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram; 30262306a36Sopenharmony_ci struct i2c_msg *pmsg; 30362306a36Sopenharmony_ci int ret; 30462306a36Sopenharmony_ci int tptr; 30562306a36Sopenharmony_ci int rptr; 30662306a36Sopenharmony_ci cbd_t __iomem *tbdf; 30762306a36Sopenharmony_ci cbd_t __iomem *rbdf; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* Reset to use first buffer */ 31062306a36Sopenharmony_ci out_be16(&i2c_ram->rbptr, in_be16(&i2c_ram->rbase)); 31162306a36Sopenharmony_ci out_be16(&i2c_ram->tbptr, in_be16(&i2c_ram->tbase)); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci tbdf = cpm->tbase; 31462306a36Sopenharmony_ci rbdf = cpm->rbase; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci tptr = 0; 31762306a36Sopenharmony_ci rptr = 0; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* 32062306a36Sopenharmony_ci * If there was a collision in the last i2c transaction, 32162306a36Sopenharmony_ci * Set I2COM_MASTER as it was cleared during collision. 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ci if (in_be16(&tbdf->cbd_sc) & BD_SC_CL) { 32462306a36Sopenharmony_ci out_8(&cpm->i2c_reg->i2com, I2COM_MASTER); 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci while (tptr < num) { 32862306a36Sopenharmony_ci pmsg = &msgs[tptr]; 32962306a36Sopenharmony_ci dev_dbg(&adap->dev, "R: %d T: %d\n", rptr, tptr); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci cpm_i2c_parse_message(adap, pmsg, num, tptr, rptr); 33262306a36Sopenharmony_ci if (pmsg->flags & I2C_M_RD) 33362306a36Sopenharmony_ci rptr++; 33462306a36Sopenharmony_ci tptr++; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci /* Start transfer now */ 33762306a36Sopenharmony_ci /* Enable RX/TX/Error interupts */ 33862306a36Sopenharmony_ci out_8(&i2c_reg->i2cmr, I2CER_TXE | I2CER_TXB | I2CER_RXB); 33962306a36Sopenharmony_ci out_8(&i2c_reg->i2cer, 0xff); /* Clear interrupt status */ 34062306a36Sopenharmony_ci /* Chip bug, set enable here */ 34162306a36Sopenharmony_ci setbits8(&i2c_reg->i2mod, I2MOD_EN); /* Enable */ 34262306a36Sopenharmony_ci /* Begin transmission */ 34362306a36Sopenharmony_ci setbits8(&i2c_reg->i2com, I2COM_START); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci tptr = 0; 34662306a36Sopenharmony_ci rptr = 0; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci while (tptr < num) { 34962306a36Sopenharmony_ci /* Check for outstanding messages */ 35062306a36Sopenharmony_ci dev_dbg(&adap->dev, "test ready.\n"); 35162306a36Sopenharmony_ci pmsg = &msgs[tptr]; 35262306a36Sopenharmony_ci if (pmsg->flags & I2C_M_RD) 35362306a36Sopenharmony_ci ret = wait_event_timeout(cpm->i2c_wait, 35462306a36Sopenharmony_ci (in_be16(&tbdf[tptr].cbd_sc) & BD_SC_NAK) || 35562306a36Sopenharmony_ci !(in_be16(&rbdf[rptr].cbd_sc) & BD_SC_EMPTY), 35662306a36Sopenharmony_ci 1 * HZ); 35762306a36Sopenharmony_ci else 35862306a36Sopenharmony_ci ret = wait_event_timeout(cpm->i2c_wait, 35962306a36Sopenharmony_ci !(in_be16(&tbdf[tptr].cbd_sc) & BD_SC_READY), 36062306a36Sopenharmony_ci 1 * HZ); 36162306a36Sopenharmony_ci if (ret == 0) { 36262306a36Sopenharmony_ci ret = -EREMOTEIO; 36362306a36Sopenharmony_ci dev_err(&adap->dev, "I2C transfer: timeout\n"); 36462306a36Sopenharmony_ci goto out_err; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci if (ret > 0) { 36762306a36Sopenharmony_ci dev_dbg(&adap->dev, "ready.\n"); 36862306a36Sopenharmony_ci ret = cpm_i2c_check_message(adap, pmsg, tptr, rptr); 36962306a36Sopenharmony_ci tptr++; 37062306a36Sopenharmony_ci if (pmsg->flags & I2C_M_RD) 37162306a36Sopenharmony_ci rptr++; 37262306a36Sopenharmony_ci if (ret) 37362306a36Sopenharmony_ci goto out_err; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci#ifdef I2C_CHIP_ERRATA 37762306a36Sopenharmony_ci /* 37862306a36Sopenharmony_ci * Chip errata, clear enable. This is not needed on rev D4 CPUs. 37962306a36Sopenharmony_ci * Disabling I2C too early may cause too short stop condition 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_ci udelay(4); 38262306a36Sopenharmony_ci clrbits8(&i2c_reg->i2mod, I2MOD_EN); 38362306a36Sopenharmony_ci#endif 38462306a36Sopenharmony_ci return (num); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ciout_err: 38762306a36Sopenharmony_ci cpm_i2c_force_close(adap); 38862306a36Sopenharmony_ci#ifdef I2C_CHIP_ERRATA 38962306a36Sopenharmony_ci /* 39062306a36Sopenharmony_ci * Chip errata, clear enable. This is not needed on rev D4 CPUs. 39162306a36Sopenharmony_ci */ 39262306a36Sopenharmony_ci clrbits8(&i2c_reg->i2mod, I2MOD_EN); 39362306a36Sopenharmony_ci#endif 39462306a36Sopenharmony_ci return ret; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic u32 cpm_i2c_func(struct i2c_adapter *adap) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci/* -----exported algorithm data: ------------------------------------- */ 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic const struct i2c_algorithm cpm_i2c_algo = { 40562306a36Sopenharmony_ci .master_xfer = cpm_i2c_xfer, 40662306a36Sopenharmony_ci .functionality = cpm_i2c_func, 40762306a36Sopenharmony_ci}; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci/* CPM_MAX_READ is also limiting writes according to the code! */ 41062306a36Sopenharmony_cistatic const struct i2c_adapter_quirks cpm_i2c_quirks = { 41162306a36Sopenharmony_ci .max_num_msgs = CPM_MAXBD, 41262306a36Sopenharmony_ci .max_read_len = CPM_MAX_READ, 41362306a36Sopenharmony_ci .max_write_len = CPM_MAX_READ, 41462306a36Sopenharmony_ci}; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic const struct i2c_adapter cpm_ops = { 41762306a36Sopenharmony_ci .owner = THIS_MODULE, 41862306a36Sopenharmony_ci .name = "i2c-cpm", 41962306a36Sopenharmony_ci .algo = &cpm_i2c_algo, 42062306a36Sopenharmony_ci .quirks = &cpm_i2c_quirks, 42162306a36Sopenharmony_ci}; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic int cpm_i2c_setup(struct cpm_i2c *cpm) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct platform_device *ofdev = cpm->ofdev; 42662306a36Sopenharmony_ci const u32 *data; 42762306a36Sopenharmony_ci int len, ret, i; 42862306a36Sopenharmony_ci void __iomem *i2c_base; 42962306a36Sopenharmony_ci cbd_t __iomem *tbdf; 43062306a36Sopenharmony_ci cbd_t __iomem *rbdf; 43162306a36Sopenharmony_ci unsigned char brg; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci dev_dbg(&cpm->ofdev->dev, "cpm_i2c_setup()\n"); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci init_waitqueue_head(&cpm->i2c_wait); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci cpm->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); 43862306a36Sopenharmony_ci if (!cpm->irq) 43962306a36Sopenharmony_ci return -EINVAL; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* Install interrupt handler. */ 44262306a36Sopenharmony_ci ret = request_irq(cpm->irq, cpm_i2c_interrupt, 0, "cpm_i2c", 44362306a36Sopenharmony_ci &cpm->adap); 44462306a36Sopenharmony_ci if (ret) 44562306a36Sopenharmony_ci return ret; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci /* I2C parameter RAM */ 44862306a36Sopenharmony_ci i2c_base = of_iomap(ofdev->dev.of_node, 1); 44962306a36Sopenharmony_ci if (i2c_base == NULL) { 45062306a36Sopenharmony_ci ret = -EINVAL; 45162306a36Sopenharmony_ci goto out_irq; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (of_device_is_compatible(ofdev->dev.of_node, "fsl,cpm1-i2c")) { 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* Check for and use a microcode relocation patch. */ 45762306a36Sopenharmony_ci cpm->i2c_ram = i2c_base; 45862306a36Sopenharmony_ci cpm->i2c_addr = in_be16(&cpm->i2c_ram->rpbase); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* 46162306a36Sopenharmony_ci * Maybe should use cpm_muram_alloc instead of hardcoding 46262306a36Sopenharmony_ci * this in micropatch.c 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_ci if (cpm->i2c_addr) { 46562306a36Sopenharmony_ci cpm->i2c_ram = cpm_muram_addr(cpm->i2c_addr); 46662306a36Sopenharmony_ci iounmap(i2c_base); 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci cpm->version = 1; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci } else if (of_device_is_compatible(ofdev->dev.of_node, "fsl,cpm2-i2c")) { 47262306a36Sopenharmony_ci cpm->i2c_addr = cpm_muram_alloc(sizeof(struct i2c_ram), 64); 47362306a36Sopenharmony_ci cpm->i2c_ram = cpm_muram_addr(cpm->i2c_addr); 47462306a36Sopenharmony_ci out_be16(i2c_base, cpm->i2c_addr); 47562306a36Sopenharmony_ci iounmap(i2c_base); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci cpm->version = 2; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci } else { 48062306a36Sopenharmony_ci iounmap(i2c_base); 48162306a36Sopenharmony_ci ret = -EINVAL; 48262306a36Sopenharmony_ci goto out_irq; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* I2C control/status registers */ 48662306a36Sopenharmony_ci cpm->i2c_reg = of_iomap(ofdev->dev.of_node, 0); 48762306a36Sopenharmony_ci if (cpm->i2c_reg == NULL) { 48862306a36Sopenharmony_ci ret = -EINVAL; 48962306a36Sopenharmony_ci goto out_ram; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len); 49362306a36Sopenharmony_ci if (!data || len != 4) { 49462306a36Sopenharmony_ci ret = -EINVAL; 49562306a36Sopenharmony_ci goto out_reg; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci cpm->cp_command = *data; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci data = of_get_property(ofdev->dev.of_node, "linux,i2c-class", &len); 50062306a36Sopenharmony_ci if (data && len == 4) 50162306a36Sopenharmony_ci cpm->adap.class = *data; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci data = of_get_property(ofdev->dev.of_node, "clock-frequency", &len); 50462306a36Sopenharmony_ci if (data && len == 4) 50562306a36Sopenharmony_ci cpm->freq = *data; 50662306a36Sopenharmony_ci else 50762306a36Sopenharmony_ci cpm->freq = 60000; /* use 60kHz i2c clock by default */ 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* 51062306a36Sopenharmony_ci * Allocate space for CPM_MAXBD transmit and receive buffer 51162306a36Sopenharmony_ci * descriptors in the DP ram. 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_ci cpm->dp_addr = cpm_muram_alloc(sizeof(cbd_t) * 2 * CPM_MAXBD, 8); 51462306a36Sopenharmony_ci if (!cpm->dp_addr) { 51562306a36Sopenharmony_ci ret = -ENOMEM; 51662306a36Sopenharmony_ci goto out_reg; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci cpm->tbase = cpm_muram_addr(cpm->dp_addr); 52062306a36Sopenharmony_ci cpm->rbase = cpm_muram_addr(cpm->dp_addr + sizeof(cbd_t) * CPM_MAXBD); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* Allocate TX and RX buffers */ 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci tbdf = cpm->tbase; 52562306a36Sopenharmony_ci rbdf = cpm->rbase; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci for (i = 0; i < CPM_MAXBD; i++) { 52862306a36Sopenharmony_ci cpm->rxbuf[i] = dma_alloc_coherent(&cpm->ofdev->dev, 52962306a36Sopenharmony_ci CPM_MAX_READ + 1, 53062306a36Sopenharmony_ci &cpm->rxdma[i], GFP_KERNEL); 53162306a36Sopenharmony_ci if (!cpm->rxbuf[i]) { 53262306a36Sopenharmony_ci ret = -ENOMEM; 53362306a36Sopenharmony_ci goto out_muram; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci out_be32(&rbdf[i].cbd_bufaddr, ((cpm->rxdma[i] + 1) & ~1)); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci cpm->txbuf[i] = dma_alloc_coherent(&cpm->ofdev->dev, 53862306a36Sopenharmony_ci CPM_MAX_READ + 1, 53962306a36Sopenharmony_ci &cpm->txdma[i], GFP_KERNEL); 54062306a36Sopenharmony_ci if (!cpm->txbuf[i]) { 54162306a36Sopenharmony_ci ret = -ENOMEM; 54262306a36Sopenharmony_ci goto out_muram; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci out_be32(&tbdf[i].cbd_bufaddr, cpm->txdma[i]); 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* Initialize Tx/Rx parameters. */ 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci cpm_reset_i2c_params(cpm); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci dev_dbg(&cpm->ofdev->dev, "i2c_ram 0x%p, i2c_addr 0x%04x, freq %d\n", 55262306a36Sopenharmony_ci cpm->i2c_ram, cpm->i2c_addr, cpm->freq); 55362306a36Sopenharmony_ci dev_dbg(&cpm->ofdev->dev, "tbase 0x%04x, rbase 0x%04x\n", 55462306a36Sopenharmony_ci (u8 __iomem *)cpm->tbase - DPRAM_BASE, 55562306a36Sopenharmony_ci (u8 __iomem *)cpm->rbase - DPRAM_BASE); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci cpm_command(cpm->cp_command, CPM_CR_INIT_TRX); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* 56062306a36Sopenharmony_ci * Select an invalid address. Just make sure we don't use loopback mode 56162306a36Sopenharmony_ci */ 56262306a36Sopenharmony_ci out_8(&cpm->i2c_reg->i2add, 0x7f << 1); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /* 56562306a36Sopenharmony_ci * PDIV is set to 00 in i2mod, so brgclk/32 is used as input to the 56662306a36Sopenharmony_ci * i2c baud rate generator. This is divided by 2 x (DIV + 3) to get 56762306a36Sopenharmony_ci * the actual i2c bus frequency. 56862306a36Sopenharmony_ci */ 56962306a36Sopenharmony_ci brg = get_brgfreq() / (32 * 2 * cpm->freq) - 3; 57062306a36Sopenharmony_ci out_8(&cpm->i2c_reg->i2brg, brg); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci out_8(&cpm->i2c_reg->i2mod, 0x00); 57362306a36Sopenharmony_ci out_8(&cpm->i2c_reg->i2com, I2COM_MASTER); /* Master mode */ 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* Disable interrupts. */ 57662306a36Sopenharmony_ci out_8(&cpm->i2c_reg->i2cmr, 0); 57762306a36Sopenharmony_ci out_8(&cpm->i2c_reg->i2cer, 0xff); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci return 0; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ciout_muram: 58262306a36Sopenharmony_ci for (i = 0; i < CPM_MAXBD; i++) { 58362306a36Sopenharmony_ci if (cpm->rxbuf[i]) 58462306a36Sopenharmony_ci dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1, 58562306a36Sopenharmony_ci cpm->rxbuf[i], cpm->rxdma[i]); 58662306a36Sopenharmony_ci if (cpm->txbuf[i]) 58762306a36Sopenharmony_ci dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1, 58862306a36Sopenharmony_ci cpm->txbuf[i], cpm->txdma[i]); 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci cpm_muram_free(cpm->dp_addr); 59162306a36Sopenharmony_ciout_reg: 59262306a36Sopenharmony_ci iounmap(cpm->i2c_reg); 59362306a36Sopenharmony_ciout_ram: 59462306a36Sopenharmony_ci if ((cpm->version == 1) && (!cpm->i2c_addr)) 59562306a36Sopenharmony_ci iounmap(cpm->i2c_ram); 59662306a36Sopenharmony_ci if (cpm->version == 2) 59762306a36Sopenharmony_ci cpm_muram_free(cpm->i2c_addr); 59862306a36Sopenharmony_ciout_irq: 59962306a36Sopenharmony_ci free_irq(cpm->irq, &cpm->adap); 60062306a36Sopenharmony_ci return ret; 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic void cpm_i2c_shutdown(struct cpm_i2c *cpm) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci int i; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci /* Shut down I2C. */ 60862306a36Sopenharmony_ci clrbits8(&cpm->i2c_reg->i2mod, I2MOD_EN); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci /* Disable interrupts */ 61162306a36Sopenharmony_ci out_8(&cpm->i2c_reg->i2cmr, 0); 61262306a36Sopenharmony_ci out_8(&cpm->i2c_reg->i2cer, 0xff); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci free_irq(cpm->irq, &cpm->adap); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci /* Free all memory */ 61762306a36Sopenharmony_ci for (i = 0; i < CPM_MAXBD; i++) { 61862306a36Sopenharmony_ci dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1, 61962306a36Sopenharmony_ci cpm->rxbuf[i], cpm->rxdma[i]); 62062306a36Sopenharmony_ci dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1, 62162306a36Sopenharmony_ci cpm->txbuf[i], cpm->txdma[i]); 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci cpm_muram_free(cpm->dp_addr); 62562306a36Sopenharmony_ci iounmap(cpm->i2c_reg); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if ((cpm->version == 1) && (!cpm->i2c_addr)) 62862306a36Sopenharmony_ci iounmap(cpm->i2c_ram); 62962306a36Sopenharmony_ci if (cpm->version == 2) 63062306a36Sopenharmony_ci cpm_muram_free(cpm->i2c_addr); 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic int cpm_i2c_probe(struct platform_device *ofdev) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci int result, len; 63662306a36Sopenharmony_ci struct cpm_i2c *cpm; 63762306a36Sopenharmony_ci const u32 *data; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci cpm = kzalloc(sizeof(struct cpm_i2c), GFP_KERNEL); 64062306a36Sopenharmony_ci if (!cpm) 64162306a36Sopenharmony_ci return -ENOMEM; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci cpm->ofdev = ofdev; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci platform_set_drvdata(ofdev, cpm); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci cpm->adap = cpm_ops; 64862306a36Sopenharmony_ci i2c_set_adapdata(&cpm->adap, cpm); 64962306a36Sopenharmony_ci cpm->adap.dev.parent = &ofdev->dev; 65062306a36Sopenharmony_ci cpm->adap.dev.of_node = of_node_get(ofdev->dev.of_node); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci result = cpm_i2c_setup(cpm); 65362306a36Sopenharmony_ci if (result) { 65462306a36Sopenharmony_ci dev_err(&ofdev->dev, "Unable to init hardware\n"); 65562306a36Sopenharmony_ci goto out_free; 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci /* register new adapter to i2c module... */ 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci data = of_get_property(ofdev->dev.of_node, "linux,i2c-index", &len); 66162306a36Sopenharmony_ci cpm->adap.nr = (data && len == 4) ? be32_to_cpup(data) : -1; 66262306a36Sopenharmony_ci result = i2c_add_numbered_adapter(&cpm->adap); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (result < 0) 66562306a36Sopenharmony_ci goto out_shut; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci dev_dbg(&ofdev->dev, "hw routines for %s registered.\n", 66862306a36Sopenharmony_ci cpm->adap.name); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci return 0; 67162306a36Sopenharmony_ciout_shut: 67262306a36Sopenharmony_ci cpm_i2c_shutdown(cpm); 67362306a36Sopenharmony_ciout_free: 67462306a36Sopenharmony_ci kfree(cpm); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci return result; 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic void cpm_i2c_remove(struct platform_device *ofdev) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci struct cpm_i2c *cpm = platform_get_drvdata(ofdev); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci i2c_del_adapter(&cpm->adap); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci cpm_i2c_shutdown(cpm); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci kfree(cpm); 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic const struct of_device_id cpm_i2c_match[] = { 69162306a36Sopenharmony_ci { 69262306a36Sopenharmony_ci .compatible = "fsl,cpm1-i2c", 69362306a36Sopenharmony_ci }, 69462306a36Sopenharmony_ci { 69562306a36Sopenharmony_ci .compatible = "fsl,cpm2-i2c", 69662306a36Sopenharmony_ci }, 69762306a36Sopenharmony_ci {}, 69862306a36Sopenharmony_ci}; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, cpm_i2c_match); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic struct platform_driver cpm_i2c_driver = { 70362306a36Sopenharmony_ci .probe = cpm_i2c_probe, 70462306a36Sopenharmony_ci .remove_new = cpm_i2c_remove, 70562306a36Sopenharmony_ci .driver = { 70662306a36Sopenharmony_ci .name = "fsl-i2c-cpm", 70762306a36Sopenharmony_ci .of_match_table = cpm_i2c_match, 70862306a36Sopenharmony_ci }, 70962306a36Sopenharmony_ci}; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cimodule_platform_driver(cpm_i2c_driver); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ciMODULE_AUTHOR("Jochen Friedrich <jochen@scram.de>"); 71462306a36Sopenharmony_ciMODULE_DESCRIPTION("I2C-Bus adapter routines for CPM boards"); 71562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 716