summaryrefslogtreecommitdiff
path: root/drivers/video/sprdfb/sprdfb_i2c.c
diff options
context:
space:
mode:
authorYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
committerYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
commit8e4bff4cab0ddac6060645b0715210484d02ff40 (patch)
tree3a5c3024371a04692a3a6d9974d001cdff8ebf84 /drivers/video/sprdfb/sprdfb_i2c.c
Initial file dump from open source releaseHEADmaster
Diffstat (limited to 'drivers/video/sprdfb/sprdfb_i2c.c')
-rw-r--r--drivers/video/sprdfb/sprdfb_i2c.c333
1 files changed, 333 insertions, 0 deletions
diff --git a/drivers/video/sprdfb/sprdfb_i2c.c b/drivers/video/sprdfb/sprdfb_i2c.c
new file mode 100644
index 00000000..00c4d339
--- /dev/null
+++ b/drivers/video/sprdfb/sprdfb_i2c.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/i2c.h>
+#include <linux/delay.h>
+
+#include "sprdfb.h"
+#include "sprdfb_panel.h"
+
+
+#define SPRDFB_I2C_NAME "sprdfb_i2c"
+#define SPRDFB_I2C_TRY_NUM (4)
+
+static struct i2c_client *this_client = NULL;
+static struct panel_spec *i2c_panel_info = NULL;
+
+static struct i2c_device_id panel_i2c_id[] = {
+ {SPRDFB_I2C_NAME, 0},
+ {}
+};
+
+static unsigned short panel_i2c_default_addr_list[] =
+ { I2C_CLIENT_END, I2C_CLIENT_END };
+
+
+static int sprdfb_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int res = 0;
+// struct sprdfb_device *dev = (struct sprdfb_device *)id->driver_data;;
+
+ printk(KERN_INFO "sprdfb: [%s], addr = %d\n", __FUNCTION__, client->addr);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ printk(KERN_INFO "sprdfb: [%s]: functionality check failed\n",
+ __FUNCTION__);
+ res = -ENODEV;
+ goto out;
+ }
+
+ this_client = client;
+
+ if (i2c_panel_info->info.rgb->bus_info.i2c->i2c_addr != (this_client->addr & (~0xFF))) {
+ this_client->addr =
+ (this_client->addr & (~0xFF)) |
+ (i2c_panel_info->info.rgb->bus_info.i2c->i2c_addr & 0xFF);
+ }
+ printk(KERN_INFO "sordfb: [%s]:this_client->addr =0x%x\n", __FUNCTION__,
+ this_client->addr);
+ msleep(20);
+ return 0;
+out:
+ return res;
+}
+
+static int sprdfb_i2c_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+static int sprdfb_i2c_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+ printk("SENSOR_DRV: detect!");
+ strcpy(info->type, client->name);
+ return 0;
+}
+
+static struct i2c_driver sprdfb_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ },
+ .probe = sprdfb_i2c_probe,
+ .remove = sprdfb_i2c_remove,
+ .detect = sprdfb_i2c_detect,
+};
+
+
+
+bool sprdfb_i2c_init(struct sprdfb_device *dev)
+{
+/* panel_i2c_id[0].driver_data = dev;*/
+ i2c_panel_info = dev->panel;
+ panel_i2c_default_addr_list[0] = dev->panel->info.rgb->bus_info.i2c->i2c_addr;
+
+ sprdfb_i2c_driver.driver.name = SPRDFB_I2C_NAME;
+ sprdfb_i2c_driver.id_table = panel_i2c_id;
+ sprdfb_i2c_driver.address_list = &panel_i2c_default_addr_list[0];
+
+ if (i2c_add_driver(&sprdfb_i2c_driver)) {
+ printk("sprdfb: [%s] i2c_add_driver fail\n", __FUNCTION__);
+ return false;
+ }else{
+ printk("sprdfb: [%s] i2c_add_driver ok\n", __FUNCTION__);
+ }
+
+ return true;
+}
+
+bool sprdfb_i2c_uninit(struct sprdfb_device *dev)
+{
+/* panel_i2c_id[0].driver_data = dev;*/
+ panel_i2c_default_addr_list[0] = dev->panel->info.rgb->bus_info.i2c->i2c_addr;
+
+ sprdfb_i2c_driver.driver.name = SPRDFB_I2C_NAME;
+ sprdfb_i2c_driver.id_table = panel_i2c_id;
+ sprdfb_i2c_driver.address_list = &panel_i2c_default_addr_list[0];
+
+ i2c_panel_info = NULL;
+
+ i2c_del_driver(&sprdfb_i2c_driver);
+
+ return true;
+}
+
+/*write i2c, reg is 8 bit, val is 8 bit*/
+static int32_t sprdfb_i2c_write_8bits(uint8_t reg, uint8_t val)
+{
+ uint8_t buf_w[2];
+ uint32_t i = 0;
+ int32_t ret = -1;
+ struct i2c_msg msg_w;
+
+ if (0xFF == reg) {
+ mdelay(val);
+ printk("sprdfb: [%s], sleep %d\n", __FUNCTION__, val);
+ return 0;
+ }
+
+ buf_w[0] = (uint8_t) reg;
+ buf_w[1] = val;
+ msg_w.addr = this_client->addr;
+ msg_w.flags = 0;
+ msg_w.buf = buf_w;
+ msg_w.len = 2;
+ for (i = 0; i < SPRDFB_I2C_TRY_NUM; i++) {
+ ret = i2c_transfer(this_client->adapter, &msg_w, 1);
+ if (ret != 1) {
+ printk("sprdfb: [%s] write panel reg fai, ret : %d, I2C w addr: 0x%x, \n",
+ __FUNCTION__, ret, this_client->addr);
+ ret = -1;
+ msleep(20);
+ }else{
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+/*read i2c, reg is 8 bit, val is 8 bit*/
+static int32_t sprdfb_i2c_read_8bits(uint8_t reg, uint8_t *val)
+{
+ uint8_t buf_w[1];
+ uint8_t buf_r;
+ uint32_t i = 0;
+ int32_t ret = -1;
+ struct i2c_msg msg_r[2];
+
+ buf_w[0] = reg;
+ msg_r[0].addr = this_client->addr;
+ msg_r[0].flags = 0;
+ msg_r[0].buf = buf_w;
+ msg_r[0].len = 1;
+ msg_r[1].addr = this_client->addr;
+ msg_r[1].flags = I2C_M_RD;
+ msg_r[1].buf = &buf_r;
+ msg_r[1].len = 1;
+ for (i = 0; i < SPRDFB_I2C_TRY_NUM; i++) {
+ ret = i2c_transfer(this_client->adapter, msg_r, 2);
+ if (ret != 2) {
+ printk("sprdfb: [%s]: read i2c reg fail, ret: %d, I2C r addr: 0x%x \n",
+ __FUNCTION__, ret, this_client->addr);
+ *val = 0xff;
+ ret = -1;
+ msleep(20);
+ }else{
+ *val = buf_r;
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+
+/*write i2c, reg is 8 or 16 bit, val is 8 or 16bit*/
+static int32_t sprdfb_i2c_write_16bits(uint16_t reg, bool reg_is_8bit, uint16_t val, bool val_is_8bit)
+{
+ uint8_t cmd[4] = { 0 };
+ uint32_t i = 0;
+ uint32_t cmd_num = 0;
+ struct i2c_msg msg_w;
+ int32_t ret = -1;
+
+ if ((reg_is_8bit && (0xff == reg))||(!reg_is_8bit &&(0xffff == reg))) {
+ mdelay(val);
+ printk("sprdfb: [%s], sleep %d\n", __FUNCTION__, val);
+ return 0;
+ }
+
+ if (!reg_is_8bit) {
+ cmd[cmd_num++] = (uint8_t) ((reg >> 8) & 0xff);
+ cmd[cmd_num++] = (uint8_t) (reg & 0xff);
+ } else {
+ cmd[cmd_num++] = (uint8_t) reg;
+ }
+
+ if (!val_is_8bit) {
+ cmd[cmd_num++] = (uint8_t) ((val >> 8) & 0xff);
+ cmd[cmd_num++] = (uint8_t) (val & 0xff);
+ } else {
+ cmd[cmd_num++] = (uint8_t) val;
+ }
+
+ msg_w.addr = this_client->addr;
+ msg_w.flags = 0;
+ msg_w.buf = cmd;
+ msg_w.len = cmd_num;
+
+ for (i = 0; i < SPRDFB_I2C_TRY_NUM; i++) {
+ ret = i2c_transfer(this_client->adapter, &msg_w, 1);
+ if (ret != 1) {
+ printk("srpdfb [%s]: write sensor reg fai, ret : %d, I2C w addr: 0x%x, \n",
+ __FUNCTION__, ret, this_client->addr);
+ ret = -1;
+ msleep(20);
+ } else {
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+/*read i2c, reg is 8 or 16 bit, val is 8 or 16bit*/
+static int32_t sprdfb_i2c_read_16bits(uint16_t reg, bool reg_is_8bit, uint16_t *val, bool val_is_8bit)
+{
+ uint32_t i = 0;
+ uint8_t cmd[2] = { 0 };
+ uint16_t w_cmd_num = 0;
+ uint16_t r_cmd_num = 0;
+ uint8_t buf_r[2] = { 0 };
+ int32_t ret = -1;
+ struct i2c_msg msg_r[2];
+
+ if (!reg_is_8bit) {
+ cmd[w_cmd_num++] = (uint8_t) ((reg >> 8) & 0xff);
+ cmd[w_cmd_num++] = (uint8_t) (reg & 0xff);
+ } else {
+ cmd[w_cmd_num++] = (uint8_t) reg;
+ }
+
+ if (!val_is_8bit) {
+ r_cmd_num = 2;
+ } else {
+ r_cmd_num = 1;
+ }
+
+ msg_r[0].addr = this_client->addr;
+ msg_r[0].flags = 0;
+ msg_r[0].buf = cmd;
+ msg_r[0].len = w_cmd_num;
+ msg_r[1].addr = this_client->addr;
+ msg_r[1].flags = I2C_M_RD;
+ msg_r[1].buf = buf_r;
+ msg_r[1].len = r_cmd_num;
+
+ for (i = 0; i < SPRDFB_I2C_TRY_NUM; i++) {
+ ret = i2c_transfer(this_client->adapter, msg_r, 2);
+ if (ret != 2) {
+ printk("srpdfb [%s]: read panel reg fai, ret : %d, I2C w addr: 0x%x, \n",
+ __FUNCTION__,ret, this_client->addr);
+ *val = 0xffff;
+ ret = -1;
+ msleep(20);
+ } else {
+ *val = (r_cmd_num == 1) ? (uint16_t) buf_r[0]
+ : (uint16_t) ((buf_r[0] << 8) + buf_r[1]);
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+
+/*write i2c with burst mode*/
+static int32_t sprdfb_i2c_write_burst(uint8_t* buf, int num)
+{
+ uint32_t i = 0;
+ struct i2c_msg msg_w;
+ int32_t ret = -1;
+
+ for (i = 0; i < SPRDFB_I2C_TRY_NUM; i++) {
+ msg_w.addr = this_client->addr;
+ msg_w.flags = 0;
+ msg_w.buf = buf;
+ msg_w.len = num;
+ ret = i2c_transfer(this_client->adapter, &msg_w, 1);
+ if (ret != 1) {
+ printk("srpdfb [%s]: write i2c reg fai, ret : %d, I2C w addr: 0x%x, \n",
+ __FUNCTION__, ret, this_client->addr);
+ ret = -1;
+ msleep(20);
+ } else {
+ ret = 0;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+struct ops_i2c sprdfb_i2c_ops = {
+ .i2c_write_8bits = sprdfb_i2c_write_8bits,
+ .i2c_read_8bits = sprdfb_i2c_read_8bits,
+ .i2c_write_16bits = sprdfb_i2c_write_16bits,
+ .i2c_read_16bits = sprdfb_i2c_read_16bits,
+ .i2c_write_burst = sprdfb_i2c_write_burst,
+};
+