diff options
Diffstat (limited to 'drivers/video/wmt/sw_i2c.c')
-rwxr-xr-x | drivers/video/wmt/sw_i2c.c | 436 |
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); |