赞
踩
因以下原因,导致不得不通过代码分析来学习如何在该平台下进行摄像头驱动移植
笔记主要以了解移植驱动所需要做的工作为目标导向,通过分析相关源码的方式一步一步地抽丝剥茧而形成的记录。
记录目的,一来可以借助笔记的方式来总结归纳以备后用,二来也可以分享给需要的人少走弯路。
在 Orange Pi 2G-IOT 平台(主控为RDA8810)移植 GC2145 摄像头驱动,使之可用。
目标的驱动 gc2145,要能驱动摄像头需要具备以下几个条件:
1. 供电电压
DVDD:1.8V (Camera Sensor 的内核电压)
AVDD:2.8V
DOVDD:2.8V (要与主控引脚 IO 电压一致)
2. 上电掉电时序(ldo、gpio、mclk)
供电、down、reset、mclock 的开启和关闭顺序
3. gc2145 设备驱动
1. 访问芯片获取 chipid (这一步至关重要)
2. 初始化代码、分辨率切换等等寄存器配置
4. 注册 V4L2 接口
根据 v4l2 接口提供对应的配置实现,如修改分辨率等等。
这部分不一定在具体的摄像头驱动中实现,如高通平台和这颗展讯平台,会有专门的驱动实现。
因此会发现没有摄像头也会有 /dev/videoX 节点存在。
通过内核日志来确认原使用的摄像头驱动
- // 摄像头: gc0309
- [ 8.502624] rda_sensor_adapt: camera id=0
- [ 8.518554] rda_sensor_adapt: try gc0309, chip_id=0xa0
- [ 8.722412] rda-i2c rda-i2c.0: hal_i2c_raw_send_byte, timeout2
- [ 8.723022] rda-i2c rda-i2c.0: rda_i2c_send_bytes, send addr fail, addr = 0x21
- [ 8.932434] rda-i2c rda-i2c.0: hal_i2c_raw_send_byte, timeout2
- [ 8.932983] rda-i2c rda-i2c.0: rda_i2c_send_bytes, send addr fail, addr = 0x21
- [ 9.142456] rda-i2c rda-i2c.0: hal_i2c_raw_send_byte, timeout2
- [ 9.143005] rda-i2c rda-i2c.0: rda_i2c_send_bytes, send addr fail, addr = 0x21
- [ 9.143859] sensor_i2c_read: i2c read error, reg: 0x0
- [ 9.144592] rda_sensor_adapt: failed!
通过外设名字搜索来确认相关源码的位置
- ~/work/git/OrangePi_2G-IOT-Andorid_SDCard$ find . -name "*gc0309*"
- ./runyee/project/riot01/riot01_NollecA9V2V8810P_ry_smt/code/device/rda/driver/camera/inc/gc0309_config_front.h
- ./runyee/project/riot01/riot01_NollecA9V2V8810P_ry_smt/code/device/rda/driver/camera/inc/gc0309_config_back.h
- ./out/target/product/etau-NollecA9V2V8810P/obj/device/rda/driver/camera/inc/gc0309_config.h
- ./out/target/product/etau-NollecA9V2V8810P/obj/device/rda/driver/camera/inc/gc0309_config_front.h
- ./out/target/product/etau-NollecA9V2V8810P/obj/device/rda/driver/camera/inc/gc0309_config_back.h
- ./device/rda/driver/camera/inc/gc0309_config.h
- ./device/rda/driver/camera/inc/gc0309_config_front.h
- ./device/rda/driver/camera/inc/gc0309_config_back.h
1. 通过日志搜索得知外设驱动源码路径:device\rda\driver
device\rda\driver\camera\rda_cam_sensor.c device\rda\driver\camera\inc\rda2201_config.h device\rda\driver\camera\inc\sp0718_config.h device\rda\driver\camera\inc\gc0313_csi_config.h device\rda\driver\camera\inc\sp0a20_csi_config.h device\rda\driver\camera\inc\gc0312_config.h device\rda\driver\camera\inc\sp0a09_csi_config.h device\rda\driver\camera\inc\gc2035_config.h device\rda\driver\camera\inc\gc0409_csi_config.h device\rda\driver\camera\inc\sp2508_csi_config.h device\rda\driver\camera\inc\rda2201_csi_config.h device\rda\driver\camera\inc\gc0308_config.h device\rda\driver\camera\inc\gc0309_config.h device\rda\driver\camera\inc\gc2355_csi_config.h device\rda\driver\camera\inc\gc0309_config_front.h device\rda\driver\camera\inc\gc2155_config.h device\rda\driver\camera\inc\gc0328_config.h device\rda\driver\camera\inc\gc0329_config.h device\rda\driver\camera\inc\gc0310_csi_config.h device\rda\driver\camera\inc\gc2145_config.h device\rda\driver\camera\inc\gc2145_csi_config.h device\rda\driver\camera\inc\gc2035_csi_config.h device\rda\driver\camera\inc\gc0328c_config.h device\rda\driver\camera\inc\gc0309_config_back.h
2. 通过查看驱动源文件确定配置项:device\rda\driver\camera\rda_cam_sensor.c
- // rda_sensor.h ---------------------------------------------------------
- struct sensor_callback_ops {
- void(*cb_pdn) (bool pdn, bool acth, int id);
- void(*cb_rst) (bool rst, bool acth);
- void(*cb_clk) (bool out, int mclk);
- void(*cb_i2c_r) (const u16 addr, u8 *data, u8 bits);
- void(*cb_i2c_w) (const u16 addr, const u8 data, u8 bits);
- void(*cb_isp_reg_write) (const u32 addr_offset, const u8 data);
- void(*cb_isp_set_exp) (int exp);
- void(*cb_isp_set_awb) (int awb);
- void(*cb_isp_set_af)(int af);
- };
- // rda_sensor.h ---------------------------------------------------------
-
- static struct sensor_callback_ops rda_sensor_cb; // 注意这个变量,保存了一系列控制接口
- void sensor_power_down(bool pdn, bool acth, int id)
- {
- rda_sensor_cb.cb_pdn(pdn, acth, id);
- }
- void sensor_reset(bool rst, bool acth)
- {
- rda_sensor_cb.cb_rst(rst, acth);
- }
- void sensor_clock(bool out, int mclk)
- {
- rda_sensor_cb.cb_clk(out, mclk);
- }
- void sensor_read(const u16 addr, u8 *data, u8 bits)
- {
- rda_sensor_cb.cb_i2c_r(addr, data, bits);
- }
- void sensor_write(const u16 addr, const u8 data, u8 bits)
- {
- rda_sensor_cb.cb_i2c_w(addr, data, bits);
- }
-
- #if defined(GC0309_B) || defined(GC0309_F)
- #include "gc0309_config.h"
- #endif
-
- #if defined(GC2145_B) || defined(GC2145_F) // 目标
- #include "gc2145_config.h" // GC2145 的驱动实现
- #endif
-
- #ifdef RDA_CUSTOMER_DRV_CSB
- static LIST_HEAD(rda_sensor_b_list);
- static void init_back_sensor_list(struct list_head *head)
- {
- ......
-
- #ifdef GC0309_B
- INIT_LIST_HEAD(&gc0309_dev.list);
- list_add_tail(&gc0309_dev.list, head); // 系统原本自带的
- #endif
- ......
- #ifdef GC2145_B // 目标
- INIT_LIST_HEAD(&gc2145_dev.list);
- list_add_tail(&gc2145_dev.list, head); // 将该驱动加入链表
- #endif
- ......
- }
- #endif
-
- static int __init cam_sensor_subsys_init(void)
- {
- ......
-
- #ifdef RDA_CUSTOMER_DRV_CSB
- init_back_sensor_list(&rda_sensor_b_list);
- // 开始进行适配, rda_sensor_cb 这个参数至关重要,gc2145 驱动最终会通过该参数操作上电时序, 这里是重点
- ret = rda_sensor_adapt(&rda_sensor_cb,&rda_sensor_b_list, 0);
- if (ret < 0) {
- rda_dbg_camera("%s: back sensor adapt failed\n", __func__);
- } else {
- init_done = 0;
- }
- #endif
-
- ......
- return init_done;
- }
-
- subsys_initcall(cam_sensor_subsys_init);
-
- MODULE_DESCRIPTION("The sensor driver for RDA Linux");
- MODULE_LICENSE("GPL");
3. 通过搜索相关的宏定义如 RDA_CUSTOMER_DRV_CSB 找到: device\rda\etau\NollecA9V2V8810P\customer.mk
- 原来配置项: RDA_CUSTOMER_DRV_CSB := GC0309
- 修改配置项: RDA_CUSTOMER_DRV_CSB := GC2145
4. 通过搜索相关的宏定义如 RDA_CUSTOMER_DRV_CSB 找到 Makefile: device\rda\driver\camera\Makefile
- ...
- ifneq ($(RDA_CUSTOMER_DRV_CSB),)
- EXTRA_CFLAGS += -DRDA_CUSTOMER_DRV_CSB
- EXTRA_CFLAGS += $(foreach n,$(RDA_CUSTOMER_DRV_CSB),-D$(n)_B) // 修改格式为 GC2145_B
- endif
- ..
5. 结合驱动源文件(步骤2)找到确定对应具体的摄像头驱动文件:device\rda\driver\camera\inc\gc2145_config.h
- ......
-
- static struct sensor_info gc2145_info = {
- .name = "gc2145",
- .chip_id = 0x2145, // 指定了 Chipid 会与读取出来的做比较
- .mclk = 26, // mclk 频率
- .i2c_addr = 0x3C, // 指定了 I2C 地址
- .exp_def = 0,
- .awb_def = 1,
- .rst_act_h = false, // reset 低复位
- .pdn_act_h = true, // pwdn 高电平有效
- .init = &gc2145_init, // 指向了一个数组,数组包含了各个寄存器的初始化数据
- .win_cfg = &gc2145_win_cfg, // 指向了一个数组,包含了所支持的分辨率的各个寄存器的配置
- .csi_cfg = &gc2145_csi_cfg
- };
-
- ......
-
- static struct sensor_ops gc2145_ops = {
- .power = gc2145_power, // 上电时序
- .get_chipid = gc2145_get_chipid, // 获取芯片ID
- .get_lum = gc2145_get_lum,
- .set_flip = gc2145_set_flip,
- .set_exp = gc2145_set_exp,
- .set_awb = gc2145_set_awb,
- .start = NULL,
- .stop = NULL
- };
-
- struct sensor_dev gc2145_dev = { // 重点
- .info = &gc2145_info,
- .ops = &gc2145_ops,
- };
- ......
-
- static u32 gc2145_get_chipid(void)
- {
- u16 chip_id = 0;
- u8 tmp;
-
- sensor_read(0xf0, &tmp, RESERVE); // 注意这点
- chip_id = (tmp << 8) & 0xff00;
- sensor_read(0xf1, &tmp, RESERVE); // 注意这点
- chip_id |= (tmp & 0xff);
- printk("%s chipid = 0x%4x\n",__func__,chip_id);
- return chip_id;
- }
-
- static u32 gc2145_power(int id, int mclk, bool rst_h, bool pdn_h)
- {
- /* set state to power off */
- sensor_power_down(true, pdn_h, 0); // 注意这点
- mdelay(1);
- sensor_power_down(true, pdn_h, 1); // 注意这点
- mdelay(1);
- sensor_reset(true, rst_h);
- mdelay(1);
- sensor_clock(false, mclk);
- mdelay(5);
-
- /* power on sequence */
- sensor_clock(true, mclk);
- mdelay(1);
- sensor_power_down(false, pdn_h, id);
- mdelay(1);
- sensor_reset(false, rst_h);
- mdelay(10);
-
- return 0;
- }
6. 搜索(步骤2)驱动调用的接口 rda_sensor_adapt() 找到:kernel\drivers\media\platform\rda\rda_sensor_base.c
- /* Export Function for camera sensor module in vendor --------------*/
- static int rda_sensor_power(struct v4l2_subdev *sd, int on);
- int rda_sensor_adapt(struct sensor_callback_ops *callback, // 一个导出函数, 被 rda_cam_sensor.c 调用
- struct list_head *sdl, u32 id)
- {
- struct rda_sensor_priv *priv;
- struct sensor_dev *tmp = NULL;
- struct i2c_client *client = rda_sensor_i2c_client[id];
- bool adapted = false;
- u32 cid;
- u32 chipid1 = 0;
- printk(KERN_ALERT "%s: camera id=%d\n", __func__, id);
-
- if (!client || !sdl || list_empty(sdl)) {
- printk(KERN_ERR "%s: failed i2c client %p sdl %p!\n",
- __func__, client, sdl);
- return -EINVAL;
- }
-
- // 提供了 I2C 读写以及对 pwdn、reset、mclk 的具体实现,由具体的摄像头驱动调用(gc2145_config.h)
- callback->cb_pdn = rda_sensor_pdn; // Camera pwdn 引脚控制回调
- callback->cb_rst = rda_sensor_rst; // Camera reset 引脚控制回调
- callback->cb_clk = rda_sensor_clk; // mclk 引脚控制回调
- callback->cb_i2c_r = SENSOR_READ(id); // I2C 读取回调
- callback->cb_i2c_w = SENSOR_WRITE(id); // I2C 写入回调
-
- mutex_lock(&rda_sensor_mutex);
- priv = to_rda_sensor(client);
-
- // 识别 Sensor ChipId
- rda_sensor_power(&priv->subdev, 1); // 上电
- // 遍历所有具体摄像头驱动的sensor_dev结构体,如 struct sensor_dev gc2145_dev 对应 tmp
- list_for_each_entry(tmp, sdl, list) {
- client->addr = tmp->info->i2c_addr; // 对应 gc2145_info->i2c_addr
- cid = tmp->info->chip_id; // 对应 gc2145_info->chip_id
- tmp->ops->power(id, // 开始调用具体摄像头的上电时序(里面控制的 pdwn\rst\clck 接口就上面提供的具体回调)
- tmp->info->mclk, // 对应 static u32 gc2145_power(int id, int mclk, bool rst_h, bool pdn_h)
- tmp->info->rst_act_h,
- tmp->info->pdn_act_h);
- printk(KERN_ALERT "%s: try %s, chip_id=0x%x\n",
- __func__, tmp->info->name, cid);
- if (cid == tmp->ops->get_chipid()) { // 对应 static u32 gc2145_get_chipid(void) 读取出来的 chipid 与 gc2145_info->chip_id 对比
- rda_dbg_camera(KERN_ERR "%s: name=%s, success!\n",
- __func__, tmp->info->name);
- tmp->cb = callback; // 保存回调接口到 gc2145_dev 中便于后续后续使用
- priv->cur_sdev = tmp;
- priv->dev_id = id;
- adapted = true; // 适配成功
- break;
- }
- }
- tmp = NULL;
- rda_sensor_power(&priv->subdev, 0); // 掉电
-
- mutex_unlock(&rda_sensor_mutex);
- if (!adapted) {
- printk(KERN_ERR "%s: failed!\n", __func__);
- return -ENODEV;
- }
- return 0;
- }
- EXPORT_SYMBOL(rda_sensor_adapt);
-
- // 控制 pwdn 的具体实现
- static void rda_sensor_pdn(bool pdn, bool acth, int id)
- {
- if (id) {
- #ifdef GPIO_CAM_PWDN1
- ...... // 如果有指定 GPIO 的话需要设定相应的宏
- ...... //gpio_request(GPIO_CAM_PWDN1, "camera pwdn1");
- ...... //gpio_direction_output(GPIO_CAM_PWDN1, x)
- ...... //gpio_free(GPIO_CAM_PWDN1)
- #else
- rcam_pdn(pdn, acth); // 默认使用主控专用的 GPIO
- #endif
- } else {
- #ifdef GPIO_CAM_PWDN0
- ...... // 如果有指定 GPIO 的话需要设定相应的宏
- ...... //gpio_request(GPIO_CAM_PWDN0, "camera pwdn0");
- ...... //gpio_direction_output(GPIO_CAM_PWDN0, x)
- ...... //gpio_free(GPIO_CAM_PWDN0)
- #else
- rcam_pdn(pdn, acth);
- #endif
- }
- }
-
- // 控制 reset 的具体实现
- static void rda_sensor_rst(bool rst, bool acth)
- {
- #ifdef GPIO_CAM_RESET
- ...... // 如果有指定 GPIO 的话需要设定相应的宏
- ...... //gpio_request(GPIO_CAM_RESET, "camera reset");
- ...... //gpio_direction_output(GPIO_CAM_RESET, x)
- ...... //gpio_free(GPIO_CAM_RESET)
- #else
- rcam_rst(rst, acth);
- #endif
- }
-
- // 控制 mclk 的具体实现
- static void rda_sensor_clk(bool out, int mclk)
- {
- rcam_clk(out, mclk);
- }
-
- ......
-
- static int rda_sensor_probe(struct i2c_client *client, const struct i2c_device_id *did)
- {
-
- ......
- v4l2_i2c_subdev_init(&priv->subdev, client, &rda_sensor_subdev_ops); // 注册了 V4L2 所需的回调
- printk(KERN_ERR "%s: sd->grp_id %x\n", __func__, priv->subdev.grp_id);
- v4l2_ctrl_handler_init(&priv->hdl, num);
- ......
- ret = rda_sensor_video_probe(client); // 里面调用了 v4l2_ctrl_handler_setup();
- ......
- return 0;
- }
-
- static const struct i2c_device_id rda_sensor_id[] = {
- { RDA_SENSOR_DRV_NAME, 0 }, // #define RDA_SENSOR_DRV_NAME "rda-sensor" 对应 Devices.c
- { RDA_SENSOR_DRV_NAME, 1 },
- };
-
- MODULE_DEVICE_TABLE(i2c, rda_sensor_id);
-
- static struct i2c_driver rda_sensor_i2c_driver = {
- .driver = {
- .name = RDA_SENSOR_DRV_NAME, // #define RDA_SENSOR_DRV_NAME "rda-sensor" 对应 Devices.c
- },
- .probe = rda_sensor_probe,
- .remove = rda_sensor_remove,
- .id_table = rda_sensor_id,
- };
-
- module_i2c_driver(rda_sensor_i2c_driver);
7. 通过平台驱动的名称 "rda-sensor" 搜索平台设备代码,找到:arch\arm\mach-rda\devices.c
- /*
- * Camera Controller
- */
- // 主控控制器的寄存器资源(这里只有一份,说明只有一个 Camera 控制器(CSI/SPI),查阅了 datasheet 也确认只有一个)
- static struct resource rda_camera_resource[] = {
- [0] = {
- .start = RDA_CAMERA_PHYS,
- .end = RDA_CAMERA_PHYS + RDA_CAMERA_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = RDA_IRQ_CAMERA,
- .end = RDA_IRQ_CAMERA,
- .flags = IORESOURCE_IRQ,
- },
- };
-
- // 主控控制器的时钟极性输出配置
- static struct rda_camera_device_data rda_camera_data[] = {
- {
- .hsync_act_low = 0, // hsync 时钟极性配置
- .vsync_act_low = 0, // vsync 时钟极性配置
- .pclk_act_falling = 0, // pclk 时钟极性配置
- },
- };
-
- static u64 rda_camera_dmamask = DMA_BIT_MASK(32);
-
- // 主控控制器的平台设备资源
- static struct platform_device rda_camera = {
- .name = RDA_CAMERA_DRV_NAME, // "rda-camera" 对应 rda_camera_8810.c(由此可见,该驱动是主控控制器驱动实现)
- .id = 0,
- .resource = rda_camera_resource, // Camera 硬件控制器资源
- .num_resources = ARRAY_SIZE(rda_camera_resource),
- .dev = {
- .dma_mask = &rda_camera_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = rda_camera_data, // 时钟极性配置
- },
- };
-
- /*
- * Camera Sensor
- */
- static struct i2c_board_info i2c_dev_camera[] = {
- { I2C_BOARD_INFO(RDA_SENSOR_DRV_NAME, (0x78 >> 1)) }, // "rda-sensor" 对应 rda_sensor_base.c (由此可见该驱动是外设驱动实现)
- { I2C_BOARD_INFO(RDA_SENSOR_DRV_NAME, (0x62 >> 1)) },
- };
-
- static struct regulator_bulk_data rda_sensor_regulator = {
- .supply = LDO_CAM, // #define LDO_CAM "v_cam", 指定 LDO 为 v_cam,重点
- };
-
- static struct soc_camera_desc sdesc_sensor[] = {
- {
- .subdev_desc = {
- .flags = 0,
- .drv_priv = NULL,
- .regulators = &rda_sensor_regulator, // 指定 LDO
- .num_regulators = 1,
- .power = NULL,
- .reset = NULL,
- },
- .host_desc = {
- .bus_id = 0,
- .i2c_adapter_id = _TGT_AP_I2C_BUS_ID_CAM,
- .board_info = &i2c_dev_camera[0],
- },
- },
- {
- .subdev_desc = {
- .flags = 0,
- .drv_priv = NULL,
- .regulators = &rda_sensor_regulator,
- .num_regulators = 1,
- .power = NULL,
- .reset = NULL,
- },
- .host_desc = {
- .bus_id = 0,
- .i2c_adapter_id = _TGT_AP_I2C_BUS_ID_CAM,
- .board_info = &i2c_dev_camera[1],
- },
- },
- };
-
- static struct platform_device rda_camera_sensor[] = {
- {
- .name = "soc-camera-pdrv", // 对应了 Soc_camera.c
- .id = 0,
- .dev = {
- .platform_data = &sdesc_sensor[0],
- },
- },
- {
- .name = "soc-camera-pdrv",
- .id = 1,
- .dev = {
- .platform_data = &sdesc_sensor[1],
- },
- },
- };
-
-
- static struct platform_device *devices[] __initdata = {
- ......
- &rda_camera_sensor[0],
- // &rda_camera_sensor[1],
- &rda_camera,
- &rda_gouda,
- ......
- };
-
- ......
-
- void __init rda_init_devices(void)
- {
- ......
- // 这里将上面的 devices 数组里面所有的设备资源都加入到平台中
- platform_add_devices(devices, ARRAY_SIZE(devices));
- }
8. 通过步骤七发现关联的驱动之一:kernel\drivers\media\platform\rda\rda_camera_8810.c
9. 通过步骤七发现关联的驱动之二:soc_camera.c
这里面主要是 V4L2 设备驱动部分的代码,就不继续分析下去了。
10. 通过步骤七确定供电是由 LDO_CAM ,搜索得到:arch/arm/mach-rda/regulator.c
- static struct regulator_ops rda_regulator_ops = {
- .enable = rda_regulator_enable,
- .disable = rda_regulator_disable,
- .is_enabled = rda_regulator_is_enabled,
- /* If we have used set_voltage_sel, we cann't use set_voltage. If so core of regulator will report warning. */
- .set_voltage_sel = rda_regulator_set_voltage_sel,
- /* If we have used get_voltage_sel, we cann't use get_voltage. If so core of regulator will report warning. */
- .get_voltage_sel = rda_regulator_get_voltage_sel,
- .list_voltage = rda_regulator_list_voltage,
- .set_mode = rda_regulator_set_mode,
- .get_mode = rda_regulator_get_mode,
- .set_current_limit = rda_regulator_set_current_limit,
- .get_current_limit = rda_regulator_get_current_limit,
- };
-
- /* standard regulator_desc define*/
- #define RDA_REGULATOR_DESC(_id_, _name_, _type_) \
- [(_id_)] = { \
- .name = (_name_), \
- .id = (_id_), \
- .ops = &rda_regulator_ops, \
- .type = _type_, \
- .owner = THIS_MODULE, \
- }
-
- static struct regulator_desc rda_regs_desc[] = {
- RDA_REGULATOR_DESC (rda_ldo_cam, LDO_CAM, REGULATOR_VOLTAGE),
- ......
- };
-
- static int rda_regulator_probe(struct platform_device *pdev)
- {
- struct rda_reg_config *rda_cfg = (struct rda_reg_config *)pdev->dev.platform_data;
- struct regulator_config config = { };
- struct regulator_init_data *init_data = rda_cfg->init_data;
- struct rda_regulator *rda_reg = NULL;
- int ret = 0;
- ......
- rda_reg->config = rda_cfg;
- rda_reg->private = (void *)pdev;
- ......
- config.dev = &pdev->dev;
- config.driver_data = rda_reg;
- config.init_data = init_data;
- rda_reg->rdev = regulator_register(&rda_regs_desc[pdev->id],&config);
- ......
- platform_set_drvdata(pdev, rda_reg);
- return 0;
- }
-
- static struct platform_driver rda_regulator_driver = {
- .driver = {
- .name = "regulator-rda", // 对应的平台设备资源驱动:regulator-devices.c
- .owner = THIS_MODULE,
- },
- .probe = rda_regulator_probe,
- .remove = rda_regulator_remove,
- };
11. 通过步骤10 的平台驱动名称 “regulator-rda”,搜索得到:arch/arm/mach-rda/regulator-devices.c
-
- #define REGULATOR_DEV(_id_, _data_) \
- { \
- .name = "regulator-rda", \
- .id = (_id_), \
- .dev = { \
- .platform_data = &(_data_), \
- }, \
- }
-
- static struct platform_device regulator_devices[] = {
-
- REGULATOR_DEV(rda_ldo_cam, cam_config),
- ......
- };
-
- void __init regulator_add_devices(void)
- {
- int i = 0;
- int j;
- struct rda_reg_config *pconfig;
- int *table;
-
- for (i = 0 ; i < ARRAY_SIZE(regulator_devices); i++) {
- ......
- platform_device_register(&(regulator_devices[i])); // 注册平台设备
- }
- ......
- }
-
- static struct regulator_consumer_supply cam_consumers[] = {
- CONSUMERS_POWER_CAM,
- };
-
- static struct rda_reg_def cam_default = {
- //.def_val = 2800000, // 指定默认电源(重点) 需要修改为 1800000 ,GC2145 DVDD 要求1.8V
- .def_val = 1800000,
- };
-
- static struct regulator_init_data cam_data = {
- .constraints = {
- .min_uV = 1800000, // 指定最电压范围
- .max_uV = 2800000,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_STATUS
- | REGULATOR_CHANGE_VOLTAGE
- | REGULATOR_CHANGE_MODE,
- },
-
- .num_consumer_supplies = ARRAY_SIZE(cam_consumers),
- .consumer_supplies = cam_consumers,
-
- .regulator_init = rda_regulator_do_init, // 指定了初始化接口
- .driver_data = &cam_default,
- };
-
- static int cam_vtable[] = {
- 1800000, 2800000 // 指定可选的电源表
- };
-
- static struct rda_reg_config cam_config = {
- .init_data = &cam_data, // 指定初始化的配置
- .pm_id = 1, // 指定芯片内的对应的 ldo (猜测, 没有文档明确)
- .msys_cmd = SYS_PM_CMD_EN, // 命令为使能该 ldo
- .table = (void *)cam_vtable, // 指定可选电压表
- .tsize = ARRAY_SIZE(cam_vtable),
- };
以该平台推荐的接法(即使用主控平台专用的 GPIO 和 ldo)
- device\rda\driver\camera\inc\rda_cam_sensor.c
- device\rda\etau\NollecA9V2V8810P\customer.mk
- kernel\arch\arm\mach-rda\devices.c
- kernel\arch\arm\mach-rda\regulator-devices.c
device\rda\driver\camera\inc\xxx_config.h
RDA_CUSTOMER_DRV_CSB := xxxxx
- kernel\arch\arm\mach-rda\devices.c
-
- // 主控控制器的时钟极性输出配置
- static struct rda_camera_device_data rda_camera_data[] = {
- {
- .hsync_act_low = 0, // hsync 时钟极性配置
- .vsync_act_low = 0, // vsync 时钟极性配置
- .pclk_act_falling = 0, // pclk 时钟极性配置
- },
- };
- kernel\arch\arm\mach-rda\regulator-devices.c
-
- static struct rda_reg_def cam_default = {
- .def_val = 2800000, // 指定默认电源(重点)
- };
效果优化部分还需要继续调整,这个已经不在本文范围内。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。