camera MCLK配置错误造成 i2c不通的 修改方法

本文探讨了MT6795/MT6735平台上MCLK配置不匹配导致的问题,包括开机能搜索到sensor ID但在open时丢失的情况。分析了背后的原因,并提供了修改MCLK配置的方法。
AI助手已提取文章相关产品:
[DESCRIPTION]
MT6795   MT6735 平台,HW 上MCLK和SW上MCLK 配置不匹配的话,如HWMCLK 共用,SW没有共用的话, 会造成能开机搜到对应的sensor id,但open时又找不到id,i2c不同(开机读到id, 但是open时还有find id过程,这时仅用了对应的mclk)。

1 开机能search 到sensor id原因:开机时三路MCLK 的pll都打开了,所以在kd_camera_hw.c中对正确的MCLK上电就可以正常工作,找到sensor id了。


2 open 时找不到sensor id原因:
sensor open 时为节省功耗,打开对应的MCLK PLL,但若HW上和SW上的MCLKPORT 配置不正确的话,会造成i2c不能正常工作难道是scl时钟线?),从而读不到sensor id。
所以SW上要根据HW配置正确的MCLK PORT(可得出:main or sub camera既可以公用一条mclk线,也可以单独在一条mclk,目前最多三条)

[SOLUTION]
a, MCLK共用配置MCLK PORT方法:
修改cfg_setting_imgsensor.cpp (vendor\mediatek\proprietary\custom\mt6735\hal\D1\imgsensor_src\cfg_setting_imgsensor.cpp)中函数getSensorMclkConnection, 根据HW 上实际MCLK连接情况来配置。
比如说:若sub sensor和main 共用MCLK1,则做如下修改:
 

b, 在kd_camera_hw.c中对正确的MCLK上下电  ,即ISP_MCLK1_EN(1);或ISP_MCLK1_EN(0);


您可能感兴趣的与本文相关内容

/* * sp0821.c sp0821 yuv module * * Author: Bruce <sunchengwei@longcheer.com> * * 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. * */ #include <linux/i2c.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/device.h> #include <linux/irq.h> #include <linux/firmware.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/proc_fs.h> #include <linux/uaccess.h> #include <linux/io.h> #include <linux/init.h> #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/gameport.h> #include <linux/moduleparam.h> #include <linux/mutex.h> #include <linux/timer.h> #include <linux/workqueue.h> #include <linux/hrtimer.h> #include <linux/ktime.h> #include <linux/kthread.h> #include <linux/regulator/consumer.h> #include "sp_sp0821_yuv.h" #include "../../../aw37004/aw37004.h" #include <soc/oplus/system/oplus_project.h> #include <linux/videodev2.h> #include <linux/cdev.h> #include <linux/atomic.h> #include <linux/types.h> extern void ISP_MCLK3_EN (bool En); extern int aw37004_camera_power_up(int out_iotype, unsigned int out_val); #define kal_uint16 unsigned short #define kal_uint32 unsigned int /***************************************************************** * sp0821 marco ******************************************************************/ #define SP0821_DRIVER_VERSION "V2.0" #define SP0821_PRODUCT_NUM 4 #define SP0821_PRODUCT_NAME_LEN 8 #define SP0821_SENSOR_ID 0x3a6c #define SP0821_MCLK_ON "sp0821_mclk_on" #define SP0821_MCLK_OFF "sp0821_mclk_off" /***************************************************************** * sp0821 global global variable ******************************************************************/ static unsigned char read_reg_id = 0; static unsigned char read_reg_value = 0; static int read_reg_flag = 0; static int driver_flag = 0; struct sp0821 *g_sp0821 = NULL; /********************************************************** * i2c write and read **********************************************************/ static void sp0821_i2c_write(struct sp0821 *sp0821, int address, int data) { u8 i2c_buf[8]; struct i2c_client *client = sp0821->i2c_client; struct i2c_msg msg[1]; msg[0].flags = !I2C_M_RD; msg[0].addr = client->addr; msg[0].len = 3; msg[0].buf = i2c_buf; i2c_buf[0] = (address & 0xff00)>>8; i2c_buf[1] = (address & 0xff); i2c_buf[2] = data; i2c_transfer(client->adapter, msg, 1); //printk("write sp0821 addr: 0x%4X val:0x%4X\n", address, data); } static unsigned char sp0821_i2c_read(struct sp0821 *sp0821, int address) { unsigned char rxdata = 0x00; unsigned char i2c_buf[4]; int ret = 0; int retry = 2; u8 i2c_addr[2]; struct i2c_client *client = sp0821->i2c_client; struct i2c_msg msgs[2]; i2c_addr[0] = (address & 0xff00)>>8; i2c_addr[1] = (address & 0xff); msgs[0].flags = 0; msgs[0].addr = (client->addr); msgs[0].len = 2; msgs[0].buf = i2c_addr; msgs[1].flags = I2C_M_RD; msgs[1].addr = (client->addr); msgs[1].len = 1; msgs[1].buf = i2c_buf; while (retry > 0) { ret = i2c_transfer(client->adapter, msgs, 2); //qvga_dev_err(&client->dev, "%s: read step1 ret:%d msgs[1].addr=%x\n", __func__, ret, msgs[1].addr); if (retry >0) { mdelay(20); if (ret == 0) { return 0; } } retry--; mdelay(2); } rxdata = i2c_buf[0]; return rxdata; } static struct sp0821 *sp0821_malloc_init(struct i2c_client *client) { struct sp0821 *sp0821 = devm_kzalloc(&client->dev, sizeof(struct sp0821), GFP_KERNEL); if (sp0821 == NULL) { qvga_dev_err(&client->dev, "%s: devm_kzalloc failed.\n", __func__); return NULL; } sp0821->i2c_client = client; pr_info("%s enter , client_addr = 0x%02x\n", __func__, sp0821->i2c_client->addr); return sp0821; } #if 1 void sp0821_Init(struct sp0821 *sp0821) { /*SYS MCLK=24MHZ*/ sp0821_i2c_write(sp0821, 0x0103,0x01); sp0821_i2c_write(sp0821, 0x0100,0x00); sp0821_i2c_write(sp0821, 0x309b,0xf0); sp0821_i2c_write(sp0821, 0x30b0,0x0a); sp0821_i2c_write(sp0821, 0x30b8,0x21); sp0821_i2c_write(sp0821, 0x320c,0x01); sp0821_i2c_write(sp0821, 0x320d,0x6a); sp0821_i2c_write(sp0821, 0x320e,0x01); sp0821_i2c_write(sp0821, 0x320f,0xba); sp0821_i2c_write(sp0821, 0x3301,0x04); sp0821_i2c_write(sp0821, 0x3304,0x0c); sp0821_i2c_write(sp0821, 0x3305,0x00); sp0821_i2c_write(sp0821, 0x3306,0x10); sp0821_i2c_write(sp0821, 0x3307,0x02); sp0821_i2c_write(sp0821, 0x3308,0x04); sp0821_i2c_write(sp0821, 0x330a,0x00); sp0821_i2c_write(sp0821, 0x330b,0x30); sp0821_i2c_write(sp0821, 0x330e,0x01); sp0821_i2c_write(sp0821, 0x330f,0x01); sp0821_i2c_write(sp0821, 0x3310,0x01); sp0821_i2c_write(sp0821, 0x331e,0x09); sp0821_i2c_write(sp0821, 0x3333,0x10); sp0821_i2c_write(sp0821, 0x3334,0x40); sp0821_i2c_write(sp0821, 0x334c,0x01); sp0821_i2c_write(sp0821, 0x33b3,0x3e); sp0821_i2c_write(sp0821, 0x349f,0x02); sp0821_i2c_write(sp0821, 0x34a6,0x01); sp0821_i2c_write(sp0821, 0x34a7,0x07); sp0821_i2c_write(sp0821, 0x34a8,0x3a); sp0821_i2c_write(sp0821, 0x34a9,0x38); sp0821_i2c_write(sp0821, 0x34e9,0x38); sp0821_i2c_write(sp0821, 0x34f8,0x07); sp0821_i2c_write(sp0821, 0x3630,0x65); sp0821_i2c_write(sp0821, 0x3637,0x47); sp0821_i2c_write(sp0821, 0x363a,0xe0); sp0821_i2c_write(sp0821, 0x3670,0x03); sp0821_i2c_write(sp0821, 0x3674,0x75); sp0821_i2c_write(sp0821, 0x3675,0x65); sp0821_i2c_write(sp0821, 0x3676,0x65); sp0821_i2c_write(sp0821, 0x367c,0x01); sp0821_i2c_write(sp0821, 0x367d,0x03); sp0821_i2c_write(sp0821, 0x3690,0xe0); sp0821_i2c_write(sp0821, 0x3691,0xe1); sp0821_i2c_write(sp0821, 0x3692,0xe1); sp0821_i2c_write(sp0821, 0x3693,0xe1); sp0821_i2c_write(sp0821, 0x3694,0x03); sp0821_i2c_write(sp0821, 0x3695,0x07); sp0821_i2c_write(sp0821, 0x3696,0x07); sp0821_i2c_write(sp0821, 0x37f9,0x29); sp0821_i2c_write(sp0821, 0x3900,0x91); sp0821_i2c_write(sp0821, 0x3904,0x0f); sp0821_i2c_write(sp0821, 0x3908,0x00); sp0821_i2c_write(sp0821, 0x391b,0x07); sp0821_i2c_write(sp0821, 0x391c,0x0a); sp0821_i2c_write(sp0821, 0x391d,0x15); sp0821_i2c_write(sp0821, 0x391e,0x28); sp0821_i2c_write(sp0821, 0x391f,0x41); sp0821_i2c_write(sp0821, 0x3948,0x00);//blc sp0821_i2c_write(sp0821, 0x4509,0x10); sp0821_i2c_write(sp0821, 0x470b,0x0a); sp0821_i2c_write(sp0821, 0x470d,0x06); sp0821_i2c_write(sp0821, 0x5000,0xc2); sp0821_i2c_write(sp0821, 0x5001,0x01); sp0821_i2c_write(sp0821, 0x5170,0x2c); sp0821_i2c_write(sp0821, 0x5172,0xc1); sp0821_i2c_write(sp0821, 0x518b,0x00);//again sp0821_i2c_write(sp0821, 0x518c,0x20); sp0821_i2c_write(sp0821, 0x518d,0x01);//shutter sp0821_i2c_write(sp0821, 0x518e,0x7c); sp0821_i2c_write(sp0821, 0x518f,0x00); sp0821_i2c_write(sp0821, 0x519e,0x10); sp0821_i2c_write(sp0821, 0x300a,0x00);//SIP input sp0821_i2c_write(sp0821, 0x0100,0x01); /*shutter gain must write after stream on */ sp0821_i2c_write(sp0821, 0x518b,0x03);//again=4x sp0821_i2c_write(sp0821, 0x518c,0x20); sp0821_i2c_write(sp0821, 0x518d,0x01);//shutter=20ms sp0821_i2c_write(sp0821, 0x518e,0xb0); sp0821_i2c_write(sp0821, 0x518f,0x00); sp0821_i2c_write(sp0821, 0x519e,0x10); } /* sensor_init */ #endif int sp0821_GetSensorID(struct sp0821 *sp0821) { int retry = 2; unsigned char reg_data = 0x00; //check if sensor ID correct do { reg_data = sp0821_i2c_read(sp0821, 0x3107)<<8|sp0821_i2c_read(sp0821, 0x3108); qvga_dev_err(sp0821->dev, "drv-%s: Read MSB Sensor ID = 0x%02x\n", __func__, reg_data); // if (reg_data == SP0821_SENSOR_ID) { if (1) { qvga_dev_err(sp0821->dev, "drv-%s: Read Sensor ID sucess = 0x%02x\n", __func__, reg_data); driver_flag = 1; return 0; } else { qvga_dev_err(sp0821->dev, "rv-%s: Read Sensor ID Fail = 0x%02x\n", __func__, reg_data); driver_flag = 0; } mdelay(10); retry--; } while (retry > 0); return -1; } static void sp0821_vcam_control(struct sp0821 *sp0821, bool flag) { // struct regulator *vcama; struct regulator *vcamio; struct regulator *vcamd; int ret; int ret1; qvga_dev_info(sp0821->dev, "%s enter\n", __func__); vcamd = regulator_get(sp0821->dev,"vcamd"); if (IS_ERR(vcamd)) { qvga_dev_err(sp0821->dev, "%s get regulator vcamd failed\n", __func__); regulator_put(vcamd); return; } else { qvga_dev_err(sp0821->dev, "%s get regulator vcamd success\n", __func__); } if (flag) { regulator_set_voltage(vcamd, 1200000, 1200000); ret = regulator_enable(vcamd); } else { regulator_disable(vcamd); } // vcama = regulator_get(sp0821->dev,"vcama"); // if (IS_ERR(vcama)) { // qvga_dev_err(sp0821->dev, "%s get regulator vcama failed\n", __func__); // regulator_put(vcama); // return; // } // if (flag) { // regulator_set_voltage(vcama, 2800000, 2800000); // ret = regulator_enable(vcama); // } else { // regulator_disable(vcama); // } if (flag) { ret1 = aw37004_camera_power_up(2, 2800); if (ret1 == 0) { qvga_dev_err(sp0821->dev, "%s get regulator vcama success\n", __func__); } else { qvga_dev_err(sp0821->dev, "%s get regulator vcama failed\n", __func__); } } vcamio = regulator_get(sp0821->dev,"vcamio"); if (IS_ERR(vcamio)) { qvga_dev_err(sp0821->dev, "%s get regulator vcamio failed\n", __func__); regulator_put(vcamio); return; } else { qvga_dev_err(sp0821->dev, "%s get regulator vcamio success\n", __func__); } if (flag) { regulator_set_voltage(vcamio, 1800000, 1800000); ret = regulator_enable(vcamio); } else { regulator_disable(vcamio); } return; } static void sp0821_hw_on_reset(struct sp0821 *sp0821) { qvga_dev_info(sp0821->dev, "%s enter\n", __func__); if (gpio_is_valid(sp0821->reset_gpio)) { gpio_set_value_cansleep(sp0821->reset_gpio, 1); } } static void sp0821_hw_on_reset1(struct sp0821 *sp0821) { qvga_dev_info(sp0821->dev, "%s enter\n", __func__); if (gpio_is_valid(sp0821->reset_gpio1)) { gpio_set_value_cansleep(sp0821->reset_gpio1, 1); } } static void sp0821_hw_off_reset(struct sp0821 *sp0821) { qvga_dev_info(sp0821->dev, "%s enter\n", __func__); if (gpio_is_valid(sp0821->reset_gpio)) { gpio_set_value_cansleep(sp0821->reset_gpio, 0); udelay(50); gpio_set_value_cansleep(sp0821->reset_gpio, 1); udelay(50); gpio_set_value_cansleep(sp0821->reset_gpio, 0); } } static void sp0821_hw_off_reset1(struct sp0821 *sp0821) { qvga_dev_info(sp0821->dev, "%s enter\n", __func__); if (gpio_is_valid(sp0821->reset_gpio1)) { gpio_set_value_cansleep(sp0821->reset_gpio1, 0); } } static void sp0821_hw_on(struct sp0821 *sp0821) { sp0821_hw_on_reset1(sp0821); sp0821_hw_on_reset(sp0821); sp0821_Init(sp0821); sp0821->hwen_flag = 1; } static void sp0821_hw_off(struct sp0821 *sp0821) { sp0821_hw_off_reset(sp0821); sp0821->hwen_flag = 0; } static ssize_t sp0821_get_reg(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; if (read_reg_flag) { len += snprintf(buf + len, PAGE_SIZE - len, "The reg 0x%02X value is 0x%02X\n", read_reg_id, read_reg_value); read_reg_flag = 0; read_reg_id = 0; read_reg_value = 0; } else { len += snprintf(buf + len, PAGE_SIZE - len, "Please echo reg id into reg\n"); } return len; } static ssize_t sp0821_set_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { unsigned int databuf[2] = { 0 }; unsigned char reg_data = 0x00; if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { sp0821_i2c_write(g_sp0821, databuf[0], databuf[1]); } else if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 1) { reg_data = sp0821_i2c_read(g_sp0821, databuf[0]); read_reg_id = databuf[0]; read_reg_value = reg_data; read_reg_flag = 1; } return len; } static ssize_t sp0821_get_name(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; if (driver_flag) { len += snprintf(buf + len, PAGE_SIZE - len, "%s\n", "sp_sp0821_yuv"); } else { len += snprintf(buf + len, PAGE_SIZE - len, "%s\n", "none"); } return len; } static ssize_t sp0821_get_light(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; unsigned char reg_data1 = 0x00; //unsigned char reg_data2 = 0x00; u16 light = 0; reg_data1 = sp0821_i2c_read(g_sp0821, 0x5160); //reg_data2 = sp0821_i2c_read(g_sp0821, 0x516b); //light = (reg_data1<<8) + reg_data2; light = reg_data1; qvga_dev_err(g_sp0821->dev, "%s: sp0821 light=%d, %d\n", __func__, light, reg_data1); len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", light); return len; } static ssize_t sp0821_set_light(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { ssize_t ret; unsigned int state; ret = kstrtouint(buf, 10, &state); if (ret) { qvga_dev_err(g_sp0821->dev, "%s: fail to change str to int\n", __func__); return ret; } if (state == 0) sp0821_hw_off(g_sp0821); /*OFF*/ else sp0821_hw_on(g_sp0821); /*ON*/ return len; } static DEVICE_ATTR(reg, S_IWUSR | S_IRUGO, sp0821_get_reg, sp0821_set_reg); static DEVICE_ATTR(cam_name, S_IWUSR | S_IRUGO, sp0821_get_name, NULL); static DEVICE_ATTR(light, S_IWUSR | S_IRUGO, sp0821_get_light, sp0821_set_light); static struct attribute *sp0821_attributes[] = { &dev_attr_reg.attr, &dev_attr_cam_name.attr, &dev_attr_light.attr, NULL }; static struct attribute_group sp0821_attribute_group = { .attrs = sp0821_attributes }; static void sp0821_parse_gpio_dt(struct sp0821 *sp0821, struct device_node *np) { qvga_dev_info(sp0821->dev, "%s enter, dev_i2c%d@0x%02X\n", __func__, sp0821->i2c_seq, sp0821->i2c_addr); sp0821->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); if (sp0821->reset_gpio < 0) { qvga_dev_err(sp0821->dev, "%s: no reset gpio provided, hardware reset unavailable\n", __func__); sp0821->reset_gpio = -1; } else { qvga_dev_info(sp0821->dev, "%s: reset gpio provided ok\n", __func__); } sp0821->reset_gpio1 = of_get_named_gpio(np, "reset-gpio1", 0); if (sp0821->reset_gpio1 < 0) { qvga_dev_err(sp0821->dev, "%s: no reset gpio1 provided, hardware reset unavailable\n", __func__); sp0821->reset_gpio1 = -1; } else { qvga_dev_info(sp0821->dev, "%s: reset gpio1 provided ok\n", __func__); } } static void sp0821_parse_dt(struct sp0821 *sp0821, struct device_node *np) { qvga_dev_info(sp0821->dev, "%s enter, dev_i2c%d@0x%02X\n", __func__, sp0821->i2c_seq, sp0821->i2c_addr); sp0821_parse_gpio_dt(sp0821, np); } /**************************************************************************** * sp0821 i2c driver *****************************************************************************/ static int sp0821_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device_node *np = client->dev.of_node; struct pinctrl *sp0821_pinctrl = NULL; struct pinctrl_state *set_state = NULL; struct pinctrl_state *sp0821_mclk_on = NULL; struct pinctrl_state *sp0821_mclk_off = NULL; struct sp0821 *sp0821 = NULL; struct class *qvga_class; struct device *dev; int ret = -1; pr_err("scw %s enter , i2c%d@0x%02x\n", __func__, client->adapter->nr, client->addr); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { qvga_dev_err(&client->dev, "%s: check_functionality failed\n", __func__); ret = -ENODEV; goto exit_check_functionality_failed; } sp0821 = sp0821_malloc_init(client); g_sp0821 = sp0821; sp0821->i2c_seq = sp0821->i2c_client->adapter->nr; sp0821->i2c_addr = sp0821->i2c_client->addr; if (sp0821 == NULL) { dev_err(&client->dev, "%s: failed to parse device tree node\n", __func__); ret = -ENOMEM; goto exit_devm_kzalloc_failed; } sp0821->dev = &client->dev; i2c_set_clientdata(client, sp0821); sp0821_parse_dt(sp0821, np); if (gpio_is_valid(sp0821->reset_gpio)) { ret = devm_gpio_request_one(&client->dev, sp0821->reset_gpio, GPIOF_OUT_INIT_LOW, "sp0821_rst"); if (ret) { qvga_dev_err(&client->dev, "%s: rst request failed\n", __func__); goto exit_gpio_request_failed; } } if (gpio_is_valid(sp0821->reset_gpio1)) { ret = devm_gpio_request_one(&client->dev, sp0821->reset_gpio1, GPIOF_OUT_INIT_LOW, "sp0821_rst1"); if (ret) { qvga_dev_err(&client->dev, "%s: rst1 request failed\n", __func__); goto exit_gpio_request_failed; } } sp0821_pinctrl = devm_pinctrl_get(&client->dev); if (IS_ERR_OR_NULL(sp0821_pinctrl)) { qvga_dev_err(&client->dev, "%s: sp0821_pinctrl not defined\n", __func__); } else { set_state = pinctrl_lookup_state(sp0821_pinctrl, SP0821_MCLK_ON); if (IS_ERR_OR_NULL(set_state)) { qvga_dev_err(&client->dev, "%s: sp0821_pinctrl lookup failed for mclk on\n", __func__); } else { sp0821_mclk_on = set_state; } set_state = pinctrl_lookup_state(sp0821_pinctrl, SP0821_MCLK_OFF); if (IS_ERR_OR_NULL(set_state)) { qvga_dev_err(&client->dev, "%s: sp0821_pinctrl lookup failed for mclk off\n", __func__); } else { sp0821_mclk_off = set_state; } ret = pinctrl_select_state(sp0821_pinctrl, sp0821_mclk_off); if (ret < 0) { qvga_dev_err(&client->dev, "%s: sp0821_pinctrl select failed for mclk off\n", __func__); } } //power on camera sp0821_hw_off_reset1(sp0821); mdelay(5); sp0821_vcam_control(sp0821, true); mdelay(1); ret = pinctrl_select_state(sp0821_pinctrl, sp0821_mclk_on); if (ret < 0) { qvga_dev_err(&client->dev, "%s: sp0821_pinctrl select failed for mclk on\n", __func__); } sp0821_hw_on_reset1(sp0821); sp0821_hw_on_reset(sp0821); mdelay(5); // sp0821->hwen_flag = 1; /* sp0821 sensor id */ ret = sp0821_GetSensorID(sp0821); if (ret < 0) { qvga_dev_err(&client->dev, "%s: sp0821read_sensorid failed ret=%d\n", __func__, ret); goto exit_i2c_check_id_failed; } //power off camera sp0821_vcam_control(sp0821, false); sp0821_hw_off_reset1(sp0821); // sp0821_Init(sp0821); qvga_class = class_create(THIS_MODULE, "qvga_cam"); dev = device_create(qvga_class, NULL, client->dev.devt, NULL, "qvga_depth"); ret = sysfs_create_group(&dev->kobj, &sp0821_attribute_group); if (ret < 0) { qvga_dev_err(&client->dev, "%s failed to create sysfs nodes\n", __func__); } return 0; exit_i2c_check_id_failed: sp0821_vcam_control(sp0821, false); sp0821_hw_off_reset1(sp0821); if (gpio_is_valid(sp0821->reset_gpio)) devm_gpio_free(&client->dev, sp0821->reset_gpio); exit_gpio_request_failed: devm_kfree(&client->dev, sp0821); sp0821 = NULL; exit_devm_kzalloc_failed: exit_check_functionality_failed: return ret; } static int sp0821_i2c_remove(struct i2c_client *client) { struct sp0821 *sp0821 = i2c_get_clientdata(client); if (gpio_is_valid(sp0821->reset_gpio)) devm_gpio_free(&client->dev, sp0821->reset_gpio); if (gpio_is_valid(sp0821->reset_gpio1)) devm_gpio_free(&client->dev, sp0821->reset_gpio1); devm_kfree(&client->dev, sp0821); sp0821 = NULL; return 0; } static const struct of_device_id sp0821_of_match[] = { {.compatible = "sc,sp_sp0821_yuv"}, {}, }; static struct i2c_driver sp0821_i2c_driver = { .driver = { .owner = THIS_MODULE, .name = "sp_sp0821_yuv", .of_match_table = sp0821_of_match, }, .probe = sp0821_i2c_probe, .remove = sp0821_i2c_remove, }; static int __init sp0821_yuv_init(void) { int ret; pr_info("%s: driver version: %s\n", __func__, SP0821_DRIVER_VERSION); ret = i2c_add_driver(&sp0821_i2c_driver); if (ret) { pr_info("****[%s] Unable to register driver (%d)\n", __func__, ret); return ret; } return 0; } static void __exit sp0821_yuv_exit(void) { pr_info("%s enter\n", __func__); i2c_del_driver(&sp0821_i2c_driver); } module_init(sp0821_yuv_init); module_exit(sp0821_yuv_exit); MODULE_AUTHOR("wangyuqiu@longcheer.com>"); MODULE_DESCRIPTION("sp0821 yuv driver"); MODULE_LICENSE("GPL v2"); 如果以这个函数为主体,想要将/* * sp0821.c sp0821 yuv module * * * 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. * */ #include <linux/i2c.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/device.h> #include <linux/irq.h> #include <linux/firmware.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/proc_fs.h> #include <linux/uaccess.h> #include <linux/io.h> #include <linux/init.h> #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/gameport.h> #include <linux/moduleparam.h> #include <linux/mutex.h> #include <linux/timer.h> #include <linux/workqueue.h> #include <linux/hrtimer.h> #include <linux/ktime.h> #include <linux/kthread.h> #include <linux/regulator/consumer.h> #include "sp_sp0821_yuv.h" #include "../../../aw37004/aw37004.h" #include <soc/oplus/system/oplus_project.h> #include <linux/videodev2.h> #include <linux/cdev.h> #include <linux/atomic.h> #include <linux/types.h> extern void ISP_MCLK3_EN (bool En); extern int aw37004_camera_power_up(int out_iotype, unsigned int out_val); #define kal_uint16 unsigned short #define kal_uint32 unsigned int /***************************************************************** * sp0821 marco ******************************************************************/ #define SP0821_DRIVER_VERSION "V2.0" #define SP0821_PRODUCT_NUM 4 #define SP0821_PRODUCT_NAME_LEN 8 #define SP0821_SENSOR_ID 0x9c #define SP0821_MCLK_ON "sp0821_mclk_on" #define SP0821_MCLK_OFF "sp0821_mclk_off" #define PAGE_SIZE = 5 /***************************************************************** * sp0821 global global variable ******************************************************************/ static unsigned char read_reg_id = 0; static unsigned char read_reg_value = 0; static int read_reg_flag = 0; static int driver_flag = 0; struct sp0821 *g_sp0821 = NULL; /********************************************************** * i2c write and read **********************************************************/ static int sp0821_i2c_write(struct sp0821 *sp0821, unsigned char reg_addr, unsigned char reg_data) { int ret = -1; unsigned char cnt = 0; while (cnt < 1) { ret = i2c_smbus_write_byte_data(sp0821->i2c_client, reg_addr, reg_data); if (ret < 0) { qvga_dev_err(sp0821->dev, "%s: i2c_write cnt=%d error=%d\n", __func__, cnt, ret); } else { break; } cnt++; msleep(2); } return ret; } static int sp0821_i2c_read(struct sp0821 *sp0821, unsigned char reg_addr, unsigned char *reg_data) { int ret = -1; unsigned char cnt = 0; while (cnt < 1) { ret = i2c_smbus_read_byte_data(sp0821->i2c_client, reg_addr); if (ret < 0) { qvga_dev_err(sp0821->dev, "%s: i2c_read cnt=%d error=%d\n", __func__, cnt, ret); } else { *reg_data = ret; break; } cnt++; msleep(2); } return ret; } static struct sp0821 *sp0821_malloc_init(struct i2c_client *client) { struct sp0821 *sp0821 = devm_kzalloc(&client->dev, sizeof(struct sp0821), GFP_KERNEL); if (sp0821 == NULL) { qvga_dev_err(&client->dev, "%s: devm_kzalloc failed.\n", __func__); return NULL; } sp0821->i2c_client = client; pr_info("%s enter , client_addr = 0x%02x\n", __func__, sp0821->i2c_client->addr); return sp0821; } #if 1 void sp0821_Init(struct sp0821 *sp0821) { /*SYS*/ sp0821_i2c_write(sp0821, 0x30, 0x00); qvga_dev_info(sp0821->dev, "%s zho0 sp0821 reg[0x30]\n", __func__); sp0821_i2c_write(sp0821, 0x32, 0x00); sp0821_i2c_write(sp0821, 0x03, 0x01); sp0821_i2c_write(sp0821, 0x04, 0x2c); sp0821_i2c_write(sp0821, 0x24, 0x80); sp0821_i2c_write(sp0821, 0x9b, 0x32); sp0821_i2c_write(sp0821, 0xd7, 0x00); sp0821_i2c_write(sp0821, 0xc5, 0xc7); sp0821_i2c_write(sp0821, 0xc6, 0xe2); sp0821_i2c_write(sp0821, 0xe7, 0x03); qvga_dev_info(sp0821->dev, "%s zho1 sp0821 reg[0xe7]\n", __func__); sp0821_i2c_write(sp0821, 0x32, 0x00); sp0821_i2c_write(sp0821, 0x32, 0x01); sp0821_i2c_write(sp0821, 0x32, 0x00); sp0821_i2c_write(sp0821, 0xbf, 0x0f); sp0821_i2c_write(sp0821, 0xba, 0x5a); sp0821_i2c_write(sp0821, 0xbb, 0x69); sp0821_i2c_write(sp0821, 0xe7, 0x00); sp0821_i2c_write(sp0821, 0x32, 0x07); sp0821_i2c_write(sp0821, 0x31, 0x03); sp0821_i2c_write(sp0821, 0x19, 0x04); sp0821_i2c_write(sp0821, 0x2c, 0x0f); sp0821_i2c_write(sp0821, 0x2e, 0x7c); qvga_dev_info(sp0821->dev, "%s zho2 sp0821 reg[0x2e]\n", __func__); sp0821_i2c_write(sp0821, 0x30, 0x00); sp0821_i2c_write(sp0821, 0x28, 0x2e); sp0821_i2c_write(sp0821, 0x29, 0x1f); sp0821_i2c_write(sp0821, 0x0f, 0x30); sp0821_i2c_write(sp0821, 0x14, 0xb0); sp0821_i2c_write(sp0821, 0x38, 0x50); sp0821_i2c_write(sp0821, 0x39, 0x52); sp0821_i2c_write(sp0821, 0x3a, 0x60); sp0821_i2c_write(sp0821, 0x3b, 0x10); sp0821_i2c_write(sp0821, 0x3c, 0xe0); sp0821_i2c_write(sp0821, 0x85, 0x01); sp0821_i2c_write(sp0821, 0xe0, 0x02); qvga_dev_info(sp0821->dev, "%s zho3 sp0821 reg[0xe0]\n", __func__); sp0821_i2c_write(sp0821, 0xe5, 0x60); sp0821_i2c_write(sp0821, 0xf5, 0x02); sp0821_i2c_write(sp0821, 0xf1, 0x03); sp0821_i2c_write(sp0821, 0xf3, 0x40); sp0821_i2c_write(sp0821, 0x41, 0x00); sp0821_i2c_write(sp0821, 0x05, 0x00); sp0821_i2c_write(sp0821, 0x06, 0x00); sp0821_i2c_write(sp0821, 0x07, 0x00); sp0821_i2c_write(sp0821, 0x08, 0x00); sp0821_i2c_write(sp0821, 0x09, 0x00); sp0821_i2c_write(sp0821, 0x0a, 0x34); sp0821_i2c_write(sp0821, 0x0D, 0x01); sp0821_i2c_write(sp0821, 0xc8, 0x10); sp0821_i2c_write(sp0821, 0x29, 0x1e); qvga_dev_info(sp0821->dev, "%s zho4 sp0821 reg[0x29]\n", __func__); sp0821_i2c_write(sp0821, 0xa2, 0x26); sp0821_i2c_write(sp0821, 0xa3, 0x02); sp0821_i2c_write(sp0821, 0xa4, 0x32); sp0821_i2c_write(sp0821, 0xa5, 0x00); sp0821_i2c_write(sp0821, 0xa8, 0x32); sp0821_i2c_write(sp0821, 0xa9, 0x00); sp0821_i2c_write(sp0821, 0xaa, 0x01); sp0821_i2c_write(sp0821, 0xab, 0x00); sp0821_i2c_write(sp0821, 0x4c, 0x80); sp0821_i2c_write(sp0821, 0x4d, 0x80); sp0821_i2c_write(sp0821, 0xa6, 0xf0); sp0821_i2c_write(sp0821, 0xa7, 0x20); sp0821_i2c_write(sp0821, 0xac, 0xf0); sp0821_i2c_write(sp0821, 0xad, 0x20); sp0821_i2c_write(sp0821, 0x8a, 0x3e); qvga_dev_info(sp0821->dev, "%s zho5 sp0821 reg[0x8a]\n", __func__); sp0821_i2c_write(sp0821, 0x8b, 0x30); sp0821_i2c_write(sp0821, 0x8c, 0x2a); sp0821_i2c_write(sp0821, 0x8d, 0x26); sp0821_i2c_write(sp0821, 0x8e, 0x26); sp0821_i2c_write(sp0821, 0x8f, 0x24); sp0821_i2c_write(sp0821, 0x90, 0x24); sp0821_i2c_write(sp0821, 0x91, 0x22); sp0821_i2c_write(sp0821, 0x92, 0x22); sp0821_i2c_write(sp0821, 0x93, 0x22); sp0821_i2c_write(sp0821, 0x94, 0x20); sp0821_i2c_write(sp0821, 0x95, 0x20); sp0821_i2c_write(sp0821, 0x96, 0x20); sp0821_i2c_write(sp0821, 0x17, 0x88); sp0821_i2c_write(sp0821, 0x18, 0x80); sp0821_i2c_write(sp0821, 0x4e, 0x78); sp0821_i2c_write(sp0821, 0x4f, 0x78); sp0821_i2c_write(sp0821, 0x58, 0x8a); sp0821_i2c_write(sp0821, 0x59, 0xa8); sp0821_i2c_write(sp0821, 0x5a, 0x80); qvga_dev_info(sp0821->dev, "%s zho6 sp0821 reg[0x5a]\n", __func__); sp0821_i2c_write(sp0821, 0xca, 0x00); sp0821_i2c_write(sp0821, 0x86, 0x08); sp0821_i2c_write(sp0821, 0x87, 0x0f); sp0821_i2c_write(sp0821, 0x88, 0x30); sp0821_i2c_write(sp0821, 0x89, 0x45); sp0821_i2c_write(sp0821, 0x9e, 0x94); sp0821_i2c_write(sp0821, 0x9f, 0x88); sp0821_i2c_write(sp0821, 0x97, 0x84); sp0821_i2c_write(sp0821, 0x98, 0x88); sp0821_i2c_write(sp0821, 0x99, 0x74); sp0821_i2c_write(sp0821, 0x9a, 0x84); sp0821_i2c_write(sp0821, 0xa0, 0x7c); sp0821_i2c_write(sp0821, 0xa1, 0x78); sp0821_i2c_write(sp0821, 0x9d, 0x09); sp0821_i2c_write(sp0821, 0xB1, 0x04); sp0821_i2c_write(sp0821, 0xb3, 0x00); qvga_dev_info(sp0821->dev, "%s zho7 sp0821 reg[0xb3]\n", __func__); sp0821_i2c_write(sp0821, 0x47, 0x40); sp0821_i2c_write(sp0821, 0xb8, 0x04); sp0821_i2c_write(sp0821, 0xb9, 0x28); sp0821_i2c_write(sp0821, 0x3f, 0x18); sp0821_i2c_write(sp0821, 0xc1, 0xff); sp0821_i2c_write(sp0821, 0xc2, 0x40); sp0821_i2c_write(sp0821, 0xc3, 0xff); sp0821_i2c_write(sp0821, 0xc4, 0x40); sp0821_i2c_write(sp0821, 0xc5, 0xc7); sp0821_i2c_write(sp0821, 0xc6, 0xe2); sp0821_i2c_write(sp0821, 0xc7, 0xef); sp0821_i2c_write(sp0821, 0xc8, 0x10); sp0821_i2c_write(sp0821, 0x50, 0x2a); sp0821_i2c_write(sp0821, 0x51, 0x2a); sp0821_i2c_write(sp0821, 0x52, 0x2f); sp0821_i2c_write(sp0821, 0x53, 0xcf); sp0821_i2c_write(sp0821, 0x54, 0xd0); qvga_dev_info(sp0821->dev, "%s zho8 sp0821 reg[0x54]\n", __func__); sp0821_i2c_write(sp0821, 0x5c, 0x1e); sp0821_i2c_write(sp0821, 0x5d, 0x21); sp0821_i2c_write(sp0821, 0x5e, 0x1a); sp0821_i2c_write(sp0821, 0x5f, 0xe9); sp0821_i2c_write(sp0821, 0x60, 0x98); sp0821_i2c_write(sp0821, 0xcb, 0x3f); sp0821_i2c_write(sp0821, 0xcc, 0x3f); sp0821_i2c_write(sp0821, 0xcd, 0x3f); sp0821_i2c_write(sp0821, 0xce, 0x85); sp0821_i2c_write(sp0821, 0xcf, 0xff); sp0821_i2c_write(sp0821, 0x79, 0x5a); sp0821_i2c_write(sp0821, 0x7a, 0xDC); sp0821_i2c_write(sp0821, 0x7b, 0x0A); sp0821_i2c_write(sp0821, 0x7c, 0xFD); sp0821_i2c_write(sp0821, 0x7d, 0x46); sp0821_i2c_write(sp0821, 0x7e, 0xFD); sp0821_i2c_write(sp0821, 0x7f, 0xFD); sp0821_i2c_write(sp0821, 0x80, 0xEF); sp0821_i2c_write(sp0821, 0x81, 0x54); qvga_dev_info(sp0821->dev, "%s zho9 sp0821 reg[0x81]\n", __func__); sp0821_i2c_write(sp0821, 0x1b, 0x0a); sp0821_i2c_write(sp0821, 0x1c, 0x0f); sp0821_i2c_write(sp0821, 0x1d, 0x15); sp0821_i2c_write(sp0821, 0x1e, 0x15); sp0821_i2c_write(sp0821, 0x1f, 0x15); sp0821_i2c_write(sp0821, 0x20, 0x1f); sp0821_i2c_write(sp0821, 0x21, 0x2a); sp0821_i2c_write(sp0821, 0x22, 0x2a); sp0821_i2c_write(sp0821, 0x56, 0x49); sp0821_i2c_write(sp0821, 0x1a, 0x14); sp0821_i2c_write(sp0821, 0x34, 0x1f); sp0821_i2c_write(sp0821, 0x82, 0x10); sp0821_i2c_write(sp0821, 0x83, 0x00); qvga_dev_info(sp0821->dev, "%s zho10 sp0821 reg[0x83]\n", __func__); sp0821_i2c_write(sp0821, 0x84, 0xff); sp0821_i2c_write(sp0821, 0xd7, 0x50); sp0821_i2c_write(sp0821, 0xd8, 0x1a); sp0821_i2c_write(sp0821, 0xd9, 0x20); sp0821_i2c_write(sp0821, 0xc9, 0x1f); sp0821_i2c_write(sp0821, 0xbf, 0x33); sp0821_i2c_write(sp0821, 0xba, 0x37); sp0821_i2c_write(sp0821, 0xbb, 0x38); qvga_dev_info(sp0821->dev, "%s zho11 sp0821 reg[0xbb]\n", __func__); } /* sensor_init */ #endif int sp0821_GetSensorID(struct sp0821 *sp0821) { int retry = 5; int len; unsigned char reg_data = 0x00; //check if sensor ID correct do { len = sp0821_i2c_read(sp0821, 0x02, &reg_data); qvga_dev_err(sp0821->dev, "drv-%s: Read MSB Sensor ID sucess = 0x%02x\n", __func__, reg_data); // if (reg_data == SP0821_SENSOR_ID) { if (1) { qvga_dev_err(sp0821->dev, "drv-%s: Read Sensor ID sucess = 0x%02x\n", __func__, reg_data); driver_flag = 1; return 0; } else { qvga_dev_err(sp0821->dev, "rv-%s: Read Sensor ID Fail = 0x%02x\n", __func__, reg_data); driver_flag = 0; } mdelay(10); retry--; } while (retry > 0); return -1; } static void sp0821_vcam_control(struct sp0821 *sp0821, bool flag) { struct regulator *vcama; struct regulator *vcamio; //struct regulator *vcamd; int ret; int ret1; qvga_dev_info(sp0821->dev, "%s weibiao_enter\n", __func__); // vcama = regulator_get(sp0821->dev,"vcama"); // if (IS_ERR(vcama)) { // qvga_dev_err(sp0821->dev, "%s get regulator vcama failed\n", __func__); // regulator_put(vcama); // return; // } // if (flag) { // regulator_set_voltage(vcama, 2800000, 2800000); // ret = regulator_enable(vcama); // } else { // regulator_disable(vcama); // } if (flag) { ret1 = aw37004_camera_power_up(2, 2800); if (ret1 == 0) { qvga_dev_err(sp0821->dev, "%s get regulator vcama success\n", __func__); } else { qvga_dev_err(sp0821->dev, "%s get regulator vcama failed\n", __func__); } } vcamio = regulator_get(sp0821->dev,"vcamio"); if (IS_ERR(vcamio)) { qvga_dev_err(sp0821->dev, "%s get regulator vcamio failed\n", __func__); regulator_put(vcamio); return; } else { qvga_dev_err(sp0821->dev, "%s get regulator vcama success\n", __func__); } if (flag) { regulator_set_voltage(vcamio, 1800000, 1800000); ret = regulator_enable(vcamio); } else { regulator_disable(vcamio); } // vcamd = regulator_get(sp0821->dev,"vcamd"); // if (IS_ERR(vcamd)) { // qvga_dev_err(sp0821->dev, "%s get regulator vcamd failed\n", __func__); // regulator_put(vcamd); // return; // } // if (flag) { // regulator_set_voltage(vcamd, 1200000, 1200000); // regulator_enable(vcamd); // } else { // regulator_disable(vcamd); // } // return; } static void sp0821_hw_on_reset(struct sp0821 *sp0821) { qvga_dev_info(sp0821->dev, "%s enter\n", __func__); if (gpio_is_valid(sp0821->reset_gpio)) { gpio_set_value_cansleep(sp0821->reset_gpio, 0); udelay(50); gpio_set_value_cansleep(sp0821->reset_gpio, 1); udelay(100); gpio_set_value_cansleep(sp0821->reset_gpio, 0); } } static void sp0821_hw_off_reset(struct sp0821 *sp0821) { qvga_dev_info(sp0821->dev, "%s enter\n", __func__); if (gpio_is_valid(sp0821->reset_gpio)) { gpio_set_value_cansleep(sp0821->reset_gpio, 0); udelay(50); gpio_set_value_cansleep(sp0821->reset_gpio, 1); udelay(50); gpio_set_value_cansleep(sp0821->reset_gpio, 0); } } static void sp0821_hw_on(struct sp0821 *sp0821) { sp0821_hw_on_reset(sp0821); sp0821_Init(sp0821); sp0821->hwen_flag = 1; } static void sp0821_hw_off(struct sp0821 *sp0821) { sp0821_hw_off_reset(sp0821); sp0821->hwen_flag = 0; } static ssize_t sp0821_get_reg(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; if (read_reg_flag) { len += snprintf(buf + len, PAGE_SIZE - len, "The reg 0x%02X value is 0x%02X\n", read_reg_id, read_reg_value); read_reg_flag = 0; read_reg_id = 0; read_reg_value = 0; } else { len += snprintf(buf + len, PAGE_SIZE - len, "Please echo reg id into reg\n"); } return len; } static ssize_t sp0821_set_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { unsigned int databuf[2] = { 0 }; unsigned char reg_data = 0x00; int length; //struct sp0821 *sp0821 = dev_get_drvdata(dev); if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { sp0821_i2c_write(g_sp0821, databuf[0], databuf[1]); } else if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 1) { length = sp0821_i2c_read(g_sp0821, databuf[0], &reg_data); read_reg_id = databuf[0]; read_reg_value = reg_data; read_reg_flag = 1; } return len; } static ssize_t sp0821_get_name(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; if (driver_flag) { len += snprintf(buf + len, PAGE_SIZE - len, "%s\n", "sp_sp0821_yuv"); } else { len += snprintf(buf + len, PAGE_SIZE - len, "%s\n", "none"); } return len; } static ssize_t sp0821_get_light(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; unsigned char reg_data = 0x00; int length; //struct sp0821 *sp0821 = dev_get_drvdata(dev); length = sp0821_i2c_read(g_sp0821, 0xb0, &reg_data); len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", reg_data); return len; } static ssize_t sp0821_set_light(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { ssize_t ret; unsigned int state; //struct sp0821 *sp0821 = dev_get_drvdata(dev); ret = kstrtouint(buf, 10, &state); if (ret) { qvga_dev_err(g_sp0821->dev, "%s: fail to change str to int\n", __func__); return ret; } if (state == 0) sp0821_hw_off(g_sp0821); /*OFF*/ else sp0821_hw_on(g_sp0821); /*ON*/ return len; } static DEVICE_ATTR(reg, S_IWUSR | S_IRUGO, sp0821_get_reg, sp0821_set_reg); static DEVICE_ATTR(cam_name, S_IWUSR | S_IRUGO, sp0821_get_name, NULL); static DEVICE_ATTR(light, S_IWUSR | S_IRUGO, sp0821_get_light, sp0821_set_light); static struct attribute *sp0821_attributes[] = { &dev_attr_reg.attr, &dev_attr_cam_name.attr, &dev_attr_light.attr, NULL }; static struct attribute_group sp0821_attribute_group = { .attrs = sp0821_attributes }; static void sp0821_parse_gpio_dt(struct sp0821 *sp0821, struct device_node *np) { qvga_dev_info(sp0821->dev, "%s enter, dev_i2c%d@0x%02X\n", __func__, sp0821->i2c_seq, sp0821->i2c_addr); sp0821->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); if (sp0821->reset_gpio < 0) { qvga_dev_err(sp0821->dev, "%s: no reset gpio provided, hardware reset unavailable\n", __func__); sp0821->reset_gpio = -1; } else { qvga_dev_info(sp0821->dev, "%s: reset gpio provided ok\n", __func__); } } static void sp0821_parse_dt(struct sp0821 *sp0821, struct device_node *np) { qvga_dev_info(sp0821->dev, "%s enter, dev_i2c%d@0x%02X\n", __func__, sp0821->i2c_seq, sp0821->i2c_addr); sp0821_parse_gpio_dt(sp0821, np); } /**************************************************************************** * sp0821 i2c driver *****************************************************************************/ static int sp0821_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device_node *np = client->dev.of_node; struct pinctrl *sp0821_pinctrl = NULL; struct pinctrl_state *set_state = NULL; struct pinctrl_state *sp0821_mclk_on = NULL; struct pinctrl_state *sp0821_mclk_off = NULL; struct sp0821 *sp0821 = NULL; struct class *qvga_class; struct device *dev; int ret = -1; pr_err("scw %s enter , i2c%d@0x%02x\n", __func__, client->adapter->nr, client->addr); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { qvga_dev_err(&client->dev, "%s: check_functionality failed\n", __func__); ret = -ENODEV; goto exit_check_functionality_failed; } sp0821 = sp0821_malloc_init(client); g_sp0821 = sp0821; sp0821->i2c_seq = sp0821->i2c_client->adapter->nr; sp0821->i2c_addr = sp0821->i2c_client->addr; if (sp0821 == NULL) { qvga_dev_err(&client->dev, "%s: failed to parse device tree node\n", __func__); ret = -ENOMEM; goto exit_devm_kzalloc_failed; } sp0821->dev = &client->dev; i2c_set_clientdata(client, sp0821); sp0821_parse_dt(sp0821, np); if (gpio_is_valid(sp0821->reset_gpio)) { ret = devm_gpio_request_one(&client->dev, sp0821->reset_gpio, GPIOF_OUT_INIT_LOW, "sp0821_rst");//sp if (ret) { qvga_dev_err(&client->dev, "%s: rst request failed\n", __func__); goto exit_gpio_request_failed; } } sp0821_pinctrl = devm_pinctrl_get(&client->dev); if (IS_ERR_OR_NULL(sp0821_pinctrl)) { qvga_dev_err(&client->dev, "%s: sp0821_pinctrl not defined\n", __func__); } else { set_state = pinctrl_lookup_state(sp0821_pinctrl, SP0821_MCLK_ON); if (IS_ERR_OR_NULL(set_state)) { qvga_dev_err(&client->dev, "%s: sp0821_pinctrl lookup failed for mclk on\n", __func__); } else { sp0821_mclk_on = set_state; } set_state = pinctrl_lookup_state(sp0821_pinctrl, SP0821_MCLK_OFF); if (IS_ERR_OR_NULL(set_state)) { qvga_dev_err(&client->dev, "%s: sp0821_pinctrl lookup failed for mclk off\n", __func__); } else { sp0821_mclk_off = set_state; } ret = pinctrl_select_state(sp0821_pinctrl, sp0821_mclk_off); if (ret < 0) { qvga_dev_err(&client->dev, "%s: sp0821_pinctrl select failed for mclk off\n", __func__); } } //power on camera sp0821_vcam_control(sp0821, true); ret = pinctrl_select_state(sp0821_pinctrl, sp0821_mclk_on); if (ret < 0) { qvga_dev_err(&client->dev, "%s: sp0821_pinctrl select failed for mclk on\n", __func__); } mdelay(5); sp0821_hw_on_reset(sp0821); // sp0821->hwen_flag = 1; /* sp0821 sensor id */ ret = sp0821_GetSensorID(sp0821); if (ret < 0) { qvga_dev_err(&client->dev, "%s: sp0821read_sensorid failed ret=%d\n", __func__, ret); goto exit_i2c_check_id_failed; } //power off camera sp0821_vcam_control(sp0821, false); // sp0821_Init(sp0821); qvga_class = class_create(THIS_MODULE, "qvga_cam"); dev = device_create(qvga_class, NULL, client->dev.devt, NULL, "qvga_depth"); ret = sysfs_create_group(&dev->kobj, &sp0821_attribute_group); if (ret < 0) { qvga_dev_err(&client->dev, "%s failed to create sysfs nodes\n", __func__); } return 0; exit_i2c_check_id_failed: sp0821_vcam_control(sp0821, false); if (gpio_is_valid(sp0821->reset_gpio)) devm_gpio_free(&client->dev, sp0821->reset_gpio); exit_gpio_request_failed: devm_kfree(&client->dev, sp0821); sp0821 = NULL; exit_devm_kzalloc_failed: exit_check_functionality_failed: return ret; } static int sp0821_i2c_remove(struct i2c_client *client) { struct sp0821 *sp0821 = i2c_get_clientdata(client); if (gpio_is_valid(sp0821->reset_gpio)) devm_gpio_free(&client->dev, sp0821->reset_gpio); devm_kfree(&client->dev, sp0821); sp0821 = NULL; return 0; } static const struct of_device_id sp0821_of_match[] = { {.compatible = "sp,sp_sp0821_yuv"}, {}, }; static struct i2c_driver sp0821_i2c_driver = { .driver = { .owner = THIS_MODULE, .name = "sp_sp0821_yuv", .of_match_table = sp0821_of_match, }, .probe = sp0821_i2c_probe, .remove = sp0821_i2c_remove, }; static int __init sp0821_yuv_init(void) { int ret; pr_info("%s: driver version: %s\n", __func__, SP0821_DRIVER_VERSION); ret = i2c_add_driver(&sp0821_i2c_driver); if (ret) { pr_info("****[%s] Unable to register driver (%d)\n", __func__, ret); return ret; } return 0; } static void __exit sp0821_yuv_exit(void) { pr_info("%s enter\n", __func__); i2c_del_driver(&sp0821_i2c_driver); } module_init(sp0821_yuv_init); module_exit(sp0821_yuv_exit); MODULE_AUTHOR("wangyuqiu@longcheer.com>"); MODULE_DESCRIPTION("sp0821 yuv driver"); MODULE_LICENSE("GPL v2"); 适配成第一个驱动那样,帮忙生成代码
07-06
/* * sp0821.c sp0821 yuv module * * Author: Bruce <sunchengwei@longcheer.com> * * 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. * */ #include <linux/i2c.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/device.h> #include <linux/irq.h> #include <linux/firmware.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/proc_fs.h> #include <linux/uaccess.h> #include <linux/io.h> #include <linux/init.h> #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/gameport.h> #include <linux/moduleparam.h> #include <linux/mutex.h> #include <linux/timer.h> #include <linux/workqueue.h> #include <linux/hrtimer.h> #include <linux/ktime.h> #include <linux/kthread.h> #include <linux/regulator/consumer.h> #include "sp_sp0821_yuv.h" #include "../../../aw37004/aw37004.h" #include <soc/oplus/system/oplus_project.h> #include <linux/videodev2.h> #include <linux/cdev.h> #include <linux/atomic.h> #include <linux/types.h> extern void ISP_MCLK3_EN (bool En); extern int aw37004_camera_power_up(int out_iotype, unsigned int out_val); #define kal_uint16 unsigned short #define kal_uint32 unsigned int /***************************************************************** * sp0821 marco ******************************************************************/ #define SP0821_DRIVER_VERSION "V2.0" #define SP0821_PRODUCT_NUM 4 #define SP0821_PRODUCT_NAME_LEN 8 #define SP0821_SENSOR_ID 0x3a6c #define SP0821_MCLK_ON "sp0821_mclk_on" #define SP0821_MCLK_OFF "sp0821_mclk_off" /***************************************************************** * sp0821 global global variable ******************************************************************/ static unsigned char read_reg_id = 0; static unsigned char read_reg_value = 0; static int read_reg_flag = 0; static int driver_flag = 0; struct sp0821 *g_sp0821 = NULL; /********************************************************** * i2c write and read **********************************************************/ static void sp0821_i2c_write(struct sp0821 *sp0821, int address, int data) { u8 i2c_buf[8]; struct i2c_client *client = sp0821->i2c_client; struct i2c_msg msg[1]; msg[0].flags = !I2C_M_RD; msg[0].addr = client->addr; msg[0].len = 3; msg[0].buf = i2c_buf; i2c_buf[0] = (address & 0xff00)>>8; i2c_buf[1] = (address & 0xff); i2c_buf[2] = data; i2c_transfer(client->adapter, msg, 1); //printk("write sp0821 addr: 0x%4X val:0x%4X\n", address, data); } // static int sp0821_i2c_write1(struct sp0821 *sp0821, // unsigned char reg_addr, unsigned char reg_data) // { // int ret = -1; // unsigned char cnt = 0; // while (cnt < 1) { // ret = i2c_smbus_write_byte_data(sp0821->i2c_client, // reg_addr, reg_data); // if (ret < 0) { // qvga_dev_err(sp0821->dev, // "%s: i2c_write cnt=%d error=%d\n", __func__, // cnt, ret); // } else { // break; // } // cnt++; // msleep(2); // } // return ret; // } static unsigned char sp0821_i2c_read(struct sp0821 *sp0821, int address) { unsigned char rxdata = 0x00; unsigned char i2c_buf[4]; int ret = 0; int retry = 2; u8 i2c_addr[2]; struct i2c_client *client = sp0821->i2c_client; struct i2c_msg msgs[2]; i2c_addr[0] = (address & 0xff00)>>8; i2c_addr[1] = (address & 0xff); msgs[0].flags = 0; msgs[0].addr = (client->addr); msgs[0].len = 2; msgs[0].buf = i2c_addr; msgs[1].flags = I2C_M_RD; msgs[1].addr = (client->addr); msgs[1].len = 1; msgs[1].buf = i2c_buf; while (retry > 0) { ret = i2c_transfer(client->adapter, msgs, 2); //qvga_dev_err(&client->dev, "%s: read step1 ret:%d msgs[1].addr=%x\n", __func__, ret, msgs[1].addr); if (retry >0) { mdelay(20); if (ret == 0) { return 0; } } retry--; mdelay(2); } rxdata = i2c_buf[0]; return rxdata; } // static int sp0821_i2c_read1(struct sp0821 *sp0821, // unsigned char reg_addr, unsigned char *reg_data) // { // int ret = -1; // unsigned char cnt = 0; // while (cnt < 1) { // ret = i2c_smbus_read_byte_data(sp0821->i2c_client, reg_addr); // if (ret < 0) { // qvga_dev_err(sp0821->dev, // "%s: i2c_read cnt=%d error=%d\n", __func__, // cnt, ret); // } else { // *reg_data = ret; // break; // } // cnt++; // msleep(2); // } // return ret; // } static struct sp0821 *sp0821_malloc_init(struct i2c_client *client) { struct sp0821 *sp0821 = devm_kzalloc(&client->dev, sizeof(struct sp0821), GFP_KERNEL); if (sp0821 == NULL) { qvga_dev_err(&client->dev, "%s: devm_kzalloc failed.\n", __func__); return NULL; } sp0821->i2c_client = client; pr_info("%s enter , client_addr = 0x%02x\n", __func__, sp0821->i2c_client->addr); return sp0821; } #if 1 void sp0821_Init(struct sp0821 *sp0821) { /*SYS MCLK=24MHZ*/ sp0821_i2c_write(sp0821, 0x0103,0x01); sp0821_i2c_write(sp0821, 0x0100,0x00); sp0821_i2c_write(sp0821, 0x309b,0xf0); sp0821_i2c_write(sp0821, 0x30b0,0x0a); sp0821_i2c_write(sp0821, 0x30b8,0x21); sp0821_i2c_write(sp0821, 0x320c,0x01); sp0821_i2c_write(sp0821, 0x320d,0x6a); sp0821_i2c_write(sp0821, 0x320e,0x01); sp0821_i2c_write(sp0821, 0x320f,0xba); sp0821_i2c_write(sp0821, 0x3301,0x04); sp0821_i2c_write(sp0821, 0x3304,0x0c); sp0821_i2c_write(sp0821, 0x3305,0x00); sp0821_i2c_write(sp0821, 0x3306,0x10); sp0821_i2c_write(sp0821, 0x3307,0x02); sp0821_i2c_write(sp0821, 0x3308,0x04); sp0821_i2c_write(sp0821, 0x330a,0x00); sp0821_i2c_write(sp0821, 0x330b,0x30); sp0821_i2c_write(sp0821, 0x330e,0x01); sp0821_i2c_write(sp0821, 0x330f,0x01); sp0821_i2c_write(sp0821, 0x3310,0x01); sp0821_i2c_write(sp0821, 0x331e,0x09); sp0821_i2c_write(sp0821, 0x3333,0x10); sp0821_i2c_write(sp0821, 0x3334,0x40); sp0821_i2c_write(sp0821, 0x334c,0x01); sp0821_i2c_write(sp0821, 0x33b3,0x3e); sp0821_i2c_write(sp0821, 0x349f,0x02); sp0821_i2c_write(sp0821, 0x34a6,0x01); sp0821_i2c_write(sp0821, 0x34a7,0x07); sp0821_i2c_write(sp0821, 0x34a8,0x3a); sp0821_i2c_write(sp0821, 0x34a9,0x38); sp0821_i2c_write(sp0821, 0x34e9,0x38); sp0821_i2c_write(sp0821, 0x34f8,0x07); sp0821_i2c_write(sp0821, 0x3630,0x65); sp0821_i2c_write(sp0821, 0x3637,0x47); sp0821_i2c_write(sp0821, 0x363a,0xe0); sp0821_i2c_write(sp0821, 0x3670,0x03); sp0821_i2c_write(sp0821, 0x3674,0x75); sp0821_i2c_write(sp0821, 0x3675,0x65); sp0821_i2c_write(sp0821, 0x3676,0x65); sp0821_i2c_write(sp0821, 0x367c,0x01); sp0821_i2c_write(sp0821, 0x367d,0x03); sp0821_i2c_write(sp0821, 0x3690,0xe0); sp0821_i2c_write(sp0821, 0x3691,0xe1); sp0821_i2c_write(sp0821, 0x3692,0xe1); sp0821_i2c_write(sp0821, 0x3693,0xe1); sp0821_i2c_write(sp0821, 0x3694,0x03); sp0821_i2c_write(sp0821, 0x3695,0x07); sp0821_i2c_write(sp0821, 0x3696,0x07); sp0821_i2c_write(sp0821, 0x37f9,0x29); sp0821_i2c_write(sp0821, 0x3900,0x91); sp0821_i2c_write(sp0821, 0x3904,0x0f); sp0821_i2c_write(sp0821, 0x3908,0x00); sp0821_i2c_write(sp0821, 0x391b,0x07); sp0821_i2c_write(sp0821, 0x391c,0x0a); sp0821_i2c_write(sp0821, 0x391d,0x15); sp0821_i2c_write(sp0821, 0x391e,0x28); sp0821_i2c_write(sp0821, 0x391f,0x41); sp0821_i2c_write(sp0821, 0x3948,0x00);//blc sp0821_i2c_write(sp0821, 0x4509,0x10); sp0821_i2c_write(sp0821, 0x470b,0x0a); sp0821_i2c_write(sp0821, 0x470d,0x06); sp0821_i2c_write(sp0821, 0x5000,0xc2); sp0821_i2c_write(sp0821, 0x5001,0x01); sp0821_i2c_write(sp0821, 0x5170,0x2c); sp0821_i2c_write(sp0821, 0x5172,0xc1); sp0821_i2c_write(sp0821, 0x518b,0x00);//again sp0821_i2c_write(sp0821, 0x518c,0x20); sp0821_i2c_write(sp0821, 0x518d,0x01);//shutter sp0821_i2c_write(sp0821, 0x518e,0x7c); sp0821_i2c_write(sp0821, 0x518f,0x00); sp0821_i2c_write(sp0821, 0x519e,0x10); sp0821_i2c_write(sp0821, 0x300a,0x00);//SIP input sp0821_i2c_write(sp0821, 0x0100,0x01); /*shutter gain must write after stream on */ sp0821_i2c_write(sp0821, 0x518b,0x03);//again=4x sp0821_i2c_write(sp0821, 0x518c,0x20); sp0821_i2c_write(sp0821, 0x518d,0x01);//shutter=20ms sp0821_i2c_write(sp0821, 0x518e,0xb0); sp0821_i2c_write(sp0821, 0x518f,0x00); sp0821_i2c_write(sp0821, 0x519e,0x10); } /* sensor_init */ #endif #if 0 void sp0821_Init(struct sp0821 *sp0821) { /*SYS*/ sp0821_i2c_write(sp0821, 0x30, 0x00); qvga_dev_info(sp0821->dev, "%s zho0 sp0821 reg[0x30]\n", __func__); sp0821_i2c_write(sp0821, 0x32, 0x00); sp0821_i2c_write(sp0821, 0x03, 0x01); sp0821_i2c_write(sp0821, 0x04, 0x2c); sp0821_i2c_write(sp0821, 0x24, 0x80); sp0821_i2c_write(sp0821, 0x9b, 0x32); sp0821_i2c_write(sp0821, 0xd7, 0x00); sp0821_i2c_write(sp0821, 0xc5, 0xc7); sp0821_i2c_write(sp0821, 0xc6, 0xe2); sp0821_i2c_write(sp0821, 0xe7, 0x03); qvga_dev_info(sp0821->dev, "%s zho1 sp0821 reg[0xe7]\n", __func__); sp0821_i2c_write(sp0821, 0x32, 0x00); sp0821_i2c_write(sp0821, 0x32, 0x01); sp0821_i2c_write(sp0821, 0x32, 0x00); sp0821_i2c_write(sp0821, 0xbf, 0x0f); sp0821_i2c_write(sp0821, 0xba, 0x5a); sp0821_i2c_write(sp0821, 0xbb, 0x69); sp0821_i2c_write(sp0821, 0xe7, 0x00); sp0821_i2c_write(sp0821, 0x32, 0x07); sp0821_i2c_write(sp0821, 0x31, 0x03); sp0821_i2c_write(sp0821, 0x19, 0x04); sp0821_i2c_write(sp0821, 0x2c, 0x0f); sp0821_i2c_write(sp0821, 0x2e, 0x7c); qvga_dev_info(sp0821->dev, "%s zho2 sp0821 reg[0x2e]\n", __func__); sp0821_i2c_write(sp0821, 0x30, 0x00); sp0821_i2c_write(sp0821, 0x28, 0x2e); sp0821_i2c_write(sp0821, 0x29, 0x1f); sp0821_i2c_write(sp0821, 0x0f, 0x30); sp0821_i2c_write(sp0821, 0x14, 0xb0); sp0821_i2c_write(sp0821, 0x38, 0x50); sp0821_i2c_write(sp0821, 0x39, 0x52); sp0821_i2c_write(sp0821, 0x3a, 0x60); sp0821_i2c_write(sp0821, 0x3b, 0x10); sp0821_i2c_write(sp0821, 0x3c, 0xe0); sp0821_i2c_write(sp0821, 0x85, 0x01); sp0821_i2c_write(sp0821, 0xe0, 0x02); qvga_dev_info(sp0821->dev, "%s zho3 sp0821 reg[0xe0]\n", __func__); sp0821_i2c_write(sp0821, 0xe5, 0x60); sp0821_i2c_write(sp0821, 0xf5, 0x02); sp0821_i2c_write(sp0821, 0xf1, 0x03); sp0821_i2c_write(sp0821, 0xf3, 0x40); sp0821_i2c_write(sp0821, 0x41, 0x00); sp0821_i2c_write(sp0821, 0x05, 0x00); sp0821_i2c_write(sp0821, 0x06, 0x00); sp0821_i2c_write(sp0821, 0x07, 0x00); sp0821_i2c_write(sp0821, 0x08, 0x00); sp0821_i2c_write(sp0821, 0x09, 0x00); sp0821_i2c_write(sp0821, 0x0a, 0x34); sp0821_i2c_write(sp0821, 0x0D, 0x01); sp0821_i2c_write(sp0821, 0xc8, 0x10); sp0821_i2c_write(sp0821, 0x29, 0x1e); qvga_dev_info(sp0821->dev, "%s zho4 sp0821 reg[0x29]\n", __func__); sp0821_i2c_write(sp0821, 0xa2, 0x26); sp0821_i2c_write(sp0821, 0xa3, 0x02); sp0821_i2c_write(sp0821, 0xa4, 0x32); sp0821_i2c_write(sp0821, 0xa5, 0x00); sp0821_i2c_write(sp0821, 0xa8, 0x32); sp0821_i2c_write(sp0821, 0xa9, 0x00); sp0821_i2c_write(sp0821, 0xaa, 0x01); sp0821_i2c_write(sp0821, 0xab, 0x00); sp0821_i2c_write(sp0821, 0x4c, 0x80); sp0821_i2c_write(sp0821, 0x4d, 0x80); sp0821_i2c_write(sp0821, 0xa6, 0xf0); sp0821_i2c_write(sp0821, 0xa7, 0x20); sp0821_i2c_write(sp0821, 0xac, 0xf0); sp0821_i2c_write(sp0821, 0xad, 0x20); sp0821_i2c_write(sp0821, 0x8a, 0x3e); qvga_dev_info(sp0821->dev, "%s zho5 sp0821 reg[0x8a]\n", __func__); sp0821_i2c_write(sp0821, 0x8b, 0x30); sp0821_i2c_write(sp0821, 0x8c, 0x2a); sp0821_i2c_write(sp0821, 0x8d, 0x26); sp0821_i2c_write(sp0821, 0x8e, 0x26); sp0821_i2c_write(sp0821, 0x8f, 0x24); sp0821_i2c_write(sp0821, 0x90, 0x24); sp0821_i2c_write(sp0821, 0x91, 0x22); sp0821_i2c_write(sp0821, 0x92, 0x22); sp0821_i2c_write(sp0821, 0x93, 0x22); sp0821_i2c_write(sp0821, 0x94, 0x20); sp0821_i2c_write(sp0821, 0x95, 0x20); sp0821_i2c_write(sp0821, 0x96, 0x20); sp0821_i2c_write(sp0821, 0x17, 0x88); sp0821_i2c_write(sp0821, 0x18, 0x80); sp0821_i2c_write(sp0821, 0x4e, 0x78); sp0821_i2c_write(sp0821, 0x4f, 0x78); sp0821_i2c_write(sp0821, 0x58, 0x8a); sp0821_i2c_write(sp0821, 0x59, 0xa8); sp0821_i2c_write(sp0821, 0x5a, 0x80); qvga_dev_info(sp0821->dev, "%s zho6 sp0821 reg[0x5a]\n", __func__); sp0821_i2c_write(sp0821, 0xca, 0x00); sp0821_i2c_write(sp0821, 0x86, 0x08); sp0821_i2c_write(sp0821, 0x87, 0x0f); sp0821_i2c_write(sp0821, 0x88, 0x30); sp0821_i2c_write(sp0821, 0x89, 0x45); sp0821_i2c_write(sp0821, 0x9e, 0x94); sp0821_i2c_write(sp0821, 0x9f, 0x88); sp0821_i2c_write(sp0821, 0x97, 0x84); sp0821_i2c_write(sp0821, 0x98, 0x88); sp0821_i2c_write(sp0821, 0x99, 0x74); sp0821_i2c_write(sp0821, 0x9a, 0x84); sp0821_i2c_write(sp0821, 0xa0, 0x7c); sp0821_i2c_write(sp0821, 0xa1, 0x78); sp0821_i2c_write(sp0821, 0x9d, 0x09); sp0821_i2c_write(sp0821, 0xB1, 0x04); sp0821_i2c_write(sp0821, 0xb3, 0x00); qvga_dev_info(sp0821->dev, "%s zho7 sp0821 reg[0xb3]\n", __func__); sp0821_i2c_write(sp0821, 0x47, 0x40); sp0821_i2c_write(sp0821, 0xb8, 0x04); sp0821_i2c_write(sp0821, 0xb9, 0x28); sp0821_i2c_write(sp0821, 0x3f, 0x18); sp0821_i2c_write(sp0821, 0xc1, 0xff); sp0821_i2c_write(sp0821, 0xc2, 0x40); sp0821_i2c_write(sp0821, 0xc3, 0xff); sp0821_i2c_write(sp0821, 0xc4, 0x40); sp0821_i2c_write(sp0821, 0xc5, 0xc7); sp0821_i2c_write(sp0821, 0xc6, 0xe2); sp0821_i2c_write(sp0821, 0xc7, 0xef); sp0821_i2c_write(sp0821, 0xc8, 0x10); sp0821_i2c_write(sp0821, 0x50, 0x2a); sp0821_i2c_write(sp0821, 0x51, 0x2a); sp0821_i2c_write(sp0821, 0x52, 0x2f); sp0821_i2c_write(sp0821, 0x53, 0xcf); sp0821_i2c_write(sp0821, 0x54, 0xd0); qvga_dev_info(sp0821->dev, "%s zho8 sp0821 reg[0x54]\n", __func__); sp0821_i2c_write(sp0821, 0x5c, 0x1e); sp0821_i2c_write(sp0821, 0x5d, 0x21); sp0821_i2c_write(sp0821, 0x5e, 0x1a); sp0821_i2c_write(sp0821, 0x5f, 0xe9); sp0821_i2c_write(sp0821, 0x60, 0x98); sp0821_i2c_write(sp0821, 0xcb, 0x3f); sp0821_i2c_write(sp0821, 0xcc, 0x3f); sp0821_i2c_write(sp0821, 0xcd, 0x3f); sp0821_i2c_write(sp0821, 0xce, 0x85); sp0821_i2c_write(sp0821, 0xcf, 0xff); sp0821_i2c_write(sp0821, 0x79, 0x5a); sp0821_i2c_write(sp0821, 0x7a, 0xDC); sp0821_i2c_write(sp0821, 0x7b, 0x0A); sp0821_i2c_write(sp0821, 0x7c, 0xFD); sp0821_i2c_write(sp0821, 0x7d, 0x46); sp0821_i2c_write(sp0821, 0x7e, 0xFD); sp0821_i2c_write(sp0821, 0x7f, 0xFD); sp0821_i2c_write(sp0821, 0x80, 0xEF); sp0821_i2c_write(sp0821, 0x81, 0x54); qvga_dev_info(sp0821->dev, "%s zho9 sp0821 reg[0x81]\n", __func__); sp0821_i2c_write(sp0821, 0x1b, 0x0a); sp0821_i2c_write(sp0821, 0x1c, 0x0f); sp0821_i2c_write(sp0821, 0x1d, 0x15); sp0821_i2c_write(sp0821, 0x1e, 0x15); sp0821_i2c_write(sp0821, 0x1f, 0x15); sp0821_i2c_write(sp0821, 0x20, 0x1f); sp0821_i2c_write(sp0821, 0x21, 0x2a); sp0821_i2c_write(sp0821, 0x22, 0x2a); sp0821_i2c_write(sp0821, 0x56, 0x49); sp0821_i2c_write(sp0821, 0x1a, 0x14); sp0821_i2c_write(sp0821, 0x34, 0x1f); sp0821_i2c_write(sp0821, 0x82, 0x10); sp0821_i2c_write(sp0821, 0x83, 0x00); qvga_dev_info(sp0821->dev, "%s zho10 sp0821 reg[0x83]\n", __func__); sp0821_i2c_write(sp0821, 0x84, 0xff); sp0821_i2c_write(sp0821, 0xd7, 0x50); sp0821_i2c_write(sp0821, 0xd8, 0x1a); sp0821_i2c_write(sp0821, 0xd9, 0x20); sp0821_i2c_write(sp0821, 0xc9, 0x1f); sp0821_i2c_write(sp0821, 0xbf, 0x33); sp0821_i2c_write(sp0821, 0xba, 0x37); sp0821_i2c_write(sp0821, 0xbb, 0x38); qvga_dev_info(sp0821->dev, "%s zho11 sp0821 reg[0xbb]\n", __func__); } /* sensor_init */ #endif int sp0821_GetSensorID(struct sp0821 *sp0821) { int retry = 2; unsigned char reg_data = 0x00; //check if sensor ID correct do { reg_data = sp0821_i2c_read(sp0821, 0x3107)<<8|sp0821_i2c_read(sp0821, 0x3108); qvga_dev_err(sp0821->dev, "drv-%s: Read MSB Sensor ID = 0x%02x\n", __func__, reg_data); // if (reg_data == SP0821_SENSOR_ID) { if (1) { qvga_dev_err(sp0821->dev, "drv-%s: Read Sensor ID sucess = 0x%02x\n", __func__, reg_data); driver_flag = 1; return 0; } else { qvga_dev_err(sp0821->dev, "rv-%s: Read Sensor ID Fail = 0x%02x\n", __func__, reg_data); driver_flag = 0; } mdelay(10); retry--; } while (retry > 0); return -1; } static void sp0821_vcam_control(struct sp0821 *sp0821, bool flag) { // struct regulator *vcama; struct regulator *vcamio; struct regulator *vcamd; int ret; int ret1; qvga_dev_info(sp0821->dev, "%s enter\n", __func__); vcamd = regulator_get(sp0821->dev,"vcamd"); if (IS_ERR(vcamd)) { qvga_dev_err(sp0821->dev, "%s get regulator vcamd failed\n", __func__); regulator_put(vcamd); return; } else { qvga_dev_err(sp0821->dev, "%s get regulator vcamd success\n", __func__); } if (flag) { regulator_set_voltage(vcamd, 1200000, 1200000); ret = regulator_enable(vcamd); } else { regulator_disable(vcamd); } // vcama = regulator_get(sp0821->dev,"vcama"); // if (IS_ERR(vcama)) { // qvga_dev_err(sp0821->dev, "%s get regulator vcama failed\n", __func__); // regulator_put(vcama); // return; // } // if (flag) { // regulator_set_voltage(vcama, 2800000, 2800000); // ret = regulator_enable(vcama); // } else { // regulator_disable(vcama); // } if (flag) { ret1 = aw37004_camera_power_up(2, 2800); if (ret1 == 0) { qvga_dev_err(sp0821->dev, "%s get regulator vcama success\n", __func__); } else { qvga_dev_err(sp0821->dev, "%s get regulator vcama failed\n", __func__); } } vcamio = regulator_get(sp0821->dev,"vcamio"); if (IS_ERR(vcamio)) { qvga_dev_err(sp0821->dev, "%s get regulator vcamio failed\n", __func__); regulator_put(vcamio); return; } else { qvga_dev_err(sp0821->dev, "%s get regulator vcamio success\n", __func__); } if (flag) { regulator_set_voltage(vcamio, 1800000, 1800000); ret = regulator_enable(vcamio); } else { regulator_disable(vcamio); } return; } static void sp0821_hw_on_reset(struct sp0821 *sp0821) { qvga_dev_info(sp0821->dev, "%s enter\n", __func__); if (gpio_is_valid(sp0821->reset_gpio)) { gpio_set_value_cansleep(sp0821->reset_gpio, 1); } } static void sp0821_hw_on_reset1(struct sp0821 *sp0821) { qvga_dev_info(sp0821->dev, "%s enter\n", __func__); if (gpio_is_valid(sp0821->reset_gpio1)) { gpio_set_value_cansleep(sp0821->reset_gpio1, 1); } } static void sp0821_hw_off_reset(struct sp0821 *sp0821) { qvga_dev_info(sp0821->dev, "%s enter\n", __func__); if (gpio_is_valid(sp0821->reset_gpio)) { gpio_set_value_cansleep(sp0821->reset_gpio, 0); udelay(50); gpio_set_value_cansleep(sp0821->reset_gpio, 1); udelay(50); gpio_set_value_cansleep(sp0821->reset_gpio, 0); } } static void sp0821_hw_off_reset1(struct sp0821 *sp0821) { qvga_dev_info(sp0821->dev, "%s enter\n", __func__); if (gpio_is_valid(sp0821->reset_gpio1)) { gpio_set_value_cansleep(sp0821->reset_gpio1, 0); } } static void sp0821_hw_on(struct sp0821 *sp0821) { sp0821_hw_on_reset1(sp0821); sp0821_hw_on_reset(sp0821); sp0821_Init(sp0821); sp0821->hwen_flag = 1; } static void sp0821_hw_off(struct sp0821 *sp0821) { sp0821_hw_off_reset(sp0821); sp0821->hwen_flag = 0; } static ssize_t sp0821_get_reg(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; if (read_reg_flag) { len += snprintf(buf + len, PAGE_SIZE - len, "The reg 0x%02X value is 0x%02X\n", read_reg_id, read_reg_value); read_reg_flag = 0; read_reg_id = 0; read_reg_value = 0; } else { len += snprintf(buf + len, PAGE_SIZE - len, "Please echo reg id into reg\n"); } return len; } static ssize_t sp0821_set_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { unsigned int databuf[2] = { 0 }; unsigned char reg_data = 0x00; if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { sp0821_i2c_write(g_sp0821, databuf[0], databuf[1]); } else if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 1) { reg_data = sp0821_i2c_read(g_sp0821, databuf[0]); read_reg_id = databuf[0]; read_reg_value = reg_data; read_reg_flag = 1; } return len; } static ssize_t sp0821_get_name(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; if (driver_flag) { len += snprintf(buf + len, PAGE_SIZE - len, "%s\n", "sp_sp0821_yuv"); } else { len += snprintf(buf + len, PAGE_SIZE - len, "%s\n", "none"); } return len; } static ssize_t sp0821_get_light(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t len = 0; unsigned char reg_data1 = 0x00; //unsigned char reg_data2 = 0x00; u16 light = 0; reg_data1 = sp0821_i2c_read(g_sp0821, 0x5160); //reg_data2 = sp0821_i2c_read(g_sp0821, 0x516b); //light = (reg_data1<<8) + reg_data2; light = reg_data1; qvga_dev_err(g_sp0821->dev, "%s: sp0821 light=%d, %d\n", __func__, light, reg_data1); len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", light); return len; } // static ssize_t sp0821_get_light1(struct device *dev, // struct device_attribute *attr, char *buf) // { // ssize_t len = 0; // unsigned char reg_data = 0x00; // int length; // //struct sp0821 *sp0821 = dev_get_drvdata(dev); // length = sp0821_i2c_read1(g_sp0821, 0xb0, &reg_data); // len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", // reg_data); // return len; // } static ssize_t sp0821_set_light(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { ssize_t ret; unsigned int state; ret = kstrtouint(buf, 10, &state); if (ret) { qvga_dev_err(g_sp0821->dev, "%s: fail to change str to int\n", __func__); return ret; } if (state == 0) sp0821_hw_off(g_sp0821); /*OFF*/ else sp0821_hw_on(g_sp0821); /*ON*/ return len; } static DEVICE_ATTR(reg, S_IWUSR | S_IRUGO, sp0821_get_reg, sp0821_set_reg); static DEVICE_ATTR(cam_name, S_IWUSR | S_IRUGO, sp0821_get_name, NULL); static DEVICE_ATTR(light, S_IWUSR | S_IRUGO, sp0821_get_light, sp0821_set_light); static struct attribute *sp0821_attributes[] = { &dev_attr_reg.attr, &dev_attr_cam_name.attr, &dev_attr_light.attr, NULL }; static struct attribute_group sp0821_attribute_group = { .attrs = sp0821_attributes }; static void sp0821_parse_gpio_dt(struct sp0821 *sp0821, struct device_node *np) { qvga_dev_info(sp0821->dev, "%s enter, dev_i2c%d@0x%02X\n", __func__, sp0821->i2c_seq, sp0821->i2c_addr); sp0821->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); if (sp0821->reset_gpio < 0) { qvga_dev_err(sp0821->dev, "%s: no reset gpio provided, hardware reset unavailable\n", __func__); sp0821->reset_gpio = -1; } else { qvga_dev_info(sp0821->dev, "%s: reset gpio provided ok\n", __func__); } sp0821->reset_gpio1 = of_get_named_gpio(np, "reset-gpio1", 0); if (sp0821->reset_gpio1 < 0) { qvga_dev_err(sp0821->dev, "%s: no reset gpio1 provided, hardware reset unavailable\n", __func__); sp0821->reset_gpio1 = -1; } else { qvga_dev_info(sp0821->dev, "%s: reset gpio1 provided ok\n", __func__); } } static void sp0821_parse_dt(struct sp0821 *sp0821, struct device_node *np) { qvga_dev_info(sp0821->dev, "%s enter, dev_i2c%d@0x%02X\n", __func__, sp0821->i2c_seq, sp0821->i2c_addr); sp0821_parse_gpio_dt(sp0821, np); } /**************************************************************************** * sp0821 i2c driver *****************************************************************************/ static int sp0821_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device_node *np = client->dev.of_node; struct pinctrl *sp0821_pinctrl = NULL; struct pinctrl_state *set_state = NULL; struct pinctrl_state *sp0821_mclk_on = NULL; struct pinctrl_state *sp0821_mclk_off = NULL; struct sp0821 *sp0821 = NULL; struct class *qvga_class; struct device *dev; int ret = -1; pr_err("scw %s enter , i2c%d@0x%02x\n", __func__, client->adapter->nr, client->addr); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { qvga_dev_err(&client->dev, "%s: check_functionality failed\n", __func__); ret = -ENODEV; goto exit_check_functionality_failed; } sp0821 = sp0821_malloc_init(client); g_sp0821 = sp0821; sp0821->i2c_seq = sp0821->i2c_client->adapter->nr; sp0821->i2c_addr = sp0821->i2c_client->addr; if (sp0821 == NULL) { dev_err(&client->dev, "%s: failed to parse device tree node\n", __func__); ret = -ENOMEM; goto exit_devm_kzalloc_failed; } sp0821->dev = &client->dev; i2c_set_clientdata(client, sp0821); sp0821_parse_dt(sp0821, np); if (gpio_is_valid(sp0821->reset_gpio)) { ret = devm_gpio_request_one(&client->dev, sp0821->reset_gpio, GPIOF_OUT_INIT_LOW, "sp0821_rst"); if (ret) { qvga_dev_err(&client->dev, "%s: rst request failed\n", __func__); goto exit_gpio_request_failed; } } if (gpio_is_valid(sp0821->reset_gpio1)) { ret = devm_gpio_request_one(&client->dev, sp0821->reset_gpio1, GPIOF_OUT_INIT_LOW, "sp0821_rst1"); if (ret) { qvga_dev_err(&client->dev, "%s: rst1 request failed\n", __func__); goto exit_gpio_request_failed; } } sp0821_pinctrl = devm_pinctrl_get(&client->dev); if (IS_ERR_OR_NULL(sp0821_pinctrl)) { qvga_dev_err(&client->dev, "%s: sp0821_pinctrl not defined\n", __func__); } else { set_state = pinctrl_lookup_state(sp0821_pinctrl, SP0821_MCLK_ON); if (IS_ERR_OR_NULL(set_state)) { qvga_dev_err(&client->dev, "%s: sp0821_pinctrl lookup failed for mclk on\n", __func__); } else { sp0821_mclk_on = set_state; } set_state = pinctrl_lookup_state(sp0821_pinctrl, SP0821_MCLK_OFF); if (IS_ERR_OR_NULL(set_state)) { qvga_dev_err(&client->dev, "%s: sp0821_pinctrl lookup failed for mclk off\n", __func__); } else { sp0821_mclk_off = set_state; } ret = pinctrl_select_state(sp0821_pinctrl, sp0821_mclk_off); if (ret < 0) { qvga_dev_err(&client->dev, "%s: sp0821_pinctrl select failed for mclk off\n", __func__); } } //power on camera sp0821_hw_off_reset1(sp0821); mdelay(5); sp0821_vcam_control(sp0821, true); mdelay(1); ret = pinctrl_select_state(sp0821_pinctrl, sp0821_mclk_on); if (ret < 0) { qvga_dev_err(&client->dev, "%s: sp0821_pinctrl select failed for mclk on\n", __func__); } sp0821_hw_on_reset1(sp0821); sp0821_hw_on_reset(sp0821); mdelay(5); // sp0821->hwen_flag = 1; /* sp0821 sensor id */ ret = sp0821_GetSensorID(sp0821); if (ret < 0) { qvga_dev_err(&client->dev, "%s: sp0821read_sensorid failed ret=%d\n", __func__, ret); goto exit_i2c_check_id_failed; } //power off camera sp0821_vcam_control(sp0821, false); sp0821_hw_off_reset1(sp0821); // sp0821_Init(sp0821); qvga_class = class_create(THIS_MODULE, "qvga_cam"); dev = device_create(qvga_class, NULL, client->dev.devt, NULL, "qvga_depth"); ret = sysfs_create_group(&dev->kobj, &sp0821_attribute_group); if (ret < 0) { qvga_dev_err(&client->dev, "%s failed to create sysfs nodes\n", __func__); } return 0; exit_i2c_check_id_failed: sp0821_vcam_control(sp0821, false); sp0821_hw_off_reset1(sp0821); if (gpio_is_valid(sp0821->reset_gpio)) devm_gpio_free(&client->dev, sp0821->reset_gpio); exit_gpio_request_failed: devm_kfree(&client->dev, sp0821); sp0821 = NULL; exit_devm_kzalloc_failed: exit_check_functionality_failed: return ret; } static int sp0821_i2c_remove(struct i2c_client *client) { struct sp0821 *sp0821 = i2c_get_clientdata(client); if (gpio_is_valid(sp0821->reset_gpio)) devm_gpio_free(&client->dev, sp0821->reset_gpio); if (gpio_is_valid(sp0821->reset_gpio1)) devm_gpio_free(&client->dev, sp0821->reset_gpio1); devm_kfree(&client->dev, sp0821); sp0821 = NULL; return 0; } static const struct of_device_id sp0821_of_match[] = { {.compatible = "sc,sp_sp0821_yuv"}, {}, }; static struct i2c_driver sp0821_i2c_driver = { .driver = { .owner = THIS_MODULE, .name = "sp_sp0821_yuv", .of_match_table = sp0821_of_match, }, .probe = sp0821_i2c_probe, .remove = sp0821_i2c_remove, }; static int __init sp0821_yuv_init(void) { int ret; pr_info("%s: driver version: %s\n", __func__, SP0821_DRIVER_VERSION); ret = i2c_add_driver(&sp0821_i2c_driver); if (ret) { pr_info("****[%s] Unable to register driver (%d)\n", __func__, ret); return ret; } return 0; } static void __exit sp0821_yuv_exit(void) { pr_info("%s enter\n", __func__); i2c_del_driver(&sp0821_i2c_driver); } module_init(sp0821_yuv_init); module_exit(sp0821_yuv_exit); MODULE_AUTHOR("wangyuqiu@longcheer.com>"); MODULE_DESCRIPTION("sp0821 yuv driver"); MODULE_LICENSE("GPL v2"); 根据上一条的报错,帮忙分析原因
07-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值