summaryrefslogtreecommitdiff
path: root/drivers/video/wmt/sw_i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/wmt/sw_i2c.c')
-rwxr-xr-xdrivers/video/wmt/sw_i2c.c436
1 files changed, 436 insertions, 0 deletions
diff --git a/drivers/video/wmt/sw_i2c.c b/drivers/video/wmt/sw_i2c.c
new file mode 100755
index 00000000..79acd966
--- /dev/null
+++ b/drivers/video/wmt/sw_i2c.c
@@ -0,0 +1,436 @@
+/*++
+ * linux/drivers/video/wmt/sw_i2c.c
+ * WonderMedia video post processor (VPP) driver
+ *
+ * Copyright c 2014 WonderMedia Technologies, Inc.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * WonderMedia Technologies, Inc.
+ * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C
+--*/
+
+#include "vpp-osif.h"
+#include "sw_i2c.h"
+
+#define SPEED 50 /* 5000000 */
+
+#define delay_time 30
+
+struct swi2c_reg_bk_t {
+ unsigned int gpio_en;
+ unsigned int out_en;
+ unsigned int data_out;
+ unsigned int pull_en;
+};
+
+#ifdef __KERNEL__
+static DEFINE_SPINLOCK(swi2c_irqlock);
+unsigned long swi2c_irqlock_flags;
+#endif
+void wmt_swi2c_lock(int lock)
+{
+#ifdef __KERNEL__
+ if (lock)
+ spin_lock_irqsave(&swi2c_irqlock, swi2c_irqlock_flags);
+ else
+ spin_unlock_irqrestore(&swi2c_irqlock, swi2c_irqlock_flags);
+#endif
+}
+
+struct swi2c_reg_s *swi2c_scl, *swi2c_sda;
+
+void wmt_swi2c_delay(unsigned int time)
+{
+ udelay(time);
+}
+
+void wmt_swi2c_SetSDAInput(void)
+{
+ outw(inw(swi2c_sda->gpio_en) | swi2c_sda->bit_mask, swi2c_sda->gpio_en);
+ outw(inw(swi2c_sda->out_en) & ~swi2c_sda->bit_mask, swi2c_sda->out_en);
+}
+
+
+void wmt_swi2c_SetSDAOutput(void)
+{
+ outw(inw(swi2c_sda->gpio_en) | swi2c_sda->bit_mask, swi2c_sda->gpio_en);
+ outw(inw(swi2c_sda->out_en) | swi2c_sda->bit_mask, swi2c_sda->out_en);
+}
+
+bool wmt_swi2c_GetSDA(void) /* bit */
+{
+ if (inw(swi2c_sda->data_in) & swi2c_sda->bit_mask)
+#ifdef CFG_LOADER
+ return 1;
+ return 0;
+#else
+ return (HW_REG bool) 1;
+ return (HW_REG bool) 0;
+#endif
+}
+
+bool wmt_swi2c_GetSCL(void) /* bit */
+{
+ if (inw(swi2c_scl->data_in) & swi2c_scl->bit_mask)
+#ifdef CFG_LOADER
+ return 1;
+ return 0;
+#else
+ return (HW_REG bool) 1;
+ return (HW_REG bool) 0;
+#endif
+}
+
+void wmt_swi2c_SetSDA(int high)
+{
+ if (high) {
+ /* set to GPI and pull high */
+ outw(inw(swi2c_sda->gpio_en) | swi2c_sda->bit_mask,
+ swi2c_sda->gpio_en);
+ outw(inw(swi2c_sda->out_en) & ~swi2c_sda->bit_mask,
+ swi2c_sda->out_en);
+ if (swi2c_sda->pull_en)
+ outw(inw(swi2c_sda->pull_en) &
+ ~swi2c_sda->pull_en_bit_mask,
+ swi2c_sda->pull_en);
+ } else {
+ outw(inw(swi2c_sda->gpio_en) | swi2c_sda->bit_mask,
+ swi2c_sda->gpio_en);
+ outw(inw(swi2c_sda->out_en) | swi2c_sda->bit_mask,
+ swi2c_sda->out_en);
+ outw(inw(swi2c_sda->data_out) & ~swi2c_sda->bit_mask,
+ swi2c_sda->data_out);
+ }
+}
+
+void wmt_swi2c_SetSCL(int high)
+{
+ if (high) {
+ outw(inw(swi2c_scl->gpio_en) | swi2c_scl->bit_mask,
+ swi2c_scl->gpio_en);
+ outw(inw(swi2c_scl->out_en) & ~swi2c_scl->bit_mask,
+ swi2c_scl->out_en);
+ if (swi2c_scl->pull_en)
+ outw(inw(swi2c_scl->pull_en) &
+ ~swi2c_scl->pull_en_bit_mask,
+ swi2c_scl->pull_en);
+ } else {
+ outw(inw(swi2c_scl->gpio_en) | swi2c_scl->bit_mask,
+ swi2c_scl->gpio_en);
+ outw(inw(swi2c_scl->out_en) | swi2c_scl->bit_mask,
+ swi2c_scl->out_en);
+ outw(inw(swi2c_scl->data_out) & ~swi2c_scl->bit_mask,
+ swi2c_scl->data_out);
+ }
+}
+
+int wmt_swi2c_SetData(int high)
+{
+ unsigned int wait = 1;
+
+ wmt_swi2c_SetSDA(high);
+ do {
+ if (wmt_swi2c_GetSDA() == ((high) ? 1 : 0))
+ return 0;
+ } while (wait++ < SPEED);
+ return 1;
+}
+
+int wmt_swi2c_SetClock(int high)
+{
+ unsigned int wait = 1;
+
+ udelay(5); /* 3-100kHz, 5-80kHz */
+
+ wmt_swi2c_SetSCL(high);
+ do {
+ if (wmt_swi2c_GetSCL() == ((high) ? 1 : 0))
+ return 0;
+ } while (wait++ < SPEED);
+ return 1; /* fail */
+}
+
+int wmt_swi2c_StartI2C(void)
+{
+ if (wmt_swi2c_SetData(1))
+ return 1;
+ if (wmt_swi2c_SetClock(1))
+ return 2;
+ if (wmt_swi2c_SetData(0))
+ return 3;
+ wmt_swi2c_delay(0);
+ if (wmt_swi2c_SetClock(0))
+ return 4;
+ return 0; /* success */
+}
+
+int wmt_swi2c_StopI2C(void)
+{
+ if (wmt_swi2c_SetData(0))
+ return 1;
+ if (wmt_swi2c_SetClock(0))
+ return 1;
+ if (wmt_swi2c_SetClock(1))
+ return 1;
+ wmt_swi2c_delay(0);
+ if (wmt_swi2c_SetData(1))
+ return 1;
+ return 0; /* success */
+}
+
+int wmt_swi2c_WriteAck(unsigned char byte)
+{
+ int ret;
+ int bit;
+
+ for (bit = 7; bit >= 0; bit--) {
+ wmt_swi2c_SetData(byte & 0x80);
+ byte <<= 1;
+ if (wmt_swi2c_SetClock(1))
+ return 1;
+ if (wmt_swi2c_SetClock(0))
+ return 1;
+ }
+ ret = 0;
+ wmt_swi2c_SetSDAInput();
+ if (wmt_swi2c_SetClock(1))
+ ret = 1;
+ else if (wmt_swi2c_GetSDA())
+ ret = (wmt_swi2c_SetClock(0)) ? 1 : 0;
+ else if (wmt_swi2c_SetClock(0))
+ ret = 1;
+ wmt_swi2c_SetSDAOutput();
+ return ret;
+}
+
+int wmt_swi2c_ReadAck(unsigned char *byte, int last)
+{
+ unsigned char i;
+ unsigned char Data = 0;
+
+ wmt_swi2c_SetSDAInput();
+
+ for (i = 0; i < 8; i++) {
+ if (wmt_swi2c_SetClock(1)) {
+ wmt_swi2c_SetSDAOutput();
+ return 1;
+ }
+ Data <<= 1;
+ wmt_swi2c_delay(0);
+ Data |= wmt_swi2c_GetSDA();
+ if (wmt_swi2c_SetClock(0)) {
+ wmt_swi2c_SetSDAOutput();
+ return 1;
+ }
+ }
+
+ *byte = Data;
+ wmt_swi2c_SetSDAOutput();
+
+ wmt_swi2c_delay(0);
+ if (wmt_swi2c_SetData((last) ? 1 : 0))
+ return 1;
+ if (wmt_swi2c_SetClock(1))
+ return 1;
+ wmt_swi2c_delay(0);
+ if (wmt_swi2c_SetClock(0))
+ return 1;
+ wmt_swi2c_delay(0);
+ return 0;
+}
+
+int wmt_swi2c_tx(
+ char addr,
+ char *buf,
+ int cnt,
+ int *ret_cnt
+)
+{
+ int ret = 0;
+ unsigned char i;
+
+ wmt_swi2c_lock(1);
+
+ ret |= wmt_swi2c_StartI2C();
+ if (ret)
+ goto tx_end;
+ ret |= wmt_swi2c_WriteAck(addr);
+ if (ret)
+ goto tx_end;
+ for (i = 0; i < cnt; i++) {
+ ret |= wmt_swi2c_WriteAck(buf[i]);
+ if (ret)
+ goto tx_end;
+ }
+ ret |= wmt_swi2c_StopI2C();
+tx_end:
+ wmt_swi2c_lock(0);
+ return ret;
+}
+
+int wmt_swi2c_rx(
+ char addr,
+ char *buf,
+ int cnt,
+ int *ret_cnt
+)
+{
+ int ret = 0;
+ int i;
+
+ wmt_swi2c_lock(1);
+
+ ret |= wmt_swi2c_StartI2C();
+ if (ret)
+ goto rx_end;
+ ret |= wmt_swi2c_WriteAck(addr | 0x01);
+ if (ret)
+ goto rx_end;
+ for (i = 0; i < cnt; i++) {
+ ret |= wmt_swi2c_ReadAck((unsigned char *)&buf[i],
+ (i == (cnt - 1)));
+ if (ret)
+ goto rx_end;
+ }
+ ret |= wmt_swi2c_StopI2C();
+rx_end:
+ wmt_swi2c_lock(0);
+ return ret;
+}
+
+void wmt_swi2c_reg_bk(struct swi2c_reg_s *reg_p,
+ struct swi2c_reg_bk_t *reg_bk, int bk)
+{
+ if (bk) {
+ reg_bk->gpio_en = inw(reg_p->gpio_en);
+ reg_bk->out_en = inw(reg_p->out_en);
+ reg_bk->data_out = inw(reg_p->data_out);
+ reg_bk->pull_en = inw(reg_p->pull_en);
+ } else {
+ outw(reg_bk->gpio_en, reg_p->gpio_en);
+ outw(reg_bk->out_en, reg_p->out_en);
+ outw(reg_bk->data_out, reg_p->data_out);
+ outw(reg_bk->pull_en, reg_p->pull_en);
+ }
+}
+
+int wmt_swi2c_read(
+ struct swi2c_handle_s *handle,
+ char addr,
+ char index,
+ char *buf,
+ int cnt
+)
+{
+ int ret = 0;
+ char buffer[24];
+ int temp = 0;
+ struct swi2c_reg_bk_t scl_bk, sda_bk;
+
+ swi2c_scl = handle->scl_reg;
+ swi2c_sda = handle->sda_reg;
+
+ wmt_swi2c_reg_bk(swi2c_scl, &scl_bk, 1);
+ wmt_swi2c_reg_bk(swi2c_sda, &sda_bk, 1);
+
+ buffer[0] = index;
+ ret = wmt_swi2c_tx(addr, buffer, 1, &temp);
+ if (ret) {
+ DPRINT("[SWI2C] *E* tx fail\n");
+ goto exit;
+ }
+ ret = wmt_swi2c_rx(addr, buf, cnt, &temp);
+ if (ret) {
+ DPRINT("[SWI2C] *E* rx fail\n");
+ goto exit;
+ }
+exit:
+ wmt_swi2c_reg_bk(swi2c_scl, &scl_bk, 0);
+ wmt_swi2c_reg_bk(swi2c_sda, &sda_bk, 0);
+ return ret;
+}
+EXPORT_SYMBOL(wmt_swi2c_read);
+
+int wmt_swi2c_write(
+ struct swi2c_handle_s *handle,
+ char addr,
+ char index,
+ char *buf,
+ int cnt
+)
+{
+ int ret = 0;
+ char buffer[24];
+ int temp;
+ struct swi2c_reg_bk_t scl_bk, sda_bk;
+
+ swi2c_scl = handle->scl_reg;
+ swi2c_sda = handle->sda_reg;
+
+ wmt_swi2c_reg_bk(swi2c_scl, &scl_bk, 1);
+ wmt_swi2c_reg_bk(swi2c_sda, &sda_bk, 1);
+
+ buffer[0] = index;
+ buffer[1] = *buf;
+ ret = wmt_swi2c_tx(addr, buffer, cnt, &temp);
+ if (ret) {
+ DPRINT("[SWI2C] *E* tx fail\n");
+ goto exit;
+ }
+exit:
+ wmt_swi2c_reg_bk(swi2c_scl, &scl_bk, 0);
+ wmt_swi2c_reg_bk(swi2c_sda, &sda_bk, 0);
+ return ret;
+}
+EXPORT_SYMBOL(wmt_swi2c_write);
+
+int wmt_swi2c_check(struct swi2c_handle_s *handle)
+{
+ int ret = 0;
+#if 0
+ struct swi2c_reg_s *reg_p;
+ struct swi2c_reg_bk_t scl_bk, sda_bk;
+
+ swi2c_scl = handle->scl_reg;
+ swi2c_sda = handle->sda_reg;
+
+ wmt_swi2c_reg_bk(swi2c_scl, &scl_bk, 1);
+ wmt_swi2c_reg_bk(swi2c_sda, &sda_bk, 1);
+ reg_p = handle->scl_reg;
+ do {
+ outw(inw(reg_p->gpio_en) | reg_p->bit_mask, reg_p->gpio_en);
+ outw(inw(reg_p->out_en) | reg_p->bit_mask, reg_p->out_en);
+ outw(inw(reg_p->data_out) & ~reg_p->bit_mask, reg_p->data_out);
+
+ outw(inw(reg_p->out_en) & ~reg_p->bit_mask, reg_p->out_en);
+ if (reg_p->pull_en)
+ outw(inw(reg_p->pull_en) & ~reg_p->pull_en_bit_mask,
+ reg_p->pull_en);
+ if (inw(reg_p->data_in) & reg_p->bit_mask) {
+ if (reg_p == handle->sda_reg)
+ break;
+ reg_p = handle->sda_reg;
+ } else {
+ ret = 1;
+ break;
+ }
+ } while (1);
+ wmt_swi2c_reg_bk(swi2c_scl, &scl_bk, 0);
+ wmt_swi2c_reg_bk(swi2c_sda, &sda_bk, 0);
+ DPRINT("[SWI2C] %s exist\n", (ret) ? "not" : "");
+#endif
+ return ret;
+}
+EXPORT_SYMBOL(wmt_swi2c_check);