blob: 73e12ac5e3c308a404eb0a37f3eb2e705bff7eeb [file] [log] [blame]
/* linux/drivers/i2c/busses/i2c-zx29.c
*
* Copyright (C) 2015 Sanechips-TSP
*
* ----------NOTICE-------------
* ZX29 serials I2C Controller driver used by zx297520, this driver
* do not support slave mode. bus clock rate should between 400KHz--100KHz.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/io.h>
//#include <linux/of_i2c.h>
#include <linux/of_gpio.h>
#include <linux/clk/zx29-clk.h>
#include <asm/irq.h>
#include <mach/i2c_private.h>
#include <mach/spinlock.h>
#include <linux/soc/zte/pm/drv_idle.h>
/*#define DEBUG_I2C_ADAPTER*/
#ifdef DEBUG_I2C_ADAPTER
#define drv_printk(fmt, arg...) printk(KERN_DEBUG fmt, ##arg)
#pragma GCC optimize("O0")
#else
#define drv_printk(fmt, arg...)
#endif
#define I2C_PSM_CONTROL (1)
#define I2C_LONG_TRANSFER (1)
#define I2C_FIFO_DEPTH 32
#define I2C_TIMEOUT (msecs_to_jiffies(1000))
#define MAX_BUS_CLK 400000
#define MIN_BUS_CLK 100000
#define I2C_WCLK_FREQ (26*1000*1000)
#if I2C_PSM_CONTROL
static volatile unsigned int i2c_active_count = 0;
#endif
#if I2C_LONG_TRANSFER
/* functions for hrtimer */
static enum hrtimer_restart zx29_i2c_timer_callback(struct hrtimer *timer)
{
struct zx29_i2c *i2c;
enum hrtimer_restart ret = HRTIMER_NORESTART;
i2c = container_of(timer, struct zx29_i2c, hr_timer);
if ((i2c->state == STATE_READ) && (i2c->buf_remaining > I2C_FIFO_DEPTH)) {
unsigned int len_rx = 0;
unsigned int len_diff = 0;
u8 *buf = i2c->msg->buf;
u8 val = 0;
len_rx = i2c_get_rx_fifo_length(i2c);
len_diff = i2c->buf_remaining - I2C_FIFO_DEPTH;
if (len_rx < len_diff) {
ret = HRTIMER_RESTART;
hrtimer_forward_now(timer, i2c->ktime);
} else {
len_rx = len_diff;
}
i2c->buf_remaining -= len_rx;
/*read data from fifo*/
while (len_rx--) {
val = (u8)i2c_read_data(i2c);
*(buf + i2c->msg_ptr) = val;
i2c->msg_ptr++;
}
} else if ((i2c->state == STATE_WRITE) && (i2c->buf_remaining > 0)) {
unsigned int len_tx = 0;
unsigned int len_diff = 0;
u8 *buf = i2c->msg->buf;
u8 val = 0;
len_tx = i2c_get_tx_fifo_length(i2c);
len_tx = I2C_FIFO_DEPTH - len_tx;
len_diff = i2c->buf_remaining;
if (len_tx < len_diff) {
ret = HRTIMER_RESTART;
hrtimer_forward_now(timer, i2c->ktime);
} else {
len_tx = len_diff;
}
i2c->buf_remaining -= len_tx;
/* write data to fifo */
while (len_tx--) {
val = *(buf + i2c->msg_ptr);
i2c_write_data(i2c, val);
i2c->msg_ptr++;
}
}
return ret;
}
static void zx29_i2c_start_timer( struct zx29_i2c *i2c )
{
unsigned long delay_in_us = (9*I2C_FIFO_DEPTH/2)*1000*1000 / i2c->clkrate;
i2c->ktime = ktime_set(0, delay_in_us * 1000);
hrtimer_init( &i2c->hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
i2c->hr_timer.function = zx29_i2c_timer_callback;
hrtimer_start( &i2c->hr_timer, i2c->ktime, HRTIMER_MODE_REL );
}
static void zx29_i2c_stop_timer( struct zx29_i2c *i2c )
{
int ret;
ret = hrtimer_cancel(&i2c->hr_timer);
if(ret){
pr_info("%s return %d\n", __FUNCTION__, ret);
}
return;
}
#endif
/* functions for hrtimer end */
#if I2C_PSM_CONTROL
static void zx29_i2c_set_active(struct wake_lock *lock)
{
unsigned long flags;
local_irq_save(flags);
if(i2c_active_count == 0)
{
zx_cpuidle_set_busy(IDLE_FLAG_I2C);
}
i2c_active_count++;
local_irq_restore(flags);
wake_lock(lock);
}
static void zx29_i2c_set_idle(struct wake_lock *lock)
{
unsigned long flags;
local_irq_save(flags);
i2c_active_count--;
if(i2c_active_count == 0)
{
zx_cpuidle_set_free(IDLE_FLAG_I2C);
}
local_irq_restore(flags);
wake_unlock(lock);
}
#endif
#ifdef CONFIG_SYSFS
static ssize_t zx29_i2c_sysfs_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t zx29_i2c_sysfs_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
DEVICE_ATTR(clk_rate, S_IWUSR | S_IRUGO, zx29_i2c_sysfs_show, zx29_i2c_sysfs_store);
static struct attribute * zx29_i2c_sysfs_attrs[] = {
&dev_attr_clk_rate.attr,
NULL
};
static const struct attribute_group zx29_i2c_sysfs_attr_group = {
.attrs = zx29_i2c_sysfs_attrs,
};
static int zx29_i2c_sysfs_create_group(struct zx29_i2c *i2c)
{
return sysfs_create_group(&i2c->dev->kobj, &zx29_i2c_sysfs_attr_group);
}
static void zx29_i2c_sysfs_remove_group(struct zx29_i2c *i2c)
{
sysfs_remove_group(&i2c->dev->kobj, &zx29_i2c_sysfs_attr_group);
}
static ssize_t zx29_i2c_sysfs_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct zx29_i2c *i2c = dev_get_drvdata(dev);
if (!i2c)
return -EINVAL;
return scnprintf(buf, PAGE_SIZE, "%ld\n", i2c->clkrate);
}
static ssize_t zx29_i2c_sysfs_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct zx29_i2c *i2c = dev_get_drvdata(dev);
unsigned long clock_rate = 0;
if(strict_strtoul(buf, 0, &clock_rate))
return -EINVAL;
if((clock_rate < MIN_BUS_CLK) || (clock_rate > MAX_BUS_CLK) || (NULL == i2c))
return -EINVAL;
i2c_lock_adapter(&i2c->adap);
i2c->clkrate = clock_rate;
i2c_unlock_adapter(&i2c->adap);
pr_info("new i2c%d scl rate: %ld\n", i2c->id, i2c->clkrate);
return count;
}
#else
static int zx29_i2c_sysfs_create_group(struct zx29_i2c *i2c)
{
return 0;
}
static void zx29_i2c_sysfs_remove_group(struct zx29_i2c *i2c)
{
return;
}
#endif
static emsf_lock_id i2c_get_sflock(unsigned int i2c_id)
{
emsf_lock_id softLock = I2C2_SFLOCK;
switch(i2c_id)
{
case 0: //pmic i2c
softLock = I2C2_SFLOCK;
break;
case 1:
softLock = I2C1_SFLOCK;
break;
default:
BUG();
}
return softLock;
}
/*
* zx29_i2c_init
*
* initialise the controller, set frequency
*/
static int zx29_i2c_init(struct zx29_i2c *i2c)
{
unsigned int bus_clk;
unsigned int pdiv;
emsf_lock_id softLock = i2c_get_sflock(i2c->id);
unsigned long actual_clk = 0;
soft_spin_lock(softLock);
/*reset*/
zx29_i2c_reset_fifo(i2c);
udelay(1);
/*calculate bus clock division, fix input clock is 26M*/
bus_clk=i2c->clkrate/1000; /*in KHz*/
pdiv=((I2C_WCLK_FREQ/1000)/4)/bus_clk - 1;
if(((I2C_WCLK_FREQ/1000)/4) % bus_clk != 0){
pdiv++;
}
actual_clk = (I2C_WCLK_FREQ/4)/(pdiv+1); /*actul bus clock rate*/
if ((actual_clk > MAX_BUS_CLK) || (actual_clk < MIN_BUS_CLK)){
pr_warn("bus clock rate error %ld!\n", actual_clk);
BUG();
}
i2c_set_clk_div(i2c, pdiv);
/*master mode, disable interrupt, clear interrupt*/
i2c_set_cmd(i2c, 0x1);
soft_spin_unlock(softLock);
i2c->state = STATE_IDLE;
return 0;
}
/*
*zx29_i2c_start
* put the start of a message onto the bus
*/
static void zx29_i2c_start(struct zx29_i2c *i2c, uint8_t fmt)
{
unsigned int addr = i2c->msg->addr;
unsigned long ctrl = 0;
unsigned int addr_mode = 0;
/*set slave device address*/
addr_mode = i2c->msg->flags & I2C_M_TEN;
i2c_set_addr(i2c, addr, addr_mode);
i2c_clr_irq_ack(i2c);
/*set cmd register for rx or tx*/
ctrl = i2c_get_cmd(i2c);
ctrl &= ~CMD_I2C_FMT_MSK;
ctrl |= fmt;
if (addr_mode){
/*10 bit address mode :clear interrupt conditions, set master mode,set 10bit address mode and start*/
ctrl |= CMD_I2C_START|CMD_I2C_MODE|CMD_TENBIT_MODE;
}
else{
/*7 bit address mode:clear interrupt conditions, set master mode and start*/
ctrl &= ~CMD_TENBIT_MODE;
ctrl |= CMD_I2C_START|CMD_I2C_MODE;
}
i2c_set_cmd(i2c, ctrl);
}
/*
* zx29_i2c_stop
*/
static inline void zx29_i2c_stop(struct zx29_i2c *i2c)
{
//unsigned long ctrl = ioread32(i2c->regs + I2C_CMD);
/* stop the transfer ,clear interrupt conditions */
//ctrl |= CMD_I2C_STOP|CMD_IRQ_ACK;
//iowrite32(ctrl, i2c->regs + I2C_CMD);
i2c->state = STATE_STOP;
}
/*
* check i2c busy or not
*/
static inline int zx29_i2c_is_busy(struct zx29_i2c *i2c)
{
unsigned int time_out=0xff;
while(time_out--){
if(i2c_get_bus_status(i2c)==0)
return 0;
else
udelay(1);
}
return -ETIMEDOUT;
}
/*
* i2c fifo write
*/
static void zx29_i2c_prepare_write(struct zx29_i2c *i2c)
{
u8 val=0;
u8 *buf=i2c->msg->buf;
u16 len =i2c->buf_remaining;
u16 len_tx = 0;
unsigned int ret=0;
/*this step must be done. because FIFO empty interrupt does not mean bus is idle*/
ret=zx29_i2c_is_busy(i2c);
if(ret)
BUG();
zx29_i2c_reset_tx_fifo(i2c);
if(len > I2C_FIFO_DEPTH)
len_tx = I2C_FIFO_DEPTH;
else
len_tx = len;
i2c->buf_remaining -= len_tx;
i2c_set_tx_fifo_depth(i2c, len_tx-1);
/*write data to fifo*/
while(len_tx--){
val = *(buf + i2c->msg_ptr);
i2c_write_data(i2c, val);
i2c->msg_ptr++;
}
barrier();
// zx29_i2c_start(i2c);
}
/*
* i2c start read
*/
static void zx29_i2c_prepare_read(struct zx29_i2c *i2c)
{
u16 len =i2c->buf_remaining;
u16 len_rx = 0;
unsigned int ret=0;
/*i2c can only be operated when bus is idle*/
ret=zx29_i2c_is_busy(i2c);
if(ret)
BUG();
zx29_i2c_reset_rx_fifo(i2c);
if(len > I2C_FIFO_DEPTH)
len_rx = I2C_FIFO_DEPTH;
else
len_rx = len;
i2c_set_rx_fifo_depth(i2c, len_rx-1);
// zx29_i2c_start(i2c);
}
/*
* i2c fifo read
*/
static void zx29_i2c_read_fifo(struct zx29_i2c *i2c)
{
unsigned int len_rx=0;
u8 *buf=i2c->msg->buf;
u8 val=0;
len_rx = i2c_get_rx_fifo_length(i2c);
i2c->buf_remaining -= len_rx;
/*read data from fifo*/
while(len_rx--){
val =(u8) i2c_read_data(i2c);
*(buf + i2c->msg_ptr) = val;
i2c->msg_ptr++;
}
}
/* zx29_i2c_irq
*
* top level IRQ servicing routine
*/
static irqreturn_t zx29_i2c_irq(int irqno, void *dev_id)
{
struct zx29_i2c *i2c = dev_id;
unsigned long status;
status = i2c_get_irq_status(i2c);
i2c->reg_status = (i2c->reg_status << 8) | status;
/*
* if state is idle or stop, maybe other core on 7510 platform trigger interrupt
* it will be looked as spurious interrupt, nothing need to be done
*/
if ((i2c->state == STATE_IDLE) || (i2c->state == STATE_STOP))
return IRQ_HANDLED;
if (status & (IRQ_ERR_DEVICE | IRQ_ERR_DATA | IRQ_TRANS_DONE)) {
i2c_disable_irq(i2c);
disable_irq_nosync(i2c->irq);
up(&i2c->msg_complete);
return IRQ_HANDLED;
}
if (status & IRQ_TIME_OUT) {
i2c_clr_irq_ack(i2c);
return IRQ_HANDLED;
}
return IRQ_HANDLED;
}
/* zx29_i2c_get_bus
*
* get the i2c bus for a master transaction
*/
static int zx29_i2c_get_bus(struct zx29_i2c *i2c)
{
int timeout = 400;
while (timeout-- > 0) {
if (!i2c_get_bus_status(i2c))
return 0;
msleep(1);
}
return -ETIMEDOUT;
}
/* zx29_i2c_doxfer
*
* this starts an i2c transfer
*/
static int zx29_i2c_doxfer(struct zx29_i2c *i2c, struct i2c_msg *msgs, bool cmb_rw)
{
int ret;
if (i2c->suspended)
return -EIO;
i2c->msg = msgs;
i2c->msg_ptr = 0;
i2c->buf_remaining = msgs->len;
// i2c->msg_idx = 0;
// init_completion(&(i2c->msg_complete));
if (unlikely(i2c->msg_complete.count)) {
pr_err("i2c sem %d\n", i2c->msg_complete.count);
}
i2c->reg_status = 0;
i2c_clr_irq_ack(i2c);
i2c_enable_irq(i2c);
enable_irq(i2c->irq);
if (cmb_rw) {
zx29_i2c_prepare_write(i2c);
i2c->msg = &msgs[1];
i2c->msg_ptr = 0;
i2c->buf_remaining = msgs[1].len;
i2c->state = STATE_READ;
memset(msgs[1].buf, 0, msgs[1].len);
zx29_i2c_prepare_read(i2c);
zx29_i2c_start(i2c, CMD_I2C_FMT_CMB);
} else if (i2c->msg->flags & I2C_M_RD) {
i2c->state = STATE_READ;
memset(msgs->buf, 0, msgs->len);
zx29_i2c_prepare_read(i2c);
zx29_i2c_start(i2c, CMD_I2C_FMT_RD);
} else {
i2c->state = STATE_WRITE;
zx29_i2c_prepare_write(i2c);
zx29_i2c_start(i2c, CMD_I2C_FMT_WR);
}
#if I2C_LONG_TRANSFER
if (i2c->msg->len > I2C_FIFO_DEPTH) {
zx29_i2c_start_timer(i2c);
}
#endif
/* waiting for tranfer finished */
ret = down_timeout(&i2c->msg_complete, I2C_TIMEOUT);
#if I2C_LONG_TRANSFER
if (i2c->msg->len > I2C_FIFO_DEPTH) {
zx29_i2c_stop_timer(i2c);
}
#endif
if (ret < 0) {
i2c_disable_irq(i2c);
disable_irq_nosync(i2c->irq);
pr_err("i2c transfer timeout\n");
zx29_i2c_stop(i2c);
zx29_i2c_init(i2c);
return -ETIMEDOUT;
}
if (i2c->state == STATE_READ) {
zx29_i2c_read_fifo(i2c);
}
/* slave no ack on address phase or data phase */
if (i2c_get_irq_status(i2c) & (IRQ_ERR_DEVICE | IRQ_ERR_DATA)) {
pr_err("NACK by slave 0x%X, status %X\n", i2c->msg->addr, i2c_get_irq_status(i2c));
while (~ i2c_get_irq_status(i2c) & IRQ_TRANS_DONE);
i2c_clr_irq_ack(i2c);
zx29_i2c_init(i2c);
return -ECOMM;
}
i2c_clr_irq_ack(i2c);
i2c->state = STATE_IDLE;
#if I2C_LONG_TRANSFER
if(i2c->buf_remaining) {
pr_err("%s: %d/%d isn't transferred\n", __FUNCTION__, i2c->buf_remaining, i2c->msg->len);
return -EAGAIN;
}
#endif
return 0;
}
/* zx29_i2c_xfer
*
* first port of call from the i2c bus code when an message needs
* transferring across the i2c bus.
*/
static int zx29_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
struct zx29_i2c *i2c = (struct zx29_i2c *)adap->algo_data;
int ret;
int i = 0;
bool combie_rw_applicable;
unsigned int pdiv;
emsf_lock_id softLock = i2c_get_sflock(i2c->id);
if (i2c->suspended)
return -EIO;
if (msgs->len == 0)
return -EINVAL;
#if I2C_PSM_CONTROL
zx29_i2c_set_active(&i2c->psm_lock);
#endif
soft_spin_lock(softLock);
#ifdef CONFIG_ARCH_ZX297502
clk_enable(i2c->clk);
#endif
ret = zx29_i2c_get_bus(i2c);
if (ret != 0) {
dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
//soft_spin_unlock(I2C_SFLOCK); /* zhouqi */
ret = -EAGAIN;
goto exit;
}
/* calculate bus clock division, fixed input clock is 26M */
pdiv = (I2C_WCLK_FREQ / 4 / i2c->clkrate) - 1;
if((I2C_WCLK_FREQ / 4) % i2c->clkrate != 0)
pdiv++;
i2c_set_clk_div(i2c, pdiv);
// i2c->msg_num = num;
/* check whether combined rw is applicable */
if ((num == 2) && (msgs[0].addr == msgs[1].addr)) {
combie_rw_applicable = ((msgs[0].flags & I2C_M_TEN) == (msgs[1].flags & I2C_M_TEN)) \
&& (~msgs[0].flags & I2C_M_RD) \
&& (msgs[1].flags & I2C_M_RD) \
&& (msgs[0].len <= I2C_FIFO_DEPTH);
} else
combie_rw_applicable = 0;
if (combie_rw_applicable) {
ret = zx29_i2c_doxfer(i2c, msgs, 1);
} else for (i = 0; i < num; i++) {
ret = zx29_i2c_doxfer(i2c, &msgs[i], 0);
// i2c->msg_idx=i;
if (ret) {
//printk(KERN_INFO "%s err code=%d\n", __FUNCTION__, ret);
break;
}
}
exit:
#ifdef CONFIG_ARCH_ZX297502
clk_disable(i2c->clk);
#endif
soft_spin_unlock(softLock);
#if I2C_PSM_CONTROL
zx29_i2c_set_idle(&i2c->psm_lock);
#endif
return ret ? ret : num;
}
/* declare our i2c functionality */
static u32 zx29_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK)| I2C_FUNC_10BIT_ADDR;
}
/* i2c bus registration info */
static const struct i2c_algorithm zx29_i2c_algorithm = {
.master_xfer = zx29_i2c_xfer,
.functionality = zx29_i2c_func,
};
#ifdef CONFIG_OF
/* zx29_i2c_parse_dt
*
* Parse the device tree node and retreive the platform data.
*/
static void
zx29_i2c_parse_dt(struct device_node *np, struct zx29_i2c *i2c)
{
struct zx29_i2c_platform_data *pdata = i2c->pdata;
if (!np)
return;
of_property_read_u32(np, "Sanechips-tsp,i2c-slave-addr", &pdata->slave_addr);
of_property_read_u32(np, "Sanechips-tsp,i2c-max-bus-freq",(u32 *)&pdata->max_bus_clk);
}
#else
static void
zx29_i2c_parse_dt(struct device_node *np, struct zx29_i2c *i2c)
{
return;
}
#endif
static int i2c_init_clks(struct platform_device *pdev, struct zx29_i2c *i2c)
{
/* find the clock and enable it */
i2c->clk = clk_get(&pdev->dev, "work_clk");
if (IS_ERR(i2c->clk)) {
dev_err(&pdev->dev, "cannot get work clock\n");
return -ENOENT;
}
/* set i2c work clock at 26MHz/1 */
clk_set_rate(i2c->clk, I2C_WCLK_FREQ);
clk_enable(i2c->clk);
i2c->pclk = clk_get(&pdev->dev, "apb_clk");
if (IS_ERR(i2c->pclk)) {
dev_err(&pdev->dev, "cannot get apb clock\n");
return -ENOENT;
}
clk_enable(i2c->pclk);
clk_set_auto_gate(i2c->clk, true);
clk_set_auto_gate(i2c->pclk, true);
return 0;
}
/* zx29_i2c_probe
*
* called by the bus driver when a suitable device is found
*/
static int zx29_i2c_probe(struct platform_device *pdev)
{
struct zx29_i2c *i2c=NULL;
struct zx29_i2c_platform_data *pdata = NULL;
struct resource *res=NULL;
void __iomem *base=NULL;
const unsigned int *prop=NULL;
int ret=0;
emsf_lock_id softLock;
/* irq&register */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no memory resource\n");
ret = -EINVAL;
goto err_iomap;
}
base = (void __iomem *)(res->start);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(&pdev->dev, "no irq resource\n");
ret = -EINVAL;
goto err_iomap;
}
i2c = devm_kzalloc(&pdev->dev, sizeof(struct zx29_i2c), GFP_KERNEL);
if (!i2c) {
dev_err(&pdev->dev, "no memory for state\n");
ret = -ENOMEM;
goto err_iomap;
}
if (!pdev->dev.of_node) {
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "no platform data\n");
return -EINVAL;
}
}
snprintf(i2c->name, sizeof(i2c->name), "zx29-i2c%d", pdev->id);
i2c->pdata = pdata;
i2c->id = pdev->id;
i2c->regs = base;
i2c->irq = res->start;
i2c->dev = &pdev->dev;
i2c->state = STATE_IDLE;
i2c->clkrate = MIN_BUS_CLK; /* default clock rate */
if (pdata) {
i2c->clkrate = pdata->bus_clk_rate;
}
else if (i2c->dev->of_node) { /* if there is a device tree node ... */
prop = of_get_property(i2c->dev->of_node,
"clock-frequency", NULL);
if (prop)
i2c->clkrate = be32_to_cpup(prop);
}
spin_lock_init(&i2c->lock);
sema_init(&i2c->msg_complete, 0);
softLock = i2c_get_sflock(i2c->id);
soft_spin_lock(softLock);
i2c_config_pins(i2c);
ret = i2c_init_clks(pdev, i2c);
if(ret < 0)
{
soft_spin_unlock(softLock);
goto err_free;
}
/* initialise the i2c controller */
ret = zx29_i2c_init(i2c);
if (ret != 0){
soft_spin_unlock(softLock);
goto err_free;
}
i2c_disable_irq(i2c);
/* find the IRQ for this unit (note, this relies on the init call to
* ensure no current IRQs pending
*/
ret = devm_request_irq(&pdev->dev, i2c->irq, zx29_i2c_irq,
IRQF_TRIGGER_HIGH | IRQF_NO_THREAD | IRQF_ONESHOT,
dev_name(&pdev->dev), i2c);
if (ret != 0) {
dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
soft_spin_unlock(softLock);
goto err_clk;
}
disable_irq_nosync(i2c->irq);
soft_spin_unlock(softLock);
/* Note, previous versions of the driver used i2c_add_adapter()
* to add the bus at any number. We now pass the bus number via
* the platform data, so if unset it will now default to always
* being bus 0.
*/
zx29_i2c_parse_dt(pdev->dev.of_node, i2c);
strlcpy(i2c->adap.name, "zx29-i2c", sizeof(i2c->adap.name));
i2c->adap.owner = THIS_MODULE;
i2c->adap.algo = &zx29_i2c_algorithm;
i2c->adap.retries = 3;
i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
i2c->adap.algo_data = i2c;
i2c->adap.dev.parent = &pdev->dev;
i2c->adap.nr = pdev->id;
i2c->adap.dev.of_node = pdev->dev.of_node;
#if I2C_PSM_CONTROL
wake_lock_init(&i2c->psm_lock, WAKE_LOCK_SUSPEND, i2c->name);
#endif
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret < 0) {
dev_err(&pdev->dev, "failed to add bus to i2c core\n");
goto err_irq;
}
// of_i2c_register_devices(&i2c->adap);
platform_set_drvdata(pdev, i2c);
zx29_i2c_sysfs_create_group(i2c);
dev_info(&pdev->dev, "%s: ZX29 I2C adapter\n", dev_name(&i2c->adap.dev));
#ifdef CONFIG_ARCH_ZX297502
clk_disable(i2c->clk);
#endif
return 0;
/*err_cpufreq:
zx29_i2c_deregister_cpufreq(i2c);*/
err_irq:
#if I2C_PSM_CONTROL
wake_lock_destroy(&i2c->psm_lock);
#endif
devm_free_irq(&pdev->dev, i2c->irq, i2c);
err_clk:
clk_disable(i2c->clk);
clk_put(i2c->clk);
clk_disable(i2c->pclk);
clk_put(i2c->pclk);
err_free:
kfree(i2c);
err_iomap:
// iounmap(base);
return ret;
}
/* zx29_i2c_remove
*
* called when device is removed from the bus
*/
static int zx29_i2c_remove(struct platform_device *pdev)
{
struct zx29_i2c *i2c = platform_get_drvdata(pdev);
zx29_i2c_sysfs_remove_group(i2c);
i2c_del_adapter(&i2c->adap);
clk_disable(i2c->clk);
clk_put(i2c->clk);
clk_disable(i2c->pclk);
clk_put(i2c->pclk);
#if I2C_PSM_CONTROL
wake_lock_destroy(&i2c->psm_lock);
#endif
return 0;
}
#ifdef CONFIG_PM
static int zx29_i2c_suspend(struct platform_device *pdev, pm_message_t state)
{
#ifdef CONFIG_ARCH_ZX297502
struct zx29_i2c *i2c = platform_get_drvdata(pdev);
i2c_lock_adapter(&i2c->adap);
i2c->suspended = 1;
i2c_unlock_adapter(&i2c->adap);
#endif
return 0;
}
static int zx29_i2c_resume(struct platform_device *pdev)
{
#ifdef CONFIG_ARCH_ZX297502
struct zx29_i2c *i2c = platform_get_drvdata(pdev);
i2c_lock_adapter(&i2c->adap);
clk_enable(i2c->clk);
zx29_i2c_init(i2c);
clk_disable(i2c->clk);
i2c->suspended = 0;
i2c_unlock_adapter(&i2c->adap);
#endif
return 0;
}
#endif
#ifdef CONFIG_OF
static const struct of_device_id zx29_i2c_match[] = {
{ .compatible = "Sanechips-TSP, zx29_i2c0" },
{},
};
MODULE_DEVICE_TABLE(of, zx29_i2c_match);
#else
#define zx29_i2c_match NULL
#endif
static struct platform_driver zx29_i2c_driver = {
.probe = zx29_i2c_probe,
.remove = zx29_i2c_remove,
#ifdef CONFIG_PM
.suspend = zx29_i2c_suspend,
.resume = zx29_i2c_resume,
#endif
.driver = {
.owner = THIS_MODULE,
.name = "zx29_i2c",
.of_match_table = zx29_i2c_match,
},
};
static int __init i2c_adap_zx29_init(void)
{
int ret;
ret=platform_driver_register(&zx29_i2c_driver);
if (ret<0) {
pr_err("zx29 i2c driver register fail\n");
}
return ret;
}
subsys_initcall(i2c_adap_zx29_init);
static void __exit i2c_adap_zx29_exit(void)
{
platform_driver_unregister(&zx29_i2c_driver);
}
module_exit(i2c_adap_zx29_exit);