| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866 |
- /*
- * Copyright (c) 2014 MediaTek Inc.
- * Author: Xudong.chen <xudong.chen@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <linux/i2c.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/sched.h>
- #include <linux/delay.h>
- #include <linux/errno.h>
- #include <linux/err.h>
- #include <linux/device.h>
- #include <linux/platform_device.h>
- #include <linux/wait.h>
- #include <linux/mm.h>
- #include <linux/dma-mapping.h>
- #include <linux/scatterlist.h>
- #include <linux/io.h>
- #include <linux/of_address.h>
- #include <linux/of_irq.h>
- #include <linux/clk.h>
- #include <mt_cpufreq_hybrid.h>
- #include "i2c-mtk.h"
- static inline void i2c_writew(u16 value, struct mt_i2c *i2c, u8 offset)
- {
- writew(value, i2c->base + offset);
- }
- static inline u16 i2c_readw(struct mt_i2c *i2c, u8 offset)
- {
- return readw(i2c->base + offset);
- }
- static inline void i2c_writel_dma(u32 value, struct mt_i2c *i2c, u8 offset)
- {
- writel(value, i2c->pdmabase + offset);
- }
- static int mt_i2c_clock_enable(struct mt_i2c *i2c)
- {
- int ret;
- ret = clk_prepare_enable(i2c->clk_dma);
- if (ret)
- return ret;
- if (i2c->id != 6) { /* the clock of i2c6 will always on */
- if (i2c->clk_arb != NULL) {
- ret = clk_prepare_enable(i2c->clk_arb);
- if (ret)
- return ret;
- }
- clk_prepare_enable(i2c->clk_main);
- if (ret)
- goto err_main;
- }
- if (i2c->have_pmic) {
- ret = clk_prepare_enable(i2c->clk_pmic);
- if (ret)
- goto err_pmic;
- }
- return 0;
- err_pmic:
- clk_disable_unprepare(i2c->clk_main);
- err_main:
- clk_disable_unprepare(i2c->clk_dma);
- return ret;
- }
- static void mt_i2c_clock_disable(struct mt_i2c *i2c)
- {
- if (i2c->have_pmic)
- clk_disable_unprepare(i2c->clk_pmic);
- if (i2c->id != 6) { /* the clock of i2c6 will always on */
- clk_disable_unprepare(i2c->clk_main);
- if (i2c->clk_arb != NULL)
- clk_disable_unprepare(i2c->clk_arb);
- }
- clk_disable_unprepare(i2c->clk_dma);
- }
- static int i2c_get_semaphore(struct mt_i2c *i2c)
- {
- if (i2c->id != 6)
- return 0;
- if (cpuhvfs_get_dvfsp_semaphore(SEMA_I2C_DRV) != 0) {
- dev_err(i2c->dev, "sema time out 2ms\n");
- if (cpuhvfs_get_dvfsp_semaphore(SEMA_I2C_DRV) != 0) {
- dev_err(i2c->dev, "sema time out 4ms\n");
- BUG_ON(1);
- return -EBUSY;
- }
- }
- return 0;
- }
- static int i2c_release_semaphore(struct mt_i2c *i2c)
- {
- if (i2c->id != 6)
- return 0;
- cpuhvfs_release_dvfsp_semaphore(SEMA_I2C_DRV);
- return 0;
- }
- static void free_i2c_dma_bufs(struct mt_i2c *i2c)
- {
- dma_free_coherent(i2c->adap.dev.parent, PAGE_SIZE,
- i2c->dma_buf.vaddr, i2c->dma_buf.paddr);
- }
- static inline void mt_i2c_init_hw(struct mt_i2c *i2c)
- {
- i2c_writew(I2C_SOFT_RST, i2c, OFFSET_SOFTRESET);
- /* Set ioconfig */
- if (i2c->use_push_pull)
- i2c_writew(I2C_IO_CONFIG_PUSH_PULL, i2c, OFFSET_IO_CONFIG);
- else
- i2c_writew(I2C_IO_CONFIG_OPEN_DRAIN, i2c, OFFSET_IO_CONFIG);
- if (i2c->have_dcm)
- i2c_writew(I2C_DCM_DISABLE, i2c, OFFSET_DCM_EN);
- i2c_writew(i2c->timing_reg, i2c, OFFSET_TIMING);
- i2c_writew(i2c->high_speed_reg, i2c, OFFSET_HS);
- }
- /* calculate i2c port speed */
- static int i2c_set_speed(struct mt_i2c *i2c, unsigned int clk_src_in_hz)
- {
- int mode;
- unsigned int khz;
- unsigned int step_cnt;
- unsigned int sample_cnt;
- unsigned int sclk;
- unsigned int hclk;
- unsigned int max_step_cnt;
- unsigned int sample_div = MAX_SAMPLE_CNT_DIV;
- unsigned int step_div;
- unsigned int min_div;
- unsigned int best_mul;
- unsigned int cnt_mul;
- unsigned int speed_hz;
- if (i2c->ext_data.isEnable && i2c->ext_data.timing)
- speed_hz = i2c->ext_data.timing;
- else
- speed_hz = i2c->speed_hz;
- if (speed_hz > MAX_HS_MODE_SPEED) {
- return -EINVAL;
- } else if (speed_hz > MAX_FS_MODE_SPEED) {
- mode = HS_MODE;
- max_step_cnt = MAX_HS_STEP_CNT_DIV;
- } else {
- mode = FS_MODE;
- max_step_cnt = MAX_STEP_CNT_DIV;
- }
- step_div = max_step_cnt;
- /* Find the best combination */
- khz = speed_hz / 1000;
- hclk = clk_src_in_hz / 1000;
- min_div = ((hclk >> 1) + khz - 1) / khz;
- best_mul = MAX_SAMPLE_CNT_DIV * max_step_cnt;
- for (sample_cnt = 1; sample_cnt <= MAX_SAMPLE_CNT_DIV; sample_cnt++) {
- step_cnt = (min_div + sample_cnt - 1) / sample_cnt;
- cnt_mul = step_cnt * sample_cnt;
- if (step_cnt > max_step_cnt)
- continue;
- if (cnt_mul < best_mul) {
- best_mul = cnt_mul;
- sample_div = sample_cnt;
- step_div = step_cnt;
- if (best_mul == min_div)
- break;
- }
- }
- sample_cnt = sample_div;
- step_cnt = step_div;
- sclk = hclk / (2 * sample_cnt * step_cnt);
- if (sclk > khz) {
- dev_dbg(i2c->dev, "%s mode: unsupported speed (%ldkhz)\n",
- (mode == HS_MODE) ? "HS" : "ST/FT", (long int)khz);
- return -ENOTSUPP;
- }
- step_cnt--;
- sample_cnt--;
- if (mode == HS_MODE) {
- /* Set the hign speed mode register */
- i2c->timing_reg = 0x1303;
- i2c->high_speed_reg = I2C_TIME_DEFAULT_VALUE |
- (sample_cnt & I2C_TIMING_SAMPLE_COUNT_MASK) << 12 |
- (step_cnt & I2C_TIMING_SAMPLE_COUNT_MASK) << 8;
- } else {
- i2c->timing_reg =
- (sample_cnt & I2C_TIMING_SAMPLE_COUNT_MASK) << 8 |
- (step_cnt & I2C_TIMING_STEP_DIV_MASK) << 0;
- /* Disable the high speed transaction */
- i2c->high_speed_reg = I2C_TIME_CLR_VALUE;
- }
- return 0;
- }
- #ifdef I2C_DEBUG_FS
- void i2c_dump_info1(struct mt_i2c *i2c)
- {
- if (i2c->ext_data.isEnable && i2c->ext_data.timing)
- dev_err(i2c->dev, "I2C structure:\nspeed %d\n",
- i2c->ext_data.timing);
- else
- dev_err(i2c->dev, "I2C structure:\nspeed %d\n",
- i2c->speed_hz);
- dev_err(i2c->dev, "I2C structure:\nOp %x\n", i2c->op);
- dev_err(i2c->dev,
- "I2C structure:\nData_size %x\nIrq_stat %x\nTrans_stop %d\n",
- i2c->msg_len, i2c->irq_stat, i2c->trans_stop);
- dev_err(i2c->dev, "base address %p\n", i2c->base);
- dev_err(i2c->dev,
- "I2C register:\nSLAVE_ADDR %x\nINTR_MASK %x\n",
- (i2c_readw(i2c, OFFSET_SLAVE_ADDR)),
- (i2c_readw(i2c, OFFSET_INTR_MASK)));
- dev_err(i2c->dev,
- "I2C register:\nINTR_STAT %x\nCONTROL %x\n",
- (i2c_readw(i2c, OFFSET_INTR_STAT)),
- (i2c_readw(i2c, OFFSET_CONTROL)));
- dev_err(i2c->dev,
- "I2C register:\nTRANSFER_LEN %x\nTRANSAC_LEN %x\n",
- (i2c_readw(i2c, OFFSET_TRANSFER_LEN)),
- (i2c_readw(i2c, OFFSET_TRANSAC_LEN)));
- dev_err(i2c->dev,
- "I2C register:\nDELAY_LEN %x\nTIMING %x\n",
- (i2c_readw(i2c, OFFSET_DELAY_LEN)),
- (i2c_readw(i2c, OFFSET_TIMING)));
- dev_err(i2c->dev,
- "I2C register:\nSTART %x\nFIFO_STAT %x\n",
- (i2c_readw(i2c, OFFSET_START)),
- (i2c_readw(i2c, OFFSET_FIFO_STAT)));
- dev_err(i2c->dev,
- "I2C register:\nIO_CONFIG %x\nHS %x\n",
- (i2c_readw(i2c, OFFSET_IO_CONFIG)),
- (i2c_readw(i2c, OFFSET_HS)));
- dev_err(i2c->dev,
- "I2C register:\nDEBUGSTAT %x\nEXT_CONF %x\nPATH_DIR %x\n",
- (i2c_readw(i2c, OFFSET_DEBUGSTAT)),
- (i2c_readw(i2c, OFFSET_EXT_CONF)),
- (i2c_readw(i2c, OFFSET_PATH_DIR)));
- }
- void i2c_dump_info(struct mt_i2c *i2c)
- {
- /* I2CFUC(); */
- /* int val=0; */
- pr_err("i2c_dump_info ++++++++++++++++++++++++++++++++++++++++++\n");
- pr_err("I2C structure:\n"
- I2CTAG "Clk=%d,Id=%d,Op=%x,Irq_stat=%x\n"
- I2CTAG "Trans_len=%x,Trans_num=%x,Trans_auxlen=%x,speed=%d\n"
- I2CTAG "Trans_stop=%u\n",
- 15600, i2c->id, i2c->op, i2c->irq_stat,
- i2c->msg_len, 1, i2c->msg_aux_len, i2c->speed_hz, i2c->trans_stop);
- pr_err("base address 0x%p\n", i2c->base);
- pr_err("I2C register:\n"
- I2CTAG "SLAVE_ADDR=%x,INTR_MASK=%x,INTR_STAT=%x,CONTROL=%x,TRANSFER_LEN=%x\n"
- I2CTAG "TRANSAC_LEN=%x,DELAY_LEN=%x,TIMING=%x,START=%x,FIFO_STAT=%x\n"
- I2CTAG "IO_CONFIG=%x,HS=%x,DCM_EN=%x,DEBUGSTAT=%x,EXT_CONF=%x,TRANSFER_LEN_AUX=%x\n",
- (i2c_readw(i2c, OFFSET_SLAVE_ADDR)),
- (i2c_readw(i2c, OFFSET_INTR_MASK)),
- (i2c_readw(i2c, OFFSET_INTR_STAT)),
- (i2c_readw(i2c, OFFSET_CONTROL)),
- (i2c_readw(i2c, OFFSET_TRANSFER_LEN)),
- (i2c_readw(i2c, OFFSET_TRANSAC_LEN)),
- (i2c_readw(i2c, OFFSET_DELAY_LEN)),
- (i2c_readw(i2c, OFFSET_TIMING)),
- (i2c_readw(i2c, OFFSET_START)),
- (i2c_readw(i2c, OFFSET_FIFO_STAT)),
- (i2c_readw(i2c, OFFSET_IO_CONFIG)),
- (i2c_readw(i2c, OFFSET_HS)),
- (i2c_readw(i2c, OFFSET_DCM_EN)),
- (i2c_readw(i2c, OFFSET_DEBUGSTAT)),
- (i2c_readw(i2c, OFFSET_EXT_CONF)), (i2c_readw(i2c, OFFSET_TRANSFER_LEN_AUX)));
- pr_err("i2c_dump_info ------------------------------------------\n");
- /*
- I2CLOG("before enable DMA register(0x%ld):\n"
- I2CTAG "INT_FLAG=%x,INT_EN=%x,EN=%x,RST=%x,\n"
- I2CTAG "STOP=%x,FLUSH=%x,CON=%x,TX_MEM_ADDR=%x, RX_MEM_ADDR=%x\n"
- I2CTAG "TX_LEN=%x,RX_LEN=%x,INT_BUF_SIZE=%x,DEBUG_STATUS=%x\n",
- g_dma_data[i2c->id].base,
- g_dma_data[i2c->id].int_flag,
- g_dma_data[i2c->id].int_en,
- g_dma_data[i2c->id].en,
- g_dma_data[i2c->id].rst,
- g_dma_data[i2c->id].stop,
- g_dma_data[i2c->id].flush,
- g_dma_data[i2c->id].con,
- g_dma_data[i2c->id].tx_mem_addr,
- g_dma_data[i2c->id].tx_mem_addr,
- g_dma_data[i2c->id].tx_len,
- g_dma_data[i2c->id].rx_len,
- g_dma_data[i2c->id].int_buf_size, g_dma_data[i2c->id].debug_sta);
- I2CLOG("DMA register(0x%p):\n"
- I2CTAG "INT_FLAG=%x,INT_EN=%x,EN=%x,RST=%x,\n"
- I2CTAG "STOP=%x,FLUSH=%x,CON=%x,TX_MEM_ADDR=%x, RX_MEM_ADDR=%x\n"
- I2CTAG "TX_LEN=%x,RX_LEN=%x,INT_BUF_SIZE=%x,DEBUG_STATUS=%x\n",
- i2c->pdmabase,
- (__raw_readl((void *)i2c->pdmabase + OFFSET_INT_FLAG)),
- (__raw_readl((void *)i2c->pdmabase + OFFSET_INT_EN)),
- (__raw_readl((void *)i2c->pdmabase + OFFSET_EN)),
- (__raw_readl((void *)i2c->pdmabase + OFFSET_RST)),
- (__raw_readl((void *)i2c->pdmabase + OFFSET_STOP)),
- (__raw_readl((void *)i2c->pdmabase + OFFSET_FLUSH)),
- (__raw_readl((void *)i2c->pdmabase + OFFSET_CON)),
- (__raw_readl((void *)i2c->pdmabase + OFFSET_TX_MEM_ADDR)),
- (__raw_readl((void *)i2c->pdmabase + OFFSET_RX_MEM_ADDR)),
- (__raw_readl((void *)i2c->pdmabase + OFFSET_TX_LEN)),
- (__raw_readl((void *)i2c->pdmabase + OFFSET_RX_LEN)),
- (__raw_readl((void *)i2c->pdmabase + OFFSET_INT_BUF_SIZE)),
- (__raw_readl((void *)i2c->pdmabase + OFFSET_DEBUG_STA)));
- */
- }
- #else
- void i2c_dump_info(struct mt_i2c *i2c)
- {
- }
- #endif
- static int mt_i2c_do_transfer(struct mt_i2c *i2c)
- {
- u16 addr_reg;
- u16 control_reg;
- int tmo = i2c->adap.timeout;
- unsigned int speed_hz;
- bool isDMA = false;
- int data_size;
- u8 *ptr;
- int ret;
- i2c->trans_stop = false;
- i2c->irq_stat = 0;
- if (i2c->msg_len > 8 || i2c->msg_aux_len > 8)
- isDMA = true;
- if (i2c->ext_data.isEnable && i2c->ext_data.timing)
- speed_hz = i2c->ext_data.timing;
- else
- speed_hz = i2c->speed_hz;
- ret = i2c_set_speed(i2c, 156000000 / i2c->clk_src_div);
- if (ret) {
- dev_err(i2c->dev, "Failed to set the speed\n");
- return -EINVAL;
- }
- /* If use i2c pin from PMIC mt6397 side, need set PATH_DIR first */
- if (i2c->have_pmic)
- i2c_writew(I2C_CONTROL_WRAPPER, i2c, OFFSET_PATH_DIR);
- control_reg = I2C_CONTROL_ACKERR_DET_EN | I2C_CONTROL_CLK_EXT_EN;
- if (isDMA == true) /* DMA */
- control_reg |= I2C_CONTROL_DMA_EN;
- if (speed_hz > 400000)
- control_reg |= I2C_CONTROL_RS;
- if (i2c->op == I2C_MASTER_WRRD)
- control_reg |= I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS;
- i2c_writew(control_reg, i2c, OFFSET_CONTROL);
- /* set start condition */
- if (speed_hz <= 100000)
- i2c_writew(I2C_ST_START_CON, i2c, OFFSET_EXT_CONF);
- else
- i2c_writew(I2C_FS_START_CON, i2c, OFFSET_EXT_CONF);
- if (~control_reg & I2C_CONTROL_RS)
- i2c_writew(I2C_DELAY_LEN, i2c, OFFSET_DELAY_LEN);
- addr_reg = i2c->addr << 1;
- if (i2c->op == I2C_MASTER_RD)
- addr_reg |= 0x1;
- i2c_writew(addr_reg, i2c, OFFSET_SLAVE_ADDR);
- /* Clear interrupt status */
- i2c_writew(I2C_HS_NACKERR | I2C_ACKERR | I2C_TRANSAC_COMP,
- i2c, OFFSET_INTR_STAT);
- i2c_writew(I2C_FIFO_ADDR_CLR, i2c, OFFSET_FIFO_ADDR_CLR);
- /* Enable interrupt */
- i2c_writew(I2C_HS_NACKERR | I2C_ACKERR | I2C_TRANSAC_COMP,
- i2c, OFFSET_INTR_MASK);
- /* Set transfer and transaction len */
- if (i2c->op == I2C_MASTER_WRRD) {
- if (i2c->id != 6) {
- i2c_writew(i2c->msg_len, i2c, OFFSET_TRANSFER_LEN);
- i2c_writew(i2c->msg_aux_len, i2c, OFFSET_TRANSFER_LEN_AUX);
- } else {
- i2c_writew(i2c->msg_len & 0xFF | (i2c->msg_aux_len<<8) & 0x1F00,
- i2c, OFFSET_TRANSFER_LEN);
- }
- i2c_writew(0x02, i2c, OFFSET_TRANSAC_LEN);
- } else {
- i2c_writew(i2c->msg_len, i2c, OFFSET_TRANSFER_LEN);
- i2c_writew(0x01, i2c, OFFSET_TRANSAC_LEN);
- }
- /* Prepare buffer data to start transfer */
- if (isDMA == true) {
- if (i2c->op == I2C_MASTER_RD) {
- i2c_writel_dma(I2C_DMA_INT_FLAG_NONE, i2c, OFFSET_INT_FLAG);
- i2c_writel_dma(I2C_DMA_CON_RX, i2c, OFFSET_CON);
- i2c_writel_dma((u32)i2c->dma_buf.paddr, i2c, OFFSET_RX_MEM_ADDR);
- i2c_writel_dma(i2c->msg_len, i2c, OFFSET_RX_LEN);
- } else if (i2c->op == I2C_MASTER_WR) {
- i2c_writel_dma(I2C_DMA_INT_FLAG_NONE, i2c, OFFSET_INT_FLAG);
- i2c_writel_dma(I2C_DMA_CON_TX, i2c, OFFSET_CON);
- i2c_writel_dma((u32)i2c->dma_buf.paddr, i2c, OFFSET_TX_MEM_ADDR);
- i2c_writel_dma(i2c->msg_len, i2c, OFFSET_TX_LEN);
- } else {
- i2c_writel_dma(0x0000, i2c, OFFSET_INT_FLAG);
- i2c_writel_dma(0x0000, i2c, OFFSET_CON);
- i2c_writel_dma((u32)i2c->dma_buf.paddr, i2c, OFFSET_TX_MEM_ADDR);
- i2c_writel_dma((u32)i2c->dma_buf.paddr, i2c,
- OFFSET_RX_MEM_ADDR);
- i2c_writel_dma(i2c->msg_len, i2c, OFFSET_TX_LEN);
- i2c_writel_dma(i2c->msg_aux_len, i2c, OFFSET_RX_LEN);
- }
- /* flush before sending DMA start */
- mb();
- i2c_writel_dma(I2C_DMA_START_EN, i2c, OFFSET_EN);
- } else {
- if (i2c->op != I2C_MASTER_RD) {
- data_size = i2c->msg_len;
- ptr = i2c->dma_buf.vaddr;
- while (data_size--) {
- i2c_writew(*ptr, i2c, OFFSET_DATA_PORT);
- ptr++;
- }
- }
- }
- /* flush before sending start */
- mb();
- if (!i2c->ext_data.isEnable || !i2c->ext_data.is_hw_trig)
- i2c_writew(I2C_TRANSAC_START, i2c, OFFSET_START);
- else
- dev_err(i2c->dev, "I2C hw trig.\n");
- tmo = wait_event_timeout(i2c->wait, i2c->trans_stop, tmo);
- if (tmo == 0) {
- dev_err(i2c->dev, "addr: %x, transfer timeout\n", i2c->addr);
- i2c_dump_info(i2c);
- mt_i2c_init_hw(i2c);
- return -ETIMEDOUT;
- }
- if (i2c->irq_stat & (I2C_HS_NACKERR | I2C_ACKERR)) {
- dev_err(i2c->dev, "addr: %x, transfer ACK error\n", i2c->addr);
- mt_i2c_init_hw(i2c);
- i2c_dump_info(i2c);
- return -EREMOTEIO;
- }
- if (i2c->op != I2C_MASTER_WR && isDMA == false) {
- data_size = (i2c_readw(i2c, OFFSET_FIFO_STAT) >> 4) & 0x000F;
- ptr = i2c->dma_buf.vaddr;
- while (data_size--) {
- *ptr = i2c_readw(i2c, OFFSET_DATA_PORT);
- /* I2CLOG("addr %x read byte = 0x%x\n", i2c->addr, *ptr); */
- ptr++;
- }
- }
- dev_dbg(i2c->dev, "i2c transfer done.\n");
- return 0;
- }
- static inline void mt_i2c_copy_to_dma(struct mt_i2c *i2c, struct i2c_msg *msg)
- {
- /* if the operate is write, need to copy the data to DMA memory */
- if (!(msg->flags & I2C_M_RD))
- memcpy(i2c->dma_buf.vaddr, msg->buf, msg->len);
- }
- static inline void mt_i2c_copy_from_dma(struct mt_i2c *i2c,
- struct i2c_msg *msg)
- {
- /* if the operate is read, need to copy the data from DMA memory */
- if (msg->flags & I2C_M_RD)
- memcpy(msg->buf, i2c->dma_buf.vaddr, msg->len);
- }
- /*
- * In MTK platform the STOP will be issued after each
- * message was transferred which is not flow the clarify
- * for i2c_transfer(), several I2C devices tolerate the STOP,
- * but some device need Repeat-Start and do not compatible with STOP
- * MTK platform has WRRD mode which can write then read with
- * Repeat-Start between two message, so we combined two
- * messages into one transaction.
- * The max read length is 4096
- */
- static bool mt_i2c_should_combine(struct i2c_msg *msg)
- {
- struct i2c_msg *next_msg = msg + 1;
- if ((next_msg->len < 4096) &&
- msg->addr == next_msg->addr &&
- !(msg->flags & I2C_M_RD) &&
- (next_msg->flags & I2C_M_RD) == I2C_M_RD) {
- return true;
- }
- return false;
- }
- static int __mt_i2c_transfer(struct mt_i2c *i2c,
- struct i2c_msg msgs[], int num)
- {
- int ret;
- int left_num = num;
- ret = mt_i2c_clock_enable(i2c);
- if (ret)
- return ret;
- while (left_num--) {
- /* In MTK platform the max transfer number is 4096 */
- if (msgs->len > MAX_DMA_TRANS_SIZE) {
- dev_dbg(i2c->dev,
- " message data length is more than 255\n");
- ret = -EINVAL;
- goto err_exit;
- }
- if (msgs->addr == 0) {
- dev_dbg(i2c->dev, " addr is invalid.\n");
- ret = -EINVAL;
- goto err_exit;
- }
- if (msgs->buf == NULL) {
- dev_dbg(i2c->dev, " data buffer is NULL.\n");
- ret = -EINVAL;
- goto err_exit;
- }
- i2c->addr = msgs->addr;
- i2c->msg_len = msgs->len;
- i2c->msg_buf = msgs->buf;
- i2c->msg_aux_len = 0;
- if (msgs->flags & I2C_M_RD)
- i2c->op = I2C_MASTER_RD;
- else
- i2c->op = I2C_MASTER_WR;
- /* combined two messages into one transaction */
- if (left_num >= 1 && mt_i2c_should_combine(msgs)) {
- i2c->msg_aux_len = (msgs + 1)->len;
- i2c->op = I2C_MASTER_WRRD;
- left_num--;
- }
- /*
- * always use DMA mode.
- * 1st when write need copy the data of message to dma memory
- * 2nd when read need copy the DMA data to the message buffer.
- * The length should be less than 255.
- */
- mt_i2c_copy_to_dma(i2c, msgs);
- i2c->msg_buf = (u8 *)i2c->dma_buf.paddr;
- /* Use HW semaphore to protect mt6313 access between AP and SPM */
- if (i2c_get_semaphore(i2c) != 0)
- return -EBUSY;
- ret = mt_i2c_do_transfer(i2c);
- /* Use HW semaphore to protect mt6313 access between AP and SPM */
- if (i2c_release_semaphore(i2c) != 0)
- ret = -EBUSY;
- if (ret < 0)
- goto err_exit;
- if (i2c->op == I2C_MASTER_WRRD)
- mt_i2c_copy_from_dma(i2c, msgs + 1);
- else
- mt_i2c_copy_from_dma(i2c, msgs);
- msgs++;
- /* after combined two messages so we need ignore one */
- if (left_num > 0 && i2c->op == I2C_MASTER_WRRD)
- msgs++;
- }
- /* the return value is number of executed messages */
- ret = num;
- err_exit:
- mt_i2c_clock_disable(i2c);
- return ret;
- }
- static int mt_i2c_transfer(struct i2c_adapter *adap,
- struct i2c_msg msgs[], int num)
- {
- int ret;
- struct mt_i2c *i2c = i2c_get_adapdata(adap);
- mutex_lock(&i2c->i2c_mutex);
- ret = __mt_i2c_transfer(i2c, msgs, num);
- mutex_unlock(&i2c->i2c_mutex);
- return ret;
- }
- static void mt_i2c_parse_extension(struct mt_i2c_ext *pext, u32 ext_flag, u32 timing)
- {
- if (ext_flag & I2C_HWTRIG_FLAG)
- pext->is_hw_trig = true;
- if (timing)
- pext->timing = timing;
- }
- int mtk_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num,
- u32 ext_flag, u32 timing)
- {
- int ret;
- struct mt_i2c *i2c = i2c_get_adapdata(adap);
- mutex_lock(&i2c->i2c_mutex);
- i2c->ext_data.isEnable = true;
- mt_i2c_parse_extension(&i2c->ext_data, ext_flag, timing);
- ret = __mt_i2c_transfer(i2c, msgs, num);
- i2c->ext_data.isEnable = false;
- mutex_unlock(&i2c->i2c_mutex);
- return ret;
- }
- EXPORT_SYMBOL(mtk_i2c_transfer);
- static irqreturn_t mt_i2c_irq(int irqno, void *dev_id)
- {
- struct mt_i2c *i2c = dev_id;
- /* Clear interrupt mask */
- i2c_writew(~(I2C_HS_NACKERR | I2C_ACKERR | I2C_TRANSAC_COMP),
- i2c, OFFSET_INTR_MASK);
- i2c->irq_stat = i2c_readw(i2c, OFFSET_INTR_STAT);
- i2c_writew(I2C_HS_NACKERR | I2C_ACKERR | I2C_TRANSAC_COMP,
- i2c, OFFSET_INTR_STAT);
- i2c->trans_stop = true;
- wake_up(&i2c->wait);
- return IRQ_HANDLED;
- }
- static u32 mt_i2c_functionality(struct i2c_adapter *adap)
- {
- return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
- }
- static const struct i2c_algorithm mt_i2c_algorithm = {
- .master_xfer = mt_i2c_transfer,
- .functionality = mt_i2c_functionality,
- };
- static int mt_i2c_parse_dt(struct device_node *np, struct mt_i2c *i2c)
- {
- i2c->speed_hz = I2C_DEFAUT_SPEED;
- of_property_read_u32(np, "clock-frequency", &i2c->speed_hz);
- of_property_read_u32(np, "clock-div", &i2c->clk_src_div);
- of_property_read_u32(np, "id", (u32 *)&i2c->id);
- i2c->have_pmic = of_property_read_bool(np, "mediatek,have-pmic");
- i2c->have_dcm = of_property_read_bool(np, "mediatek,have-dcm");
- i2c->use_push_pull = of_property_read_bool(np, "mediatek,use-push-pull");
- pr_err("[I2C] id : %d, freq : %d, div : %d.\n", i2c->id, i2c->speed_hz, i2c->clk_src_div);
- if (i2c->clk_src_div == 0)
- return -EINVAL;
- return 0;
- }
- static int mt_i2c_probe(struct platform_device *pdev)
- {
- int ret = 0;
- struct mt_i2c *i2c;
- unsigned int clk_src_in_hz;
- struct resource *res;
- i2c = devm_kzalloc(&pdev->dev, sizeof(struct mt_i2c), GFP_KERNEL);
- if (i2c == NULL)
- return -ENOMEM;
- ret = mt_i2c_parse_dt(pdev->dev.of_node, i2c);
- if (ret)
- return -EINVAL;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- i2c->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(i2c->base))
- return PTR_ERR(i2c->base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- i2c->pdmabase = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(i2c->pdmabase))
- return PTR_ERR(i2c->pdmabase);
- i2c->irqnr = platform_get_irq(pdev, 0);
- if (i2c->irqnr <= 0)
- return -EINVAL;
- ret = devm_request_irq(&pdev->dev, i2c->irqnr, mt_i2c_irq,
- IRQF_TRIGGER_NONE, I2C_DRV_NAME, i2c);
- if (ret < 0) {
- dev_err(&pdev->dev,
- "Request I2C IRQ %d fail\n", i2c->irqnr);
- return ret;
- }
- i2c->adap.dev.of_node = pdev->dev.of_node;
- i2c->dev = &i2c->adap.dev;
- i2c->adap.dev.parent = &pdev->dev;
- i2c->adap.owner = THIS_MODULE;
- i2c->adap.algo = &mt_i2c_algorithm;
- i2c->adap.algo_data = NULL;
- i2c->adap.timeout = 2 * HZ;
- i2c->adap.retries = 1;
- i2c->adap.nr = i2c->id;
- i2c->clk_main = devm_clk_get(&pdev->dev, "main");
- if (IS_ERR(i2c->clk_main)) {
- dev_err(&pdev->dev, "cannot get main clock\n");
- return PTR_ERR(i2c->clk_main);
- }
- i2c->clk_dma = devm_clk_get(&pdev->dev, "dma");
- if (IS_ERR(i2c->clk_dma)) {
- dev_err(&pdev->dev, "cannot get dma clock\n");
- return PTR_ERR(i2c->clk_dma);
- }
- i2c->clk_arb = devm_clk_get(&pdev->dev, "arb");
- if (IS_ERR(i2c->clk_arb))
- i2c->clk_arb = NULL;
- else
- dev_dbg(&pdev->dev, "i2c%d has the relevant arbitrator clk.\n", i2c->id);
- if (i2c->have_pmic) {
- i2c->clk_pmic = devm_clk_get(&pdev->dev, "pmic");
- if (IS_ERR(i2c->clk_pmic)) {
- dev_err(&pdev->dev, "cannot get pmic clock\n");
- return PTR_ERR(i2c->clk_pmic);
- }
- clk_src_in_hz = clk_get_rate(i2c->clk_pmic) / i2c->clk_src_div;
- } else {
- clk_src_in_hz = clk_get_rate(i2c->clk_main) / i2c->clk_src_div;
- }
- dev_dbg(&pdev->dev, "clock source %p,clock src frequency %d\n",
- i2c->clk_main, clk_src_in_hz);
- strlcpy(i2c->adap.name, I2C_DRV_NAME, sizeof(i2c->adap.name));
- init_waitqueue_head(&i2c->wait);
- mutex_init(&i2c->i2c_mutex);
- ret = i2c_set_speed(i2c, clk_src_in_hz);
- if (ret) {
- dev_err(&pdev->dev, "Failed to set the speed\n");
- return -EINVAL;
- }
- ret = mt_i2c_clock_enable(i2c);
- if (ret) {
- dev_err(&pdev->dev, "clock enable failed!\n");
- return ret;
- }
- mt_i2c_init_hw(i2c);
- mt_i2c_clock_disable(i2c);
- i2c->dma_buf.vaddr = dma_alloc_coherent(&pdev->dev,
- PAGE_SIZE, &i2c->dma_buf.paddr, GFP_KERNEL);
- if (i2c->dma_buf.vaddr == NULL) {
- dev_err(&pdev->dev, "dma_alloc_coherent fail\n");
- return -ENOMEM;
- }
- i2c_set_adapdata(&i2c->adap, i2c);
- /* ret = i2c_add_adapter(&i2c->adap); */
- ret = i2c_add_numbered_adapter(&i2c->adap);
- if (ret) {
- dev_err(&pdev->dev, "Failed to add i2c bus to i2c core\n");
- free_i2c_dma_bufs(i2c);
- return ret;
- }
- platform_set_drvdata(pdev, i2c);
- return 0;
- }
- static int mt_i2c_remove(struct platform_device *pdev)
- {
- struct mt_i2c *i2c = platform_get_drvdata(pdev);
- i2c_del_adapter(&i2c->adap);
- free_i2c_dma_bufs(i2c);
- platform_set_drvdata(pdev, NULL);
- return 0;
- }
- static const struct of_device_id mtk_i2c_of_match[] = {
- { .compatible = "mediatek,mt6735-i2c", },
- { .compatible = "mediatek,mt6797-i2c", },
- {},
- };
- MODULE_DEVICE_TABLE(of, mt_i2c_match);
- static struct platform_driver mt_i2c_driver = {
- .probe = mt_i2c_probe,
- .remove = mt_i2c_remove,
- .driver = {
- .name = I2C_DRV_NAME,
- .owner = THIS_MODULE,
- .of_match_table = of_match_ptr(mtk_i2c_of_match),
- },
- };
- #ifdef CONFIG_MTK_I2C_ARBITRATION
- static s32 enable_arbitration(void)
- {
- struct device_node *pericfg_node;
- void __iomem *pericfg_base;
- pericfg_node = of_find_compatible_node(NULL, NULL, "mediatek,pericfg");
- if (!pericfg_node) {
- pr_err("Cannot find pericfg node\n");
- return -ENODEV;
- }
- pericfg_base = of_iomap(pericfg_node, 0);
- if (!pericfg_base) {
- pr_err("pericfg iomap failed\n");
- return -ENOMEM;
- }
- /* Enable the I2C arbitration */
- writew(0x3, pericfg_base + OFFSET_PERI_I2C_MODE_ENABLE);
- return 0;
- }
- #endif
- static s32 __init mt_i2c_init(void)
- {
- #ifdef CONFIG_MTK_I2C_ARBITRATION
- int ret;
- ret = enable_arbitration();
- if (ret) {
- pr_err("Cannot enalbe arbitration.\n");
- return ret;
- }
- #endif
- pr_err(" mt_i2c_init driver as platform device\n");
- return platform_driver_register(&mt_i2c_driver);
- }
- static void __exit mt_i2c_exit(void)
- {
- platform_driver_unregister(&mt_i2c_driver);
- }
- module_init(mt_i2c_init);
- module_exit(mt_i2c_exit);
- /* module_platform_driver(mt_i2c_driver); */
- MODULE_LICENSE("GPL");
- MODULE_DESCRIPTION("MediaTek I2C Bus Driver");
- MODULE_AUTHOR("Xudong Chen <xudong.chen@mediatek.com>");
|