162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Provides I2C support for Philips PNX010x/PNX4008 boards. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Authors: Dennis Kovalev <dkovalev@ru.mvista.com> 562306a36Sopenharmony_ci * Vitaly Wool <vwool@ru.mvista.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * 2004-2006 (c) MontaVista Software, Inc. This file is licensed under 862306a36Sopenharmony_ci * the terms of the GNU General Public License version 2. This program 962306a36Sopenharmony_ci * is licensed "as is" without any warranty of any kind, whether express 1062306a36Sopenharmony_ci * or implied. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/ioport.h> 1662306a36Sopenharmony_ci#include <linux/delay.h> 1762306a36Sopenharmony_ci#include <linux/i2c.h> 1862306a36Sopenharmony_ci#include <linux/timer.h> 1962306a36Sopenharmony_ci#include <linux/completion.h> 2062306a36Sopenharmony_ci#include <linux/platform_device.h> 2162306a36Sopenharmony_ci#include <linux/io.h> 2262306a36Sopenharmony_ci#include <linux/err.h> 2362306a36Sopenharmony_ci#include <linux/clk.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci#include <linux/of.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define I2C_PNX_TIMEOUT_DEFAULT 10 /* msec */ 2862306a36Sopenharmony_ci#define I2C_PNX_SPEED_KHZ_DEFAULT 100 2962306a36Sopenharmony_ci#define I2C_PNX_REGION_SIZE 0x100 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistruct i2c_pnx_mif { 3262306a36Sopenharmony_ci int ret; /* Return value */ 3362306a36Sopenharmony_ci int mode; /* Interface mode */ 3462306a36Sopenharmony_ci struct completion complete; /* I/O completion */ 3562306a36Sopenharmony_ci struct timer_list timer; /* Timeout */ 3662306a36Sopenharmony_ci u8 * buf; /* Data buffer */ 3762306a36Sopenharmony_ci int len; /* Length of data buffer */ 3862306a36Sopenharmony_ci int order; /* RX Bytes to order via TX */ 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistruct i2c_pnx_algo_data { 4262306a36Sopenharmony_ci void __iomem *ioaddr; 4362306a36Sopenharmony_ci struct i2c_pnx_mif mif; 4462306a36Sopenharmony_ci int last; 4562306a36Sopenharmony_ci struct clk *clk; 4662306a36Sopenharmony_ci struct i2c_adapter adapter; 4762306a36Sopenharmony_ci int irq; 4862306a36Sopenharmony_ci u32 timeout; 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cienum { 5262306a36Sopenharmony_ci mstatus_tdi = 0x00000001, 5362306a36Sopenharmony_ci mstatus_afi = 0x00000002, 5462306a36Sopenharmony_ci mstatus_nai = 0x00000004, 5562306a36Sopenharmony_ci mstatus_drmi = 0x00000008, 5662306a36Sopenharmony_ci mstatus_active = 0x00000020, 5762306a36Sopenharmony_ci mstatus_scl = 0x00000040, 5862306a36Sopenharmony_ci mstatus_sda = 0x00000080, 5962306a36Sopenharmony_ci mstatus_rff = 0x00000100, 6062306a36Sopenharmony_ci mstatus_rfe = 0x00000200, 6162306a36Sopenharmony_ci mstatus_tff = 0x00000400, 6262306a36Sopenharmony_ci mstatus_tfe = 0x00000800, 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cienum { 6662306a36Sopenharmony_ci mcntrl_tdie = 0x00000001, 6762306a36Sopenharmony_ci mcntrl_afie = 0x00000002, 6862306a36Sopenharmony_ci mcntrl_naie = 0x00000004, 6962306a36Sopenharmony_ci mcntrl_drmie = 0x00000008, 7062306a36Sopenharmony_ci mcntrl_drsie = 0x00000010, 7162306a36Sopenharmony_ci mcntrl_rffie = 0x00000020, 7262306a36Sopenharmony_ci mcntrl_daie = 0x00000040, 7362306a36Sopenharmony_ci mcntrl_tffie = 0x00000080, 7462306a36Sopenharmony_ci mcntrl_reset = 0x00000100, 7562306a36Sopenharmony_ci mcntrl_cdbmode = 0x00000400, 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cienum { 7962306a36Sopenharmony_ci rw_bit = 1 << 0, 8062306a36Sopenharmony_ci start_bit = 1 << 8, 8162306a36Sopenharmony_ci stop_bit = 1 << 9, 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define I2C_REG_RX(a) ((a)->ioaddr) /* Rx FIFO reg (RO) */ 8562306a36Sopenharmony_ci#define I2C_REG_TX(a) ((a)->ioaddr) /* Tx FIFO reg (WO) */ 8662306a36Sopenharmony_ci#define I2C_REG_STS(a) ((a)->ioaddr + 0x04) /* Status reg (RO) */ 8762306a36Sopenharmony_ci#define I2C_REG_CTL(a) ((a)->ioaddr + 0x08) /* Ctl reg */ 8862306a36Sopenharmony_ci#define I2C_REG_CKL(a) ((a)->ioaddr + 0x0c) /* Clock divider low */ 8962306a36Sopenharmony_ci#define I2C_REG_CKH(a) ((a)->ioaddr + 0x10) /* Clock divider high */ 9062306a36Sopenharmony_ci#define I2C_REG_ADR(a) ((a)->ioaddr + 0x14) /* I2C address */ 9162306a36Sopenharmony_ci#define I2C_REG_RFL(a) ((a)->ioaddr + 0x18) /* Rx FIFO level (RO) */ 9262306a36Sopenharmony_ci#define I2C_REG_TFL(a) ((a)->ioaddr + 0x1c) /* Tx FIFO level (RO) */ 9362306a36Sopenharmony_ci#define I2C_REG_RXB(a) ((a)->ioaddr + 0x20) /* Num of bytes Rx-ed (RO) */ 9462306a36Sopenharmony_ci#define I2C_REG_TXB(a) ((a)->ioaddr + 0x24) /* Num of bytes Tx-ed (RO) */ 9562306a36Sopenharmony_ci#define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */ 9662306a36Sopenharmony_ci#define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */ 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic inline int wait_timeout(struct i2c_pnx_algo_data *data) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci long timeout = data->timeout; 10162306a36Sopenharmony_ci while (timeout > 0 && 10262306a36Sopenharmony_ci (ioread32(I2C_REG_STS(data)) & mstatus_active)) { 10362306a36Sopenharmony_ci mdelay(1); 10462306a36Sopenharmony_ci timeout--; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci return (timeout <= 0); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic inline int wait_reset(struct i2c_pnx_algo_data *data) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci long timeout = data->timeout; 11262306a36Sopenharmony_ci while (timeout > 0 && 11362306a36Sopenharmony_ci (ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) { 11462306a36Sopenharmony_ci mdelay(1); 11562306a36Sopenharmony_ci timeout--; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci return (timeout <= 0); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct timer_list *timer = &alg_data->mif.timer; 12362306a36Sopenharmony_ci unsigned long expires = msecs_to_jiffies(alg_data->timeout); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (expires <= 1) 12662306a36Sopenharmony_ci expires = 2; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci del_timer_sync(timer); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, "Timer armed at %lu plus %lu jiffies.\n", 13162306a36Sopenharmony_ci jiffies, expires); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci timer->expires = jiffies + expires; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci add_timer(timer); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/** 13962306a36Sopenharmony_ci * i2c_pnx_start - start a device 14062306a36Sopenharmony_ci * @slave_addr: slave address 14162306a36Sopenharmony_ci * @alg_data: pointer to local driver data structure 14262306a36Sopenharmony_ci * 14362306a36Sopenharmony_ci * Generate a START signal in the desired mode. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_cistatic int i2c_pnx_start(unsigned char slave_addr, 14662306a36Sopenharmony_ci struct i2c_pnx_algo_data *alg_data) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, "%s(): addr 0x%x mode %d\n", __func__, 14962306a36Sopenharmony_ci slave_addr, alg_data->mif.mode); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Check for 7 bit slave addresses only */ 15262306a36Sopenharmony_ci if (slave_addr & ~0x7f) { 15362306a36Sopenharmony_ci dev_err(&alg_data->adapter.dev, 15462306a36Sopenharmony_ci "%s: Invalid slave address %x. Only 7-bit addresses are supported\n", 15562306a36Sopenharmony_ci alg_data->adapter.name, slave_addr); 15662306a36Sopenharmony_ci return -EINVAL; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* First, make sure bus is idle */ 16062306a36Sopenharmony_ci if (wait_timeout(alg_data)) { 16162306a36Sopenharmony_ci /* Somebody else is monopolizing the bus */ 16262306a36Sopenharmony_ci dev_err(&alg_data->adapter.dev, 16362306a36Sopenharmony_ci "%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n", 16462306a36Sopenharmony_ci alg_data->adapter.name, slave_addr, 16562306a36Sopenharmony_ci ioread32(I2C_REG_CTL(alg_data)), 16662306a36Sopenharmony_ci ioread32(I2C_REG_STS(alg_data))); 16762306a36Sopenharmony_ci return -EBUSY; 16862306a36Sopenharmony_ci } else if (ioread32(I2C_REG_STS(alg_data)) & mstatus_afi) { 16962306a36Sopenharmony_ci /* Sorry, we lost the bus */ 17062306a36Sopenharmony_ci dev_err(&alg_data->adapter.dev, 17162306a36Sopenharmony_ci "%s: Arbitration failure. Slave addr = %02x\n", 17262306a36Sopenharmony_ci alg_data->adapter.name, slave_addr); 17362306a36Sopenharmony_ci return -EIO; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* 17762306a36Sopenharmony_ci * OK, I2C is enabled and we have the bus. 17862306a36Sopenharmony_ci * Clear the current TDI and AFI status flags. 17962306a36Sopenharmony_ci */ 18062306a36Sopenharmony_ci iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi, 18162306a36Sopenharmony_ci I2C_REG_STS(alg_data)); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, "%s(): sending %#x\n", __func__, 18462306a36Sopenharmony_ci (slave_addr << 1) | start_bit | alg_data->mif.mode); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* Write the slave address, START bit and R/W bit */ 18762306a36Sopenharmony_ci iowrite32((slave_addr << 1) | start_bit | alg_data->mif.mode, 18862306a36Sopenharmony_ci I2C_REG_TX(alg_data)); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, "%s(): exit\n", __func__); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci/** 19662306a36Sopenharmony_ci * i2c_pnx_stop - stop a device 19762306a36Sopenharmony_ci * @alg_data: pointer to local driver data structure 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * Generate a STOP signal to terminate the master transaction. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_cistatic void i2c_pnx_stop(struct i2c_pnx_algo_data *alg_data) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci /* Only 1 msec max timeout due to interrupt context */ 20462306a36Sopenharmony_ci long timeout = 1000; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n", 20762306a36Sopenharmony_ci __func__, ioread32(I2C_REG_STS(alg_data))); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* Write a STOP bit to TX FIFO */ 21062306a36Sopenharmony_ci iowrite32(0xff | stop_bit, I2C_REG_TX(alg_data)); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* Wait until the STOP is seen. */ 21362306a36Sopenharmony_ci while (timeout > 0 && 21462306a36Sopenharmony_ci (ioread32(I2C_REG_STS(alg_data)) & mstatus_active)) { 21562306a36Sopenharmony_ci /* may be called from interrupt context */ 21662306a36Sopenharmony_ci udelay(1); 21762306a36Sopenharmony_ci timeout--; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n", 22162306a36Sopenharmony_ci __func__, ioread32(I2C_REG_STS(alg_data))); 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci/** 22562306a36Sopenharmony_ci * i2c_pnx_master_xmit - transmit data to slave 22662306a36Sopenharmony_ci * @alg_data: pointer to local driver data structure 22762306a36Sopenharmony_ci * 22862306a36Sopenharmony_ci * Sends one byte of data to the slave 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_cistatic int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci u32 val; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n", 23562306a36Sopenharmony_ci __func__, ioread32(I2C_REG_STS(alg_data))); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (alg_data->mif.len > 0) { 23862306a36Sopenharmony_ci /* We still have something to talk about... */ 23962306a36Sopenharmony_ci val = *alg_data->mif.buf++; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (alg_data->mif.len == 1) 24262306a36Sopenharmony_ci val |= stop_bit; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci alg_data->mif.len--; 24562306a36Sopenharmony_ci iowrite32(val, I2C_REG_TX(alg_data)); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, "%s(): xmit %#x [%d]\n", 24862306a36Sopenharmony_ci __func__, val, alg_data->mif.len + 1); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (alg_data->mif.len == 0) { 25162306a36Sopenharmony_ci if (alg_data->last) { 25262306a36Sopenharmony_ci /* Wait until the STOP is seen. */ 25362306a36Sopenharmony_ci if (wait_timeout(alg_data)) 25462306a36Sopenharmony_ci dev_err(&alg_data->adapter.dev, 25562306a36Sopenharmony_ci "The bus is still active after timeout\n"); 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci /* Disable master interrupts */ 25862306a36Sopenharmony_ci iowrite32(ioread32(I2C_REG_CTL(alg_data)) & 25962306a36Sopenharmony_ci ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie), 26062306a36Sopenharmony_ci I2C_REG_CTL(alg_data)); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci del_timer_sync(&alg_data->mif.timer); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, 26562306a36Sopenharmony_ci "%s(): Waking up xfer routine.\n", 26662306a36Sopenharmony_ci __func__); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci complete(&alg_data->mif.complete); 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci } else if (alg_data->mif.len == 0) { 27162306a36Sopenharmony_ci /* zero-sized transfer */ 27262306a36Sopenharmony_ci i2c_pnx_stop(alg_data); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* Disable master interrupts. */ 27562306a36Sopenharmony_ci iowrite32(ioread32(I2C_REG_CTL(alg_data)) & 27662306a36Sopenharmony_ci ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie), 27762306a36Sopenharmony_ci I2C_REG_CTL(alg_data)); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* Stop timer. */ 28062306a36Sopenharmony_ci del_timer_sync(&alg_data->mif.timer); 28162306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, 28262306a36Sopenharmony_ci "%s(): Waking up xfer routine after zero-xfer.\n", 28362306a36Sopenharmony_ci __func__); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci complete(&alg_data->mif.complete); 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n", 28962306a36Sopenharmony_ci __func__, ioread32(I2C_REG_STS(alg_data))); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci return 0; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci/** 29562306a36Sopenharmony_ci * i2c_pnx_master_rcv - receive data from slave 29662306a36Sopenharmony_ci * @alg_data: pointer to local driver data structure 29762306a36Sopenharmony_ci * 29862306a36Sopenharmony_ci * Reads one byte data from the slave 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_cistatic int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci unsigned int val = 0; 30362306a36Sopenharmony_ci u32 ctl = 0; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n", 30662306a36Sopenharmony_ci __func__, ioread32(I2C_REG_STS(alg_data))); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* Check, whether there is already data, 30962306a36Sopenharmony_ci * or we didn't 'ask' for it yet. 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_ci if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) { 31262306a36Sopenharmony_ci /* 'Asking' is done asynchronously, e.g. dummy TX of several 31362306a36Sopenharmony_ci * bytes is done before the first actual RX arrives in FIFO. 31462306a36Sopenharmony_ci * Therefore, ordered bytes (via TX) are counted separately. 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_ci if (alg_data->mif.order) { 31762306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, 31862306a36Sopenharmony_ci "%s(): Write dummy data to fill Rx-fifo...\n", 31962306a36Sopenharmony_ci __func__); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (alg_data->mif.order == 1) { 32262306a36Sopenharmony_ci /* Last byte, do not acknowledge next rcv. */ 32362306a36Sopenharmony_ci val |= stop_bit; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* 32662306a36Sopenharmony_ci * Enable interrupt RFDAIE (data in Rx fifo), 32762306a36Sopenharmony_ci * and disable DRMIE (need data for Tx) 32862306a36Sopenharmony_ci */ 32962306a36Sopenharmony_ci ctl = ioread32(I2C_REG_CTL(alg_data)); 33062306a36Sopenharmony_ci ctl |= mcntrl_rffie | mcntrl_daie; 33162306a36Sopenharmony_ci ctl &= ~mcntrl_drmie; 33262306a36Sopenharmony_ci iowrite32(ctl, I2C_REG_CTL(alg_data)); 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* 33662306a36Sopenharmony_ci * Now we'll 'ask' for data: 33762306a36Sopenharmony_ci * For each byte we want to receive, we must 33862306a36Sopenharmony_ci * write a (dummy) byte to the Tx-FIFO. 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_ci iowrite32(val, I2C_REG_TX(alg_data)); 34162306a36Sopenharmony_ci alg_data->mif.order--; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci return 0; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci /* Handle data. */ 34762306a36Sopenharmony_ci if (alg_data->mif.len > 0) { 34862306a36Sopenharmony_ci val = ioread32(I2C_REG_RX(alg_data)); 34962306a36Sopenharmony_ci *alg_data->mif.buf++ = (u8) (val & 0xff); 35062306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, "%s(): rcv 0x%x [%d]\n", 35162306a36Sopenharmony_ci __func__, val, alg_data->mif.len); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci alg_data->mif.len--; 35462306a36Sopenharmony_ci if (alg_data->mif.len == 0) { 35562306a36Sopenharmony_ci if (alg_data->last) 35662306a36Sopenharmony_ci /* Wait until the STOP is seen. */ 35762306a36Sopenharmony_ci if (wait_timeout(alg_data)) 35862306a36Sopenharmony_ci dev_err(&alg_data->adapter.dev, 35962306a36Sopenharmony_ci "The bus is still active after timeout\n"); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* Disable master interrupts */ 36262306a36Sopenharmony_ci ctl = ioread32(I2C_REG_CTL(alg_data)); 36362306a36Sopenharmony_ci ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | 36462306a36Sopenharmony_ci mcntrl_drmie | mcntrl_daie); 36562306a36Sopenharmony_ci iowrite32(ctl, I2C_REG_CTL(alg_data)); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* Kill timer. */ 36862306a36Sopenharmony_ci del_timer_sync(&alg_data->mif.timer); 36962306a36Sopenharmony_ci complete(&alg_data->mif.complete); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n", 37462306a36Sopenharmony_ci __func__, ioread32(I2C_REG_STS(alg_data))); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci return 0; 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct i2c_pnx_algo_data *alg_data = dev_id; 38262306a36Sopenharmony_ci u32 stat, ctl; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, 38562306a36Sopenharmony_ci "%s(): mstat = %x mctrl = %x, mode = %d\n", 38662306a36Sopenharmony_ci __func__, 38762306a36Sopenharmony_ci ioread32(I2C_REG_STS(alg_data)), 38862306a36Sopenharmony_ci ioread32(I2C_REG_CTL(alg_data)), 38962306a36Sopenharmony_ci alg_data->mif.mode); 39062306a36Sopenharmony_ci stat = ioread32(I2C_REG_STS(alg_data)); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* let's see what kind of event this is */ 39362306a36Sopenharmony_ci if (stat & mstatus_afi) { 39462306a36Sopenharmony_ci /* We lost arbitration in the midst of a transfer */ 39562306a36Sopenharmony_ci alg_data->mif.ret = -EIO; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* Disable master interrupts. */ 39862306a36Sopenharmony_ci ctl = ioread32(I2C_REG_CTL(alg_data)); 39962306a36Sopenharmony_ci ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | 40062306a36Sopenharmony_ci mcntrl_drmie); 40162306a36Sopenharmony_ci iowrite32(ctl, I2C_REG_CTL(alg_data)); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* Stop timer, to prevent timeout. */ 40462306a36Sopenharmony_ci del_timer_sync(&alg_data->mif.timer); 40562306a36Sopenharmony_ci complete(&alg_data->mif.complete); 40662306a36Sopenharmony_ci } else if (stat & mstatus_nai) { 40762306a36Sopenharmony_ci /* Slave did not acknowledge, generate a STOP */ 40862306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, 40962306a36Sopenharmony_ci "%s(): Slave did not acknowledge, generating a STOP.\n", 41062306a36Sopenharmony_ci __func__); 41162306a36Sopenharmony_ci i2c_pnx_stop(alg_data); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* Disable master interrupts. */ 41462306a36Sopenharmony_ci ctl = ioread32(I2C_REG_CTL(alg_data)); 41562306a36Sopenharmony_ci ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | 41662306a36Sopenharmony_ci mcntrl_drmie); 41762306a36Sopenharmony_ci iowrite32(ctl, I2C_REG_CTL(alg_data)); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* Our return value. */ 42062306a36Sopenharmony_ci alg_data->mif.ret = -EIO; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* Stop timer, to prevent timeout. */ 42362306a36Sopenharmony_ci del_timer_sync(&alg_data->mif.timer); 42462306a36Sopenharmony_ci complete(&alg_data->mif.complete); 42562306a36Sopenharmony_ci } else { 42662306a36Sopenharmony_ci /* 42762306a36Sopenharmony_ci * Two options: 42862306a36Sopenharmony_ci * - Master Tx needs data. 42962306a36Sopenharmony_ci * - There is data in the Rx-fifo 43062306a36Sopenharmony_ci * The latter is only the case if we have requested for data, 43162306a36Sopenharmony_ci * via a dummy write. (See 'i2c_pnx_master_rcv'.) 43262306a36Sopenharmony_ci * We therefore check, as a sanity check, whether that interrupt 43362306a36Sopenharmony_ci * has been enabled. 43462306a36Sopenharmony_ci */ 43562306a36Sopenharmony_ci if ((stat & mstatus_drmi) || !(stat & mstatus_rfe)) { 43662306a36Sopenharmony_ci if (alg_data->mif.mode == I2C_SMBUS_WRITE) { 43762306a36Sopenharmony_ci i2c_pnx_master_xmit(alg_data); 43862306a36Sopenharmony_ci } else if (alg_data->mif.mode == I2C_SMBUS_READ) { 43962306a36Sopenharmony_ci i2c_pnx_master_rcv(alg_data); 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* Clear TDI and AFI bits */ 44562306a36Sopenharmony_ci stat = ioread32(I2C_REG_STS(alg_data)); 44662306a36Sopenharmony_ci iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data)); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, 44962306a36Sopenharmony_ci "%s(): exiting, stat = %x ctrl = %x.\n", 45062306a36Sopenharmony_ci __func__, ioread32(I2C_REG_STS(alg_data)), 45162306a36Sopenharmony_ci ioread32(I2C_REG_CTL(alg_data))); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return IRQ_HANDLED; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic void i2c_pnx_timeout(struct timer_list *t) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci struct i2c_pnx_algo_data *alg_data = from_timer(alg_data, t, mif.timer); 45962306a36Sopenharmony_ci u32 ctl; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci dev_err(&alg_data->adapter.dev, 46262306a36Sopenharmony_ci "Master timed out. stat = %04x, cntrl = %04x. Resetting master...\n", 46362306a36Sopenharmony_ci ioread32(I2C_REG_STS(alg_data)), 46462306a36Sopenharmony_ci ioread32(I2C_REG_CTL(alg_data))); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* Reset master and disable interrupts */ 46762306a36Sopenharmony_ci ctl = ioread32(I2C_REG_CTL(alg_data)); 46862306a36Sopenharmony_ci ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | mcntrl_drmie); 46962306a36Sopenharmony_ci iowrite32(ctl, I2C_REG_CTL(alg_data)); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci ctl |= mcntrl_reset; 47262306a36Sopenharmony_ci iowrite32(ctl, I2C_REG_CTL(alg_data)); 47362306a36Sopenharmony_ci wait_reset(alg_data); 47462306a36Sopenharmony_ci alg_data->mif.ret = -EIO; 47562306a36Sopenharmony_ci complete(&alg_data->mif.complete); 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cistatic inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci u32 stat; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_active) { 48362306a36Sopenharmony_ci dev_err(&alg_data->adapter.dev, 48462306a36Sopenharmony_ci "%s: Bus is still active after xfer. Reset it...\n", 48562306a36Sopenharmony_ci alg_data->adapter.name); 48662306a36Sopenharmony_ci iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, 48762306a36Sopenharmony_ci I2C_REG_CTL(alg_data)); 48862306a36Sopenharmony_ci wait_reset(alg_data); 48962306a36Sopenharmony_ci } else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) { 49062306a36Sopenharmony_ci /* If there is data in the fifo's after transfer, 49162306a36Sopenharmony_ci * flush fifo's by reset. 49262306a36Sopenharmony_ci */ 49362306a36Sopenharmony_ci iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, 49462306a36Sopenharmony_ci I2C_REG_CTL(alg_data)); 49562306a36Sopenharmony_ci wait_reset(alg_data); 49662306a36Sopenharmony_ci } else if (stat & mstatus_nai) { 49762306a36Sopenharmony_ci iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, 49862306a36Sopenharmony_ci I2C_REG_CTL(alg_data)); 49962306a36Sopenharmony_ci wait_reset(alg_data); 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci/** 50462306a36Sopenharmony_ci * i2c_pnx_xfer - generic transfer entry point 50562306a36Sopenharmony_ci * @adap: pointer to I2C adapter structure 50662306a36Sopenharmony_ci * @msgs: array of messages 50762306a36Sopenharmony_ci * @num: number of messages 50862306a36Sopenharmony_ci * 50962306a36Sopenharmony_ci * Initiates the transfer 51062306a36Sopenharmony_ci */ 51162306a36Sopenharmony_cistatic int 51262306a36Sopenharmony_cii2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci struct i2c_msg *pmsg; 51562306a36Sopenharmony_ci int rc = 0, completed = 0, i; 51662306a36Sopenharmony_ci struct i2c_pnx_algo_data *alg_data = adap->algo_data; 51762306a36Sopenharmony_ci u32 stat; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, 52062306a36Sopenharmony_ci "%s(): entering: %d messages, stat = %04x.\n", 52162306a36Sopenharmony_ci __func__, num, ioread32(I2C_REG_STS(alg_data))); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci bus_reset_if_active(alg_data); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci /* Process transactions in a loop. */ 52662306a36Sopenharmony_ci for (i = 0; rc >= 0 && i < num; i++) { 52762306a36Sopenharmony_ci u8 addr; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci pmsg = &msgs[i]; 53062306a36Sopenharmony_ci addr = pmsg->addr; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (pmsg->flags & I2C_M_TEN) { 53362306a36Sopenharmony_ci dev_err(&alg_data->adapter.dev, 53462306a36Sopenharmony_ci "%s: 10 bits addr not supported!\n", 53562306a36Sopenharmony_ci alg_data->adapter.name); 53662306a36Sopenharmony_ci rc = -EINVAL; 53762306a36Sopenharmony_ci break; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci alg_data->mif.buf = pmsg->buf; 54162306a36Sopenharmony_ci alg_data->mif.len = pmsg->len; 54262306a36Sopenharmony_ci alg_data->mif.order = pmsg->len; 54362306a36Sopenharmony_ci alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ? 54462306a36Sopenharmony_ci I2C_SMBUS_READ : I2C_SMBUS_WRITE; 54562306a36Sopenharmony_ci alg_data->mif.ret = 0; 54662306a36Sopenharmony_ci alg_data->last = (i == num - 1); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n", 54962306a36Sopenharmony_ci __func__, alg_data->mif.mode, alg_data->mif.len); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci i2c_pnx_arm_timer(alg_data); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci /* initialize the completion var */ 55462306a36Sopenharmony_ci init_completion(&alg_data->mif.complete); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* Enable master interrupt */ 55762306a36Sopenharmony_ci iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_afie | 55862306a36Sopenharmony_ci mcntrl_naie | mcntrl_drmie, 55962306a36Sopenharmony_ci I2C_REG_CTL(alg_data)); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* Put start-code and slave-address on the bus. */ 56262306a36Sopenharmony_ci rc = i2c_pnx_start(addr, alg_data); 56362306a36Sopenharmony_ci if (rc < 0) 56462306a36Sopenharmony_ci break; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* Wait for completion */ 56762306a36Sopenharmony_ci wait_for_completion(&alg_data->mif.complete); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (!(rc = alg_data->mif.ret)) 57062306a36Sopenharmony_ci completed++; 57162306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, 57262306a36Sopenharmony_ci "%s(): Complete, return code = %d.\n", 57362306a36Sopenharmony_ci __func__, rc); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* Clear TDI and AFI bits in case they are set. */ 57662306a36Sopenharmony_ci if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) { 57762306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, 57862306a36Sopenharmony_ci "%s: TDI still set... clearing now.\n", 57962306a36Sopenharmony_ci alg_data->adapter.name); 58062306a36Sopenharmony_ci iowrite32(stat, I2C_REG_STS(alg_data)); 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) { 58362306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, 58462306a36Sopenharmony_ci "%s: AFI still set... clearing now.\n", 58562306a36Sopenharmony_ci alg_data->adapter.name); 58662306a36Sopenharmony_ci iowrite32(stat, I2C_REG_STS(alg_data)); 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci bus_reset_if_active(alg_data); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* Cleanup to be sure... */ 59362306a36Sopenharmony_ci alg_data->mif.buf = NULL; 59462306a36Sopenharmony_ci alg_data->mif.len = 0; 59562306a36Sopenharmony_ci alg_data->mif.order = 0; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n", 59862306a36Sopenharmony_ci __func__, ioread32(I2C_REG_STS(alg_data))); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (completed != num) 60162306a36Sopenharmony_ci return ((rc < 0) ? rc : -EREMOTEIO); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci return num; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic u32 i2c_pnx_func(struct i2c_adapter *adapter) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic const struct i2c_algorithm pnx_algorithm = { 61262306a36Sopenharmony_ci .master_xfer = i2c_pnx_xfer, 61362306a36Sopenharmony_ci .functionality = i2c_pnx_func, 61462306a36Sopenharmony_ci}; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_cistatic int i2c_pnx_controller_suspend(struct device *dev) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci clk_disable_unprepare(alg_data->clk); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci return 0; 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic int i2c_pnx_controller_resume(struct device *dev) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci return clk_prepare_enable(alg_data->clk); 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(i2c_pnx_pm, 63362306a36Sopenharmony_ci i2c_pnx_controller_suspend, 63462306a36Sopenharmony_ci i2c_pnx_controller_resume); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic int i2c_pnx_probe(struct platform_device *pdev) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci unsigned long tmp; 63962306a36Sopenharmony_ci int ret = 0; 64062306a36Sopenharmony_ci struct i2c_pnx_algo_data *alg_data; 64162306a36Sopenharmony_ci unsigned long freq; 64262306a36Sopenharmony_ci struct resource *res; 64362306a36Sopenharmony_ci u32 speed = I2C_PNX_SPEED_KHZ_DEFAULT * 1000; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci alg_data = devm_kzalloc(&pdev->dev, sizeof(*alg_data), GFP_KERNEL); 64662306a36Sopenharmony_ci if (!alg_data) 64762306a36Sopenharmony_ci return -ENOMEM; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci platform_set_drvdata(pdev, alg_data); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci alg_data->adapter.dev.parent = &pdev->dev; 65262306a36Sopenharmony_ci alg_data->adapter.algo = &pnx_algorithm; 65362306a36Sopenharmony_ci alg_data->adapter.algo_data = alg_data; 65462306a36Sopenharmony_ci alg_data->adapter.nr = pdev->id; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci alg_data->timeout = I2C_PNX_TIMEOUT_DEFAULT; 65762306a36Sopenharmony_ci#ifdef CONFIG_OF 65862306a36Sopenharmony_ci alg_data->adapter.dev.of_node = of_node_get(pdev->dev.of_node); 65962306a36Sopenharmony_ci if (pdev->dev.of_node) { 66062306a36Sopenharmony_ci of_property_read_u32(pdev->dev.of_node, "clock-frequency", 66162306a36Sopenharmony_ci &speed); 66262306a36Sopenharmony_ci /* 66362306a36Sopenharmony_ci * At this point, it is planned to add an OF timeout property. 66462306a36Sopenharmony_ci * As soon as there is a consensus about how to call and handle 66562306a36Sopenharmony_ci * this, sth. like the following can be put here: 66662306a36Sopenharmony_ci * 66762306a36Sopenharmony_ci * of_property_read_u32(pdev->dev.of_node, "timeout", 66862306a36Sopenharmony_ci * &alg_data->timeout); 66962306a36Sopenharmony_ci */ 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci#endif 67262306a36Sopenharmony_ci alg_data->clk = devm_clk_get(&pdev->dev, NULL); 67362306a36Sopenharmony_ci if (IS_ERR(alg_data->clk)) 67462306a36Sopenharmony_ci return PTR_ERR(alg_data->clk); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci timer_setup(&alg_data->mif.timer, i2c_pnx_timeout, 0); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name), 67962306a36Sopenharmony_ci "%s", pdev->name); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci /* Register I/O resource */ 68262306a36Sopenharmony_ci alg_data->ioaddr = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 68362306a36Sopenharmony_ci if (IS_ERR(alg_data->ioaddr)) 68462306a36Sopenharmony_ci return PTR_ERR(alg_data->ioaddr); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci ret = clk_prepare_enable(alg_data->clk); 68762306a36Sopenharmony_ci if (ret) 68862306a36Sopenharmony_ci return ret; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci freq = clk_get_rate(alg_data->clk); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* 69362306a36Sopenharmony_ci * Clock Divisor High This value is the number of system clocks 69462306a36Sopenharmony_ci * the serial clock (SCL) will be high. 69562306a36Sopenharmony_ci * For example, if the system clock period is 50 ns and the maximum 69662306a36Sopenharmony_ci * desired serial period is 10000 ns (100 kHz), then CLKHI would be 69762306a36Sopenharmony_ci * set to 0.5*(f_sys/f_i2c)-2=0.5*(20e6/100e3)-2=98. The actual value 69862306a36Sopenharmony_ci * programmed into CLKHI will vary from this slightly due to 69962306a36Sopenharmony_ci * variations in the output pad's rise and fall times as well as 70062306a36Sopenharmony_ci * the deglitching filter length. 70162306a36Sopenharmony_ci */ 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci tmp = (freq / speed) / 2 - 2; 70462306a36Sopenharmony_ci if (tmp > 0x3FF) 70562306a36Sopenharmony_ci tmp = 0x3FF; 70662306a36Sopenharmony_ci iowrite32(tmp, I2C_REG_CKH(alg_data)); 70762306a36Sopenharmony_ci iowrite32(tmp, I2C_REG_CKL(alg_data)); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data)); 71062306a36Sopenharmony_ci if (wait_reset(alg_data)) { 71162306a36Sopenharmony_ci ret = -ENODEV; 71262306a36Sopenharmony_ci goto out_clock; 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci init_completion(&alg_data->mif.complete); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci alg_data->irq = platform_get_irq(pdev, 0); 71762306a36Sopenharmony_ci if (alg_data->irq < 0) { 71862306a36Sopenharmony_ci ret = alg_data->irq; 71962306a36Sopenharmony_ci goto out_clock; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, alg_data->irq, i2c_pnx_interrupt, 72262306a36Sopenharmony_ci 0, pdev->name, alg_data); 72362306a36Sopenharmony_ci if (ret) 72462306a36Sopenharmony_ci goto out_clock; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* Register this adapter with the I2C subsystem */ 72762306a36Sopenharmony_ci ret = i2c_add_numbered_adapter(&alg_data->adapter); 72862306a36Sopenharmony_ci if (ret < 0) 72962306a36Sopenharmony_ci goto out_clock; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci dev_dbg(&pdev->dev, "%s: Master at %pap, irq %d.\n", 73262306a36Sopenharmony_ci alg_data->adapter.name, &res->start, alg_data->irq); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci return 0; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ciout_clock: 73762306a36Sopenharmony_ci clk_disable_unprepare(alg_data->clk); 73862306a36Sopenharmony_ci return ret; 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic void i2c_pnx_remove(struct platform_device *pdev) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci i2c_del_adapter(&alg_data->adapter); 74662306a36Sopenharmony_ci clk_disable_unprepare(alg_data->clk); 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci#ifdef CONFIG_OF 75062306a36Sopenharmony_cistatic const struct of_device_id i2c_pnx_of_match[] = { 75162306a36Sopenharmony_ci { .compatible = "nxp,pnx-i2c" }, 75262306a36Sopenharmony_ci { }, 75362306a36Sopenharmony_ci}; 75462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, i2c_pnx_of_match); 75562306a36Sopenharmony_ci#endif 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cistatic struct platform_driver i2c_pnx_driver = { 75862306a36Sopenharmony_ci .driver = { 75962306a36Sopenharmony_ci .name = "pnx-i2c", 76062306a36Sopenharmony_ci .of_match_table = of_match_ptr(i2c_pnx_of_match), 76162306a36Sopenharmony_ci .pm = pm_sleep_ptr(&i2c_pnx_pm), 76262306a36Sopenharmony_ci }, 76362306a36Sopenharmony_ci .probe = i2c_pnx_probe, 76462306a36Sopenharmony_ci .remove_new = i2c_pnx_remove, 76562306a36Sopenharmony_ci}; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic int __init i2c_adap_pnx_init(void) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci return platform_driver_register(&i2c_pnx_driver); 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cistatic void __exit i2c_adap_pnx_exit(void) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci platform_driver_unregister(&i2c_pnx_driver); 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ciMODULE_AUTHOR("Vitaly Wool"); 77862306a36Sopenharmony_ciMODULE_AUTHOR("Dennis Kovalev <source@mvista.com>"); 77962306a36Sopenharmony_ciMODULE_DESCRIPTION("I2C driver for Philips IP3204-based I2C busses"); 78062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 78162306a36Sopenharmony_ciMODULE_ALIAS("platform:pnx-i2c"); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci/* We need to make sure I2C is initialized before USB */ 78462306a36Sopenharmony_cisubsys_initcall(i2c_adap_pnx_init); 78562306a36Sopenharmony_cimodule_exit(i2c_adap_pnx_exit); 786