| /* |
| * drivers/amlogic/media/camera/common/cam_prober.c |
| * |
| * Copyright (C) 2017 Amlogic, Inc. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| */ |
| |
| #include <linux/i2c.h> |
| #include <linux/init.h> |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/err.h> |
| #include <linux/platform_device.h> |
| #include <linux/of.h> |
| #include <linux/slab.h> |
| #include <linux/pinctrl/consumer.h> |
| #include <linux/delay.h> |
| #include <linux/amlogic/media/frame_provider/tvin/tvin.h> |
| #include <linux/amlogic/media/camera/aml_cam_info.h> |
| #include <linux/amlogic/aml_gpio_consumer.h> |
| #include <linux/pinctrl/consumer.h> |
| #include <linux/amlogic/iomap.h> |
| #include <linux/amlogic/cpu_version.h> |
| #include <linux/amlogic/media/old_cpu_version.h> |
| #include <linux/clk.h> |
| |
| #define CONFIG_ARCH_MESON8 |
| |
| static struct platform_device *cam_pdev; |
| static struct clk *cam_clk; |
| static unsigned int bt_path_count; |
| |
| static unsigned int camera0_pwdn_pin; |
| static unsigned int camera0_rst_pin; |
| static unsigned int camera1_pwdn_pin; |
| static unsigned int camera1_rst_pin; |
| |
| static struct aml_cam_info_s *temp_cam; |
| |
| static int aml_camera_read_buff(struct i2c_adapter *adapter, |
| unsigned short dev_addr, char *buf, |
| int addr_len, int data_len) |
| { |
| int i2c_flag = -1; |
| struct i2c_msg msgs[] = {{ |
| .addr = dev_addr, .flags = 0, |
| .len = addr_len, .buf = buf, |
| }, { |
| .addr = dev_addr, .flags = I2C_M_RD, |
| .len = data_len, .buf = buf, |
| } |
| }; |
| |
| i2c_flag = i2c_transfer(adapter, msgs, 2); |
| |
| return i2c_flag; |
| } |
| |
| static int aml_camera_write_buff(struct i2c_adapter *adapter, |
| unsigned short dev_addr, char *buf, int len) |
| { |
| struct i2c_msg msg[] = {{ |
| .addr = dev_addr, .flags = 0, /*I2C_M_TEN*/ |
| .len = len, .buf = buf, |
| } |
| }; |
| |
| if (i2c_transfer(adapter, msg, 1) < 0) |
| return -1; |
| else |
| return 0; |
| } |
| |
| static int aml_i2c_get_byte(struct i2c_adapter *adapter, |
| unsigned short dev_addr, unsigned short addr) |
| { |
| unsigned char buff[4]; |
| |
| buff[0] = (unsigned char)((addr >> 8) & 0xff); |
| buff[1] = (unsigned char)(addr & 0xff); |
| |
| if (aml_camera_read_buff(adapter, dev_addr, buff, 2, 1) < 0) |
| return -1; |
| return buff[0]; |
| } |
| |
| static int aml_i2c_put_byte(struct i2c_adapter *adapter, |
| unsigned short dev_addr, unsigned short addr, |
| unsigned char data) |
| { |
| unsigned char buff[4]; |
| |
| buff[0] = (unsigned char)((addr >> 8) & 0xff); |
| buff[1] = (unsigned char)(addr & 0xff); |
| buff[2] = data; |
| if (aml_camera_write_buff(adapter, dev_addr, buff, 3) < 0) |
| return -1; |
| return 0; |
| } |
| |
| static int aml_i2c_get_byte_add8(struct i2c_adapter *adapter, |
| unsigned short dev_addr, |
| unsigned short addr) |
| { |
| unsigned char buff[4]; |
| |
| buff[0] = (unsigned char)(addr & 0xff); |
| |
| if (aml_camera_read_buff(adapter, dev_addr, buff, 1, 1) < 0) |
| return -1; |
| return buff[0]; |
| } |
| |
| static int aml_i2c_put_byte_add8(struct i2c_adapter *adapter, |
| unsigned short dev_addr, |
| unsigned short addr, unsigned char data) |
| { |
| unsigned char buff[4]; |
| |
| buff[0] = (unsigned char)(addr & 0xff); |
| buff[1] = data; |
| if (aml_camera_write_buff(adapter, dev_addr, buff, 2) < 0) |
| return -1; |
| return 0; |
| } |
| |
| int aml_i2c_put_word(struct i2c_adapter *adapter, unsigned short dev_addr, |
| unsigned short addr, unsigned short data) |
| { |
| unsigned char buff[4]; |
| |
| buff[0] = (unsigned char)((addr >> 8) & 0xff); |
| buff[1] = (unsigned char)(addr & 0xff); |
| buff[2] = (unsigned char)((data >> 8) & 0xff); |
| buff[3] = (unsigned char)(data & 0xff); |
| if (aml_camera_write_buff(adapter, dev_addr, buff, 4) < 0) |
| return -1; |
| return 0; |
| } |
| |
| static int aml_i2c_get_word(struct i2c_adapter *adapter, |
| unsigned short dev_addr, unsigned short addr) |
| { |
| int ret; |
| unsigned char buff[4]; |
| |
| buff[0] = (unsigned char)((addr >> 8) & 0xff); |
| buff[1] = (unsigned char)(addr & 0xff); |
| if (aml_camera_read_buff(adapter, dev_addr, buff, 2, 2) < 0) |
| return -1; |
| ret = (buff[0] << 8) | (buff[1]); |
| return ret; |
| } |
| |
| static int aml_i2c_get_word_add8(struct i2c_adapter *adapter, |
| unsigned short dev_addr, |
| unsigned short addr) |
| { |
| int ret; |
| unsigned char buff[4]; |
| |
| buff[0] = (unsigned char)((addr >> 8) & 0xff); |
| buff[1] = (unsigned char)(addr & 0xff); |
| if (aml_camera_read_buff(adapter, dev_addr, buff, 2, 2) < 0) |
| return -1; |
| ret = buff[0] | (buff[1] << 8); |
| return ret; |
| } |
| |
| static int aml_i2c_put_word_add8(struct i2c_adapter *adapter, |
| unsigned short dev_addr, unsigned char addr, |
| unsigned short data) |
| { |
| unsigned char buff[4]; |
| |
| buff[0] = (unsigned char)(addr & 0xff); |
| buff[1] = (unsigned char)(data >> 8 & 0xff); |
| buff[2] = (unsigned char)(data & 0xff); |
| if (aml_camera_write_buff(adapter, dev_addr, buff, 3) < 0) |
| return -1; |
| return 0; |
| } |
| |
| |
| extern struct i2c_client * |
| i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info); |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC0307 |
| int gc0307_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg; |
| |
| reg = aml_i2c_get_byte_add8(adapter, 0x21, 0x00); |
| if (reg == 0x99) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC0308 |
| int gc0308_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg; |
| |
| reg = aml_i2c_get_byte_add8(adapter, 0x21, 0x00); |
| if (reg == 0x9b) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC0328 |
| int gc0328_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg; |
| |
| reg = aml_i2c_get_byte_add8(adapter, 0x21, 0xf0); |
| if (reg == 0x9d) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC0329 |
| int gc0329_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg; |
| |
| aml_i2c_put_byte_add8(adapter, 0x31, 0xfc, 0x16); /*select page 0*/ |
| reg = aml_i2c_get_byte_add8(adapter, 0x31, 0x00); |
| if (reg == 0xc0) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2015 |
| int gc2015_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte_add8(adapter, 0x30, 0x00); |
| reg[1] = aml_i2c_get_byte_add8(adapter, 0x30, 0x01); |
| if (reg[0] == 0x20 && reg[1] == 0x05) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HM2057 |
| int hm2057_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte(adapter, 0x24, 0x0001); |
| reg[1] = aml_i2c_get_byte(adapter, 0x24, 0x0002); |
| if (reg[0] == 0x20 && reg[1] == 0x56) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2035 |
| int gc2035_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte_add8(adapter, 0x3c, 0xf0); |
| reg[1] = aml_i2c_get_byte_add8(adapter, 0x3c, 0xf1); |
| if (reg[0] == 0x20 && reg[1] == 0x35) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2155 |
| int gc2155_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte_add8(adapter, 0x3c, 0xf0); |
| reg[1] = aml_i2c_get_byte_add8(adapter, 0x3c, 0xf1); |
| if (reg[0] == 0x21 && reg[1] == 0x55) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GT2005 |
| int gt2005_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte(adapter, 0x3c, 0x0000); |
| reg[1] = aml_i2c_get_byte(adapter, 0x3c, 0x0001); |
| if (reg[0] == 0x51 && reg[1] == 0x38) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV2659 |
| int ov2659_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte(adapter, 0x30, 0x300a); |
| reg[1] = aml_i2c_get_byte(adapter, 0x30, 0x300b); |
| if (reg[0] == 0x26 && reg[1] == 0x56) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV3640 |
| int ov3640_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte(adapter, 0x3c, 0x300a); |
| reg[1] = aml_i2c_get_byte(adapter, 0x3c, 0x300b); |
| if (reg[0] == 0x36 && reg[1] == 0x4c) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV3660 |
| int ov3660_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte(adapter, 0x3c, 0x300a); |
| reg[1] = aml_i2c_get_byte(adapter, 0x3c, 0x300b); |
| if (reg[0] == 0x36 && reg[1] == 0x60) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV5640 |
| int ov5640_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte(adapter, 0x3c, 0x300a); |
| reg[1] = aml_i2c_get_byte(adapter, 0x3c, 0x300b); |
| if (reg[0] == 0x56 && reg[1] == 0x40) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV5642 |
| int ov5642_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte(adapter, 0x3c, 0x300a); |
| reg[1] = aml_i2c_get_byte(adapter, 0x3c, 0x300b); |
| if (reg[0] == 0x56 && reg[1] == 0x42) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV7675 |
| int ov7675_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte_add8(adapter, 0x21, 0x0a); |
| reg[1] = aml_i2c_get_byte_add8(adapter, 0x21, 0x0b); |
| if (reg[0] == 0x76 && reg[1] == 0x73) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_SP0A19 |
| int sp0a19_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg; |
| |
| reg = aml_i2c_get_byte_add8(adapter, 0x21, 0x02); |
| if (reg == 0xa6) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_SP2518 |
| int sp2518_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg; |
| |
| reg = aml_i2c_get_byte_add8(adapter, 0x30, 0x02); |
| pr_info("sp2518 chip id reg = %x .\n", reg); |
| if (reg == 0x53) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_SP0838 |
| int sp0838_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg; |
| |
| reg = aml_i2c_get_byte_add8(adapter, 0x18, 0x02); |
| if (reg == 0x27) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HI253 |
| int hi253_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg; |
| |
| reg = aml_i2c_get_byte_add8(adapter, 0x20, 0x04); |
| if (reg == 0x92) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HM5065 |
| int hm5065_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte(adapter, 0x1F, 0x0000); |
| reg[1] = aml_i2c_get_byte(adapter, 0x1F, 0x0001); |
| if (reg[0] == 0x03 && reg[1] == 0x9e) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HM1375 |
| int hm1375_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte(adapter, 0x24, 0x0001); |
| reg[1] = aml_i2c_get_byte(adapter, 0x24, 0x0002); |
| pr_info("hm1375_v4l2_probe: device ID: 0x%x%x", reg[0], reg[1]); |
| if ((reg[0] == 0x13 || reg[0] == 0x03) && reg[1] == 0x75) |
| ret = 1; |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HI2056 |
| int hi2056_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte(adapter, 0x24, 0x0001); |
| reg[1] = aml_i2c_get_byte(adapter, 0x24, 0x0002); |
| pr_info("reg[0]=%x, reg[1]=%x\n", reg[0], reg[1]); |
| if (reg[0] == 0x20 && reg[1] == 0x56) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV5647 |
| int ov5647_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte(adapter, 0x36, 0x300a); |
| reg[1] = aml_i2c_get_byte(adapter, 0x36, 0x300b); |
| pr_info("reg[0]:%x,reg[1]:%x\n", reg[0], reg[1]); |
| if (reg[0] == 0x56 && reg[1] == 0x47) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_AR0543 |
| int ar0543_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0, reg_val; |
| |
| reg_val = aml_i2c_get_word(adapter, 0x36, 0x3000); |
| pr_info("reg:0x%x\n", reg_val); |
| if (reg_val == 0x4800) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_AR0833 |
| int ar0833_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0, reg_val; |
| |
| reg_val = aml_i2c_get_word(adapter, 0x36, 0x3000); |
| pr_info("reg:0x%x\n", reg_val); |
| if (reg_val == 0x4B03) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_SP1628 |
| int sp1628_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte_add8(adapter, 0x3c, 0x02); |
| reg[1] = aml_i2c_get_byte_add8(adapter, 0x3c, 0xa0); |
| if (reg[0] == 0x16 && reg[1] == 0x28) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_BF3720 |
| int bf3720_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte_add8(adapter, 0x6e, 0xfc); |
| reg[1] = aml_i2c_get_byte_add8(adapter, 0x6e, 0xfd); |
| if (reg[0] == 0x37 && reg[1] == 0x20) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_BF3703 |
| int __init bf3703_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte_add8(adapter, 0x6e, 0xfc); /*i2c addr:0x6f*/ |
| reg[1] = aml_i2c_get_byte_add8(adapter, 0x6e, 0xfd); |
| if (reg[0] == 0x37 && reg[1] == 0x03) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_BF3920 |
| int __init bf3920_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte_add8(adapter, 0x6e, 0xfc); /*i2c addr:0x6f*/ |
| reg[1] = aml_i2c_get_byte_add8(adapter, 0x6e, 0xfd); |
| if (reg[0] == 0x39 && reg[1] == 0x20) |
| ret = 1; |
| return ret; |
| } |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2145 |
| int __init gc2145_v4l2_probe(struct i2c_adapter *adapter) |
| { |
| int ret = 0; |
| unsigned char reg[2]; |
| |
| reg[0] = aml_i2c_get_byte_add8(adapter, 0x3c, 0xf0); |
| reg[1] = aml_i2c_get_byte_add8(adapter, 0x3c, 0xf1); |
| /*datasheet chip id is error*/ |
| if (reg[0] == 0x21 && reg[1] == 0x45) |
| ret = 1; |
| pr_info("%s, ret = %d\n", __func__, ret); |
| return ret; |
| } |
| #endif |
| |
| struct aml_cam_dev_info_s { |
| unsigned char addr; |
| char *name; |
| unsigned char pwdn; |
| enum resolution_size max_cap_size; |
| aml_cam_probe_fun_t probe_func; |
| }; |
| |
| static const struct aml_cam_dev_info_s cam_devs[] = { |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC0307 |
| { |
| .addr = 0x21, |
| .name = "gc0307", |
| .pwdn = 1, |
| .max_cap_size = SIZE_640X480, |
| .probe_func = gc0307_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC0308 |
| { |
| .addr = 0x21, |
| .name = "gc0308", |
| .pwdn = 1, |
| .max_cap_size = SIZE_640X480, |
| .probe_func = gc0308_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC0328 |
| { |
| .addr = 0x21, |
| .name = "gc0328", |
| .pwdn = 1, |
| .max_cap_size = SIZE_640X480, |
| .probe_func = gc0328_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC0329 |
| { |
| .addr = 0x31, |
| .name = "gc0329", |
| .pwdn = 1, |
| .max_cap_size = SIZE_640X480, |
| .probe_func = gc0329_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2015 |
| { |
| .addr = 0x30, |
| .name = "gc2015", |
| .pwdn = 1, |
| .max_cap_size = SIZE_1600X1200, |
| .probe_func = gc2015_v4l2_probe, |
| }, |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HM2057 |
| { |
| .addr = 0x24, |
| .name = "hm2057", |
| .pwdn = 1, |
| .max_cap_size = SIZE_1600X1200, |
| .probe_func = hm2057_v4l2_probe, |
| }, |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2035 |
| { |
| .addr = 0x3c, |
| .name = "gc2035", |
| .pwdn = 1, |
| .max_cap_size = SIZE_1600X1200, |
| .probe_func = gc2035_v4l2_probe, |
| }, |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2155 |
| { |
| .addr = 0x3c, |
| .name = "gc2155", |
| .pwdn = 1, |
| .max_cap_size = SIZE_1600X1200, |
| .probe_func = gc2155_v4l2_probe, |
| }, |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GT2005 |
| { |
| .addr = 0x3c, |
| .name = "gt2005", |
| .pwdn = 0, |
| .max_cap_size = SIZE_1600X1200, |
| .probe_func = gt2005_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV2659 |
| { |
| .addr = 0x30, |
| .name = "ov2659", |
| .pwdn = 1, |
| .max_cap_size = SIZE_1600X1200, |
| .probe_func = ov2659_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV3640 |
| { |
| .addr = 0x3c, |
| .name = "ov3640", |
| .pwdn = 1, |
| .max_cap_size = SIZE_2048X1536; |
| .probe_func = ov3640_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV3660 |
| { |
| .addr = 0x3c, |
| .name = "ov3660", |
| .pwdn = 1, |
| .max_cap_size = SIZE_2048X1536, |
| .probe_func = ov3660_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV5640 |
| { |
| .addr = 0x3c, |
| .name = "ov5640", |
| .pwdn = 1, |
| .max_cap_size = SIZE_2592X1944, |
| .probe_func = ov5640_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV5642 |
| { |
| .addr = 0x3c, |
| .name = "ov5642", |
| .pwdn = 1, |
| .max_cap_size = SIZE_2592X1944, |
| .probe_func = ov5642_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV5647 |
| { |
| .addr = 0x36, /* really value should be 0x6c */ |
| .name = "ov5647", .pwdn = 1, .max_cap_size = SIZE_2592X1944, |
| .probe_func = ov5647_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV7675 |
| { |
| .addr = 0x21, |
| .name = "ov7675", |
| .pwdn = 1, |
| .max_cap_size = SIZE_640X480, |
| .probe_func = ov7675_v4l2_probe, |
| }, |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_SP0A19 |
| { |
| .addr = 0x21, |
| .name = "sp0a19", |
| .pwdn = 1, |
| .max_cap_size = SIZE_640X480, |
| .probe_func = sp0a19_v4l2_probe, |
| }, |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_SP0838 |
| { |
| .addr = 0x18, |
| .name = "sp0838", |
| .pwdn = 1, |
| .max_cap_size = SIZE_640X480, |
| .probe_func = sp0838_v4l2_probe, |
| }, |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_SP2518 |
| { |
| .addr = 0x30, |
| .name = "sp2518", |
| .pwdn = 1, |
| .max_cap_size = SIZE_1600X1200, |
| .probe_func = sp2518_v4l2_probe, |
| }, |
| #endif |
| |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HI253 |
| { |
| .addr = 0x20, |
| .name = "hi253", |
| .pwdn = 1, |
| .max_cap_size = SIZE_1600X1200, |
| .probe_func = hi253_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HM5065 |
| { |
| .addr = 0x1f, |
| .name = "hm5065", |
| .pwdn = 0, |
| .max_cap_size = SIZE_2592X1944, |
| .probe_func = hm5065_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HM1375 |
| { |
| .addr = 0x24, |
| .name = "hm1375", |
| .pwdn = 1, |
| .max_cap_size = SIZE_1280X1024, |
| .probe_func = hm1375_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HI2056 |
| { |
| .addr = 0x24, |
| .name = "mipi-hi2056", |
| .pwdn = 1, |
| .max_cap_size = SIZE_1600X1200, |
| .probe_func = hi2056_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_AR0543 |
| { |
| .addr = 0x36, |
| .name = "ar0543", |
| .pwdn = 0, |
| .max_cap_size = SIZE_2592X1944, |
| .probe_func = ar0543_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_AR0833 |
| { |
| .addr = 0x36, |
| .name = "ar0833", |
| .pwdn = 0, |
| .max_cap_size = SIZE_2592X1944, |
| .probe_func = ar0833_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_SP1628 |
| { |
| .addr = 0x3c, |
| .name = "sp1628", |
| .pwdn = 1, |
| .max_cap_size = SIZE_1280X960, |
| .probe_func = sp1628_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_BF3720 |
| { |
| .addr = 0x6e, |
| .name = "bf3720", |
| .pwdn = 1, |
| .max_cap_size = SIZE_1600X1200, |
| .probe_func = bf3720_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_BF3703 |
| { |
| .addr = 0x6e, |
| .name = "bf3703", |
| .pwdn = 1, |
| .max_cap_size = SIZE_640X480, |
| .probe_func = bf3703_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_BF3920 |
| { |
| .addr = 0x6e, |
| .name = "bf3920", |
| .pwdn = 1, |
| .max_cap_size = SIZE_1600X1200, |
| .probe_func = bf3920_v4l2_probe, |
| }, |
| #endif |
| #ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2145 |
| { |
| .addr = 0x3c, |
| .name = "gc2145", |
| .pwdn = 1, |
| .max_cap_size = SIZE_1600X1200, |
| .probe_func = gc2145_v4l2_probe, |
| }, |
| #endif |
| }; |
| |
| static const struct aml_cam_dev_info_s *get_cam_info_by_name(const char *name) |
| { |
| int i; |
| |
| if (!name) |
| return NULL; |
| /*pr_info("cam_devs num is %d\n", ARRAY_SIZE(cam_devs));*/ |
| for (i = 0; i < ARRAY_SIZE(cam_devs); i++) { |
| if (!strcmp(name, cam_devs[i].name)) { |
| pr_info("camera dev %s found\n", cam_devs[i].name); |
| pr_info("camera i2c addr: 0x%x\n", cam_devs[i].addr); |
| return &cam_devs[i]; |
| } |
| } |
| return NULL; |
| } |
| |
| struct res_item { |
| enum resolution_size size; |
| char *name; |
| }; |
| |
| static const struct res_item res_item_array[] = { |
| {SIZE_320X240, "320X240"}, { |
| SIZE_640X480, "640X480" |
| }, {SIZE_720X405, "720X405"}, { |
| SIZE_800X600, "800X600" |
| }, {SIZE_960X540, "960X540"}, { |
| SIZE_1024X576, "1024X576" |
| }, {SIZE_960X720, "960X720"}, { |
| SIZE_1024X768, "1024X768" |
| }, {SIZE_1280X720, "1280X720"}, { |
| SIZE_1152X864, "1152X864" |
| }, {SIZE_1366X768, "1366X768"}, { |
| SIZE_1280X960, "1280X960" |
| }, {SIZE_1280X1024, "1280X1024"}, { |
| SIZE_1400X1050, "1400X1050" |
| }, {SIZE_1600X900, "1600X900"}, { |
| SIZE_1600X1200, "1600X1200" |
| }, {SIZE_1920X1080, "1920X1080"}, { |
| SIZE_1792X1344, "1792X1344" |
| }, {SIZE_2048X1152, "2048X1152"}, { |
| SIZE_2048X1536, "2048X1536" |
| }, {SIZE_2304X1728, "2304X1728"}, { |
| SIZE_2560X1440, "2560X1440" |
| }, {SIZE_2592X1944, "2592X1944"}, { |
| SIZE_3072X1728, "3072X1728" |
| }, {SIZE_2816X2112, "2816X2112"}, { |
| SIZE_3072X2304, "3072X2304" |
| }, {SIZE_3200X2400, "3200X2400"}, { |
| SIZE_3264X2448, "3264X2448" |
| }, {SIZE_3840X2160, "3840X2160"}, { |
| SIZE_3456X2592, "3456X2592" |
| }, {SIZE_3600X2700, "3600X2700"}, { |
| SIZE_4096X2304, "4096X2304" |
| }, {SIZE_3672X2754, "3672X2754"}, { |
| SIZE_3840X2880, "3840X2880" |
| }, {SIZE_4000X3000, "4000X3000"}, { |
| SIZE_4608X2592, "4608X2592" |
| }, {SIZE_4096X3072, "4096X3072"}, { |
| SIZE_4800X3200, "4800X3200" |
| }, {SIZE_5120X2880, "5120X2880"}, { |
| SIZE_5120X3840, "5120X3840" |
| }, {SIZE_6400X4800, "6400X480"}, |
| |
| }; |
| |
| static enum resolution_size get_res_size(const char *res_str) |
| { |
| enum resolution_size ret = SIZE_NULL; |
| const struct res_item *item; |
| int i; |
| |
| if (!res_str) |
| return SIZE_NULL; |
| for (i = 0; i < ARRAY_SIZE(res_item_array); i++) { |
| item = &res_item_array[i]; |
| if (!strcmp(item->name, res_str)) { |
| ret = item->size; |
| return ret; |
| } |
| } |
| |
| return ret; |
| } |
| |
| static inline void GXBB_cam_enable_clk(void) |
| { |
| struct clk *clk; |
| |
| clk = clk_get(&cam_pdev->dev, "clk_camera_24"); |
| if (IS_ERR(clk)) { |
| pr_info("cannot get camera m-clock\n"); |
| clk = NULL; |
| } else { |
| cam_clk = clk; |
| clk_prepare_enable(clk); |
| } |
| } |
| |
| static inline void GXBB_cam_disable_clk(int spread_spectrum) |
| { |
| if (cam_clk) { |
| clk_disable_unprepare(cam_clk); |
| clk_put(cam_clk); |
| } |
| } |
| |
| static inline void GX12_cam_enable_clk(void) |
| { |
| struct clk *clk; |
| unsigned long clk_rate; |
| |
| clk = devm_clk_get(&cam_pdev->dev, "g12a_24m"); |
| if (IS_ERR(clk)) { |
| pr_info("cannot get camera m-clock\n"); |
| clk = NULL; |
| } else { |
| cam_clk = clk; |
| clk_set_rate(clk, 24000000); |
| clk_prepare_enable(clk); |
| clk_rate = clk_get_rate(clk); |
| } |
| } |
| |
| static inline void GX12_cam_disable_clk(int spread_spectrum) |
| { |
| if (cam_clk) { |
| clk_disable_unprepare(cam_clk); |
| devm_clk_put(&cam_pdev->dev, cam_clk); |
| pr_info("Success disable mclk\n"); |
| } |
| } |
| |
| static inline void cam_enable_clk(int clk, int spread_spectrum) |
| { |
| pr_err("camera mclk enable failed, unsupport chip\n"); |
| } |
| |
| static inline void cam_disable_clk(int spread_spectrum) |
| { |
| pr_err("camera mclk disable failed, unsupport chip\n"); |
| } |
| |
| /*static struct platform_device *cam_pdev;*/ |
| |
| void aml_cam_init(struct aml_cam_info_s *cam_dev) |
| { |
| /*select XTAL as camera clock*/ |
| if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB) |
| GXBB_cam_enable_clk(); |
| else if ((get_cpu_type() == MESON_CPU_MAJOR_ID_G12A) || |
| (get_cpu_type() == MESON_CPU_MAJOR_ID_G12B)) |
| GX12_cam_enable_clk(); |
| else |
| cam_enable_clk(cam_dev->mclk, cam_dev->spread_spectrum); |
| |
| /*coding style need: msleep < 20ms can sleep for up to 20ms*/ |
| msleep(20); |
| /*set camera power enable*/ |
| if (!cam_dev->front_back) { |
| cam_dev->pwdn_pin = camera0_pwdn_pin; |
| cam_dev->rst_pin = camera0_rst_pin; |
| } else { |
| cam_dev->pwdn_pin = camera1_pwdn_pin; |
| cam_dev->rst_pin = camera1_rst_pin; |
| } |
| |
| gpio_direction_output(cam_dev->pwdn_pin, cam_dev->pwdn_act); |
| |
| msleep(20); |
| |
| gpio_direction_output(cam_dev->pwdn_pin, !(cam_dev->pwdn_act)); |
| |
| msleep(20); |
| |
| gpio_direction_output(cam_dev->rst_pin, 0); |
| |
| msleep(20); |
| |
| gpio_direction_output(cam_dev->rst_pin, 1); |
| |
| msleep(20); |
| |
| pr_info("aml_cams: %s init OK\n", cam_dev->name); |
| |
| } |
| |
| void aml_cam_uninit(struct aml_cam_info_s *cam_dev) |
| { |
| int ret; |
| |
| pr_info("aml_cams: %s uninit.\n", cam_dev->name); |
| /*set camera power disable*/ |
| /*coding style need: msleep < 20ms can sleep for up to 20ms*/ |
| /*msleep(20);*/ |
| |
| ret = gpio_direction_output(cam_dev->pwdn_pin, cam_dev->pwdn_act); |
| if (ret < 0) |
| pr_info("aml_cam_uninit pwdn_pin output pwdn_act failed\n"); |
| |
| msleep(20); |
| |
| ret = gpio_direction_output(cam_dev->rst_pin, 0); |
| if (ret < 0) |
| pr_info("aml_cam_uninit rst_pin output rst_pin failed\n"); |
| |
| msleep(20); |
| |
| if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB) |
| GXBB_cam_disable_clk(cam_dev->spread_spectrum); |
| else if ((get_cpu_type() == MESON_CPU_MAJOR_ID_G12A) || |
| (get_cpu_type() == MESON_CPU_MAJOR_ID_G12B)) |
| GX12_cam_disable_clk(cam_dev->spread_spectrum); |
| else |
| cam_disable_clk(cam_dev->spread_spectrum); |
| } |
| |
| void aml_cam_flash(struct aml_cam_info_s *cam_dev, int is_on) |
| { |
| int ret; |
| |
| if (cam_dev->flash_support) { |
| pr_info("aml_cams: %s flash %s.\n", |
| cam_dev->name, is_on ? "on" : "off"); |
| |
| ret = gpio_direction_output(cam_dev->flash_ctrl_pin, |
| cam_dev->flash_ctrl_level ? is_on : !is_on); |
| if (ret < 0) |
| pr_info("aml_cam_flash flash_ctrl_pin output failed\n"); |
| } |
| } |
| |
| void aml_cam_torch(struct aml_cam_info_s *cam_dev, int is_on) |
| { |
| int ret; |
| |
| if (cam_dev->torch_support) { |
| pr_info("aml_cams: %s torch %s.\n", |
| cam_dev->name, is_on ? "on" : "off"); |
| |
| ret = gpio_direction_output(cam_dev->torch_ctrl_pin, |
| cam_dev->torch_ctrl_level ? is_on : !is_on); |
| if (ret < 0) |
| pr_info("aml_cam_torch torch_ctrl_pin output failed\n"); |
| } |
| } |
| |
| static struct list_head cam_head = LIST_HEAD_INIT(cam_head); |
| |
| #define DEBUG_DUMP_CAM_INFO |
| |
| static int fill_csi_dev(struct device_node *p_node, |
| struct aml_cam_info_s *cam_dev) |
| { |
| const char *str; |
| int ret = 0; |
| |
| ret = of_property_read_string(p_node, "clk_channel", &str); |
| if (ret) { |
| pr_info("failed to read clock channel, \"a or b\"\n"); |
| cam_dev->clk_channel = CLK_CHANNEL_A; |
| } else { |
| pr_info("clock channel:clk %s\n", str); |
| if (strncmp("a", str, 1) == 0) |
| cam_dev->clk_channel = CLK_CHANNEL_A; |
| else |
| cam_dev->clk_channel = CLK_CHANNEL_B; |
| } |
| |
| return ret; |
| |
| } |
| static int fill_cam_dev(struct device_node *p_node, |
| struct aml_cam_info_s *cam_dev) |
| { |
| const char *str; |
| int ret = 0; |
| const struct aml_cam_dev_info_s *cam_info = NULL; |
| struct device_node *adapter_node = NULL; |
| struct i2c_adapter *adapter = NULL; |
| unsigned int mclk = 0; |
| unsigned int vcm_mode = 0; |
| |
| if (!p_node || !cam_dev) |
| return -1; |
| |
| ret = of_property_read_u32(p_node, "front_back", &cam_dev->front_back); |
| if (ret) { |
| pr_info("get camera name failed!\n"); |
| goto err_out; |
| } |
| |
| ret = of_property_read_string(p_node, "cam_name", &cam_dev->name); |
| if (ret) { |
| pr_info("get camera name failed!\n"); |
| goto err_out; |
| } |
| |
| cam_dev->pwdn_pin = of_get_named_gpio(p_node, "gpio_pwdn-gpios", 0); |
| if (cam_dev->pwdn_pin == 0) { |
| pr_info("%s: failed to map gpio_pwdn !\n", cam_dev->name); |
| goto err_out; |
| } |
| |
| ret = gpio_request(cam_dev->pwdn_pin, "camera"); |
| if (ret < 0) |
| pr_info("aml_cam_init pwdn_pin request failed\n"); |
| |
| if (!cam_dev->front_back) |
| camera0_pwdn_pin = cam_dev->pwdn_pin; |
| else |
| camera1_pwdn_pin = cam_dev->pwdn_pin; |
| |
| cam_dev->rst_pin = of_get_named_gpio(p_node, "gpio_rst-gpios", 0); |
| if (cam_dev->rst_pin == 0) { |
| pr_info("%s: failed to map gpio_rst !\n", cam_dev->name); |
| goto err_out; |
| } |
| ret = gpio_request(cam_dev->rst_pin, "camera"); |
| if (ret < 0) |
| pr_info("aml_cam_init rst_pin request failed\n"); |
| |
| if (!cam_dev->front_back) |
| camera0_rst_pin = cam_dev->rst_pin; |
| else |
| camera1_rst_pin = cam_dev->rst_pin; |
| |
| cam_info = get_cam_info_by_name(cam_dev->name); |
| if (cam_info == NULL) { |
| pr_info("camera %s is not support\n", cam_dev->name); |
| ret = -1; |
| goto err_out; |
| } |
| |
| of_property_read_u32(p_node, "spread_spectrum", |
| &cam_dev->spread_spectrum); |
| |
| ret = of_property_read_string(p_node, "bt_path", &str); |
| if (ret) { |
| pr_info("failed to read bt_path\n"); |
| cam_dev->bt_path = BT_PATH_GPIO; |
| } else { |
| pr_info("bt_path :%d\n", cam_dev->bt_path); |
| if (strncmp("csi", str, 3) == 0) |
| cam_dev->bt_path = BT_PATH_CSI2; |
| else if (strncmp("gpio_b", str, 6) == 0) |
| cam_dev->bt_path = BT_PATH_GPIO_B; |
| else |
| cam_dev->bt_path = BT_PATH_GPIO; |
| } |
| of_property_read_u32(p_node, "bt_path_count", &cam_dev->bt_path_count); |
| bt_path_count = cam_dev->bt_path_count; |
| |
| cam_dev->pwdn_act = cam_info->pwdn; |
| cam_dev->i2c_addr = cam_info->addr; |
| pr_info("camer addr: 0x%x\n", cam_dev->i2c_addr); |
| pr_info("camer i2c bus: %d\n", cam_dev->i2c_bus_num); |
| |
| adapter_node = of_parse_phandle(p_node, "camera-i2c-bus", 0); |
| if (adapter_node) { |
| adapter = of_find_i2c_adapter_by_node(adapter_node); |
| of_node_put(adapter_node); |
| if (adapter == NULL) { |
| pr_err("%s, failed parse camera-i2c-bus\n", |
| __func__); |
| return -1; |
| } |
| } |
| |
| if (adapter && cam_info->probe_func) { |
| aml_cam_init(cam_dev); |
| if (cam_info->probe_func(adapter) != 1) { |
| pr_info("camera %s not on board\n", cam_dev->name); |
| ret = -1; |
| aml_cam_uninit(cam_dev); |
| goto err_out; |
| } |
| aml_cam_uninit(cam_dev); |
| } else { |
| pr_err("can not do probe function\n"); |
| ret = -1; |
| goto err_out; |
| } |
| |
| of_property_read_u32(p_node, "mirror_flip", &cam_dev->m_flip); |
| of_property_read_u32(p_node, "vertical_flip", &cam_dev->v_flip); |
| of_property_read_u32(p_node, "vdin_path", &cam_dev->vdin_path); |
| |
| ret = of_property_read_string(p_node, "max_cap_size", &str); |
| if (ret) |
| pr_info("failed to read max_cap_size\n"); |
| else { |
| pr_info("max_cap_size :%s\n", str); |
| cam_dev->max_cap_size = get_res_size(str); |
| } |
| if (cam_dev->max_cap_size == SIZE_NULL) |
| cam_dev->max_cap_size = cam_info->max_cap_size; |
| |
| ret = of_property_read_u32(p_node, "mclk", &mclk); |
| if (ret) |
| cam_dev->mclk = 24000; |
| else |
| cam_dev->mclk = mclk; |
| |
| ret = of_property_read_u32(p_node, "vcm_mode", &vcm_mode); |
| if (ret) |
| cam_dev->vcm_mode = 0; |
| else |
| cam_dev->vcm_mode = vcm_mode; |
| pr_info("vcm mode is %d\n", cam_dev->vcm_mode); |
| |
| ret = of_property_read_u32(p_node, "flash_support", |
| &cam_dev->flash_support); |
| if (cam_dev->flash_support) { |
| of_property_read_u32(p_node, "flash_ctrl_level", |
| &cam_dev->flash_ctrl_level); |
| ret = of_property_read_string(p_node, "flash_ctrl_pin", &str); |
| if (ret) { |
| pr_info("%s: failed to get flash_ctrl_pin!\n", |
| cam_dev->name); |
| cam_dev->flash_support = 0; |
| } else { |
| cam_dev->flash_ctrl_pin = of_get_named_gpio(p_node, |
| "flash_ctrl_pin", 0); |
| if (cam_dev->flash_ctrl_pin == 0) { |
| pr_info("%s: failed to map flash_ctrl_pin !\n", |
| cam_dev->name); |
| cam_dev->flash_support = 0; |
| cam_dev->flash_ctrl_level = 0; |
| } |
| ret = gpio_request(cam_dev->flash_ctrl_pin, "camera"); |
| if (ret < 0) |
| pr_info("camera flash_ctrl_pin request failed\n"); |
| } |
| } |
| |
| ret = of_property_read_u32(p_node, "torch_support", |
| &cam_dev->torch_support); |
| if (cam_dev->torch_support) { |
| of_property_read_u32(p_node, "torch_ctrl_level", |
| &cam_dev->torch_ctrl_level); |
| ret = of_property_read_string(p_node, "torch_ctrl_pin", &str); |
| if (ret) { |
| pr_info("%s: failed to get torch_ctrl_pin!\n", |
| cam_dev->name); |
| cam_dev->torch_support = 0; |
| } else { |
| cam_dev->torch_ctrl_pin = of_get_named_gpio(p_node, |
| "torch_ctrl_level", 0); |
| ret = gpio_request(cam_dev->torch_ctrl_pin, "camera"); |
| if (ret < 0) |
| pr_info("camera torch_ctrl_pin request failed\n"); |
| } |
| } |
| |
| ret = of_property_read_string(p_node, "interface", &str); |
| if (ret) { |
| pr_info("failed to read camera interface \"mipi or dvp\"\n"); |
| cam_dev->interface = CAM_DVP; |
| } else { |
| pr_info("camera interface:%s\n", str); |
| if (strncmp("dvp", str, 1) == 0) |
| cam_dev->interface = CAM_DVP; |
| else |
| cam_dev->interface = CAM_MIPI; |
| } |
| if (cam_dev->interface == CAM_MIPI) { |
| ret = fill_csi_dev(p_node, cam_dev); |
| if (ret < 0) |
| goto err_out; |
| } |
| |
| ret = of_property_read_string(p_node, "bayer_fmt", &str); |
| if (ret) { |
| pr_info("failed to read camera bayer fmt\n"); |
| cam_dev->bayer_fmt = TVIN_GBRG; |
| } else { |
| pr_info("color format:%s\n", str); |
| if (strncmp("BGGR", str, 4) == 0) |
| cam_dev->bayer_fmt = TVIN_BGGR; |
| else if (strncmp("RGGB", str, 4) == 0) |
| cam_dev->bayer_fmt = TVIN_RGGB; |
| else if (strncmp("GBRG", str, 4) == 0) |
| cam_dev->bayer_fmt = TVIN_GBRG; |
| else if (strncmp("GRBG", str, 4) == 0) |
| cam_dev->bayer_fmt = TVIN_GRBG; |
| else |
| cam_dev->bayer_fmt = TVIN_GBRG; |
| } |
| |
| ret = of_property_read_string(p_node, "config_path", &cam_dev->config); |
| if (ret) |
| pr_info("failed to read config_file path\n"); |
| else |
| pr_info("config path :%s\n", cam_dev->config); |
| |
| #ifdef DEBUG_DUMP_CAM_INFO |
| pr_info("=======cam %s info=======\n" |
| "i2c_bus_num: %d\n" |
| "pwdn_act: %d\n" |
| "front_back: %d\n" |
| "m_flip: %d\n" |
| "v_flip: %d\n" |
| "i2c_addr: 0x%x\n" |
| "config path:%s\n" |
| "bt_path:%d\n", |
| cam_dev->name, cam_dev->i2c_bus_num, cam_dev->pwdn_act, |
| cam_dev->front_back, cam_dev->m_flip, cam_dev->v_flip, |
| cam_dev->i2c_addr, cam_dev->config, cam_dev->bt_path); |
| #endif /* DEBUG_DUMP_CAM_INFO */ |
| |
| ret = 0; |
| |
| err_out: |
| return ret; |
| } |
| |
| static int do_read_work(char argn, char **argv) |
| { |
| unsigned int dev_addr, reg_addr, data_len = 1, result; |
| unsigned int i2c_bus; |
| struct i2c_adapter *adapter; |
| |
| if (argn < 4) { |
| pr_err("args num error"); |
| return -1; |
| } |
| |
| if (!strncmp(argv[1], "i2c_bus_ao", 9)) |
| i2c_bus = 4; |
| else if (!strncmp(argv[1], "i2c_bus_0", 9)) |
| i2c_bus = 0; |
| else if (!strncmp(argv[1], "i2c_bus_1", 9)) |
| i2c_bus = 1; |
| else if (!strncmp(argv[1], "i2c_bus_2", 9)) |
| i2c_bus = 2; |
| else if (!strncmp(argv[1], "i2c_bus_3", 9)) |
| i2c_bus = 3; |
| else { |
| pr_err("bus name error!\n"); |
| return -1; |
| } |
| |
| adapter = i2c_get_adapter(i2c_bus); |
| |
| if (adapter == NULL) { |
| pr_info("no adapter!\n"); |
| return -1; |
| } |
| |
| dev_addr = kstrtol(argv[2], 16, NULL); |
| reg_addr = kstrtol(argv[3], 16, NULL); |
| if (argn == 5) { |
| pr_info("argv[4] is %s\n", argv[4]); |
| data_len = kstrtol(argv[4], 16, NULL); |
| } |
| |
| if (reg_addr > 256) { |
| if (data_len != 2) { |
| result = aml_i2c_get_byte(adapter, dev_addr, reg_addr); |
| pr_info("register [0x%04x]=0x%02x\n", reg_addr, result); |
| } else { |
| result = aml_i2c_get_word(adapter, dev_addr, reg_addr); |
| pr_info("register [0x%04x]=0x%04x\n", reg_addr, result); |
| } |
| } else { |
| if (data_len != 2) { |
| result = aml_i2c_get_byte_add8(adapter, |
| dev_addr, reg_addr); |
| pr_info("register [0x%02x]=0x%02x\n", reg_addr, result); |
| } else { |
| result = aml_i2c_get_word_add8(adapter, |
| dev_addr, reg_addr); |
| pr_info("register [0x%02x]=0x%04x\n", reg_addr, result); |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int do_write_work(char argn, char **argv) |
| { |
| unsigned int dev_addr, reg_addr, reg_val, data_len = 1, ret = 0; |
| unsigned int i2c_bus; |
| struct i2c_adapter *adapter; |
| |
| if (argn < 5) { |
| pr_err("args num error"); |
| return -1; |
| } |
| |
| if (!strncmp(argv[1], "i2c_bus_0", 9)) |
| i2c_bus = 0; |
| else if (!strncmp(argv[1], "i2c_bus_1", 9)) |
| i2c_bus = 1; |
| else if (!strncmp(argv[1], "i2c_bus_2", 9)) |
| i2c_bus = 2; |
| else if (!strncmp(argv[1], "i2c_bus_3", 9)) |
| i2c_bus = 3; |
| else if (!strncmp(argv[1], "i2c_bus_ao", 9)) |
| i2c_bus = 4; |
| else { |
| pr_err("bus name error!\n"); |
| return -1; |
| } |
| |
| adapter = i2c_get_adapter(i2c_bus); |
| |
| if (adapter == NULL) { |
| pr_info("no adapter!\n"); |
| return -1; |
| } |
| |
| dev_addr = kstrtol(argv[2], 16, NULL); |
| reg_addr = kstrtol(argv[3], 16, NULL); |
| reg_val = kstrtol(argv[4], 16, NULL); |
| if (argn == 6) |
| data_len = kstrtol(argv[5], 16, NULL); |
| if (reg_addr > 256) { |
| if (data_len != 2) { |
| if (aml_i2c_put_byte(adapter, dev_addr, |
| reg_addr, reg_val) < 0) { |
| pr_err("write error\n"); |
| ret = -1; |
| } else { |
| pr_info("write ok\n"); |
| ret = 0; |
| } |
| } else { |
| if (aml_i2c_put_word(adapter, dev_addr, |
| reg_addr, reg_val) < 0) { |
| pr_err("write error\n"); |
| ret = -1; |
| } else { |
| pr_info("write ok\n"); |
| ret = 0; |
| } |
| } |
| } else { |
| if (data_len != 2) { |
| if (aml_i2c_put_byte_add8(adapter, dev_addr, |
| reg_addr, reg_val) < 0) { |
| pr_err("write error\n"); |
| ret = -1; |
| } else { |
| pr_info("write ok\n"); |
| ret = 0; |
| } |
| } else { |
| if (aml_i2c_put_word_add8(adapter, dev_addr, |
| reg_addr, reg_val) < 0) { |
| pr_err("write error\n"); |
| ret = -1; |
| } else { |
| pr_info("write ok\n"); |
| ret = 0; |
| } |
| } |
| } |
| |
| return ret; |
| } |
| |
| static struct class *cam_clsp; |
| |
| static ssize_t show_help(struct class *class, struct class_attribute *attr, |
| char *buf) |
| { |
| ssize_t size = 0; |
| |
| pr_info( |
| "echo [read | write] i2c_bus_type device_address register_address [value] [data_len] > i2c_debug\n" |
| "i2c_bus_type are: i2c_bus_ao, i2c_bus_a, i2c_bus_b, i2c_bus_c, i2c_bus_d\n" |
| "e.g.: echo read i2c_bus_ao 0x3c 0x18 1\n" |
| " echo write i2c_bus_ao 0x3c 0x18 0x24 1\n"); |
| return size; |
| } |
| |
| static ssize_t store_i2c_debug(struct class *class, |
| struct class_attribute *attr, const char *buf, |
| size_t count) |
| { |
| int argn; |
| char *buf_work, *p, *para; |
| char cmd; |
| char *argv[6]; |
| |
| buf_work = kstrdup(buf, GFP_KERNEL); |
| p = buf_work; |
| |
| for (argn = 0; argn < 6; argn++) { |
| para = strsep(&p, " "); |
| if (para == NULL) |
| break; |
| argv[argn] = para; |
| pr_info("argv[%d] = %s\n", argn, para); |
| } |
| |
| if (argn < 4 || argn > 6) |
| goto end; |
| |
| cmd = argv[0][0]; |
| switch (cmd) { |
| case 'r': |
| case 'R': |
| do_read_work(argn, argv); |
| break; |
| case 'w': |
| case 'W': |
| do_write_work(argn, argv); |
| break; |
| } |
| return count; |
| end: |
| pr_err("error command!\n"); |
| kfree(buf_work); |
| return -EINVAL; |
| } |
| |
| static LIST_HEAD(info_head); |
| |
| static ssize_t cam_info_show(struct class *class, struct class_attribute *attr, |
| char *buf) |
| { |
| struct list_head *p; |
| struct aml_cam_info_s *cam_info = NULL; |
| int count = 0; |
| |
| if (!list_empty(&info_head)) { |
| count += sprintf(&buf[count], |
| "name\t\tversion\t\t\t\tface_dir\t" |
| "i2c_addr\n"); |
| list_for_each(p, &info_head) { |
| cam_info = list_entry(p, struct aml_cam_info_s, |
| info_entry); |
| } |
| } |
| return count; |
| } |
| |
| static struct class_attribute aml_cam_attrs[] = { |
| __ATTR(i2c_debug, 0644, show_help, store_i2c_debug), |
| __ATTR_RO(cam_info), __ATTR(help, 0644, show_help, NULL), |
| __ATTR_NULL, |
| }; |
| |
| int aml_cam_info_reg(struct aml_cam_info_s *cam_info) |
| { |
| int ret = -1; |
| |
| if (cam_info) { |
| list_add(&cam_info->info_entry, &info_head); |
| ret = 0; |
| } |
| return ret; |
| } |
| |
| int aml_cam_info_unreg(struct aml_cam_info_s *cam_info) |
| { |
| int ret = -1; |
| struct list_head *p, *n; |
| struct aml_cam_info_s *tmp_info = NULL; |
| |
| if (cam_info) { |
| list_for_each_safe(p, n, &info_head) { |
| tmp_info = list_entry(p, struct aml_cam_info_s, |
| info_entry); |
| if (tmp_info == cam_info) { |
| list_del(p); |
| return 0; |
| } |
| } |
| } |
| return ret; |
| } |
| |
| static int aml_cams_probe(struct platform_device *pdev) |
| { |
| struct device_node *cams_node = pdev->dev.of_node; |
| struct device_node *child; |
| struct i2c_board_info board_info; |
| struct i2c_adapter *adapter = NULL; |
| struct device_node *adapter_node = NULL; |
| struct timeval camera_start; |
| struct timeval camera_end; |
| int i; |
| unsigned long time_use = 0; |
| |
| temp_cam = kzalloc(sizeof(struct aml_cam_info_s), GFP_KERNEL); |
| if (!temp_cam) |
| return -ENOMEM; |
| |
| cam_pdev = pdev; |
| do_gettimeofday(&camera_start); |
| for_each_child_of_node(cams_node, child) { |
| |
| memset(temp_cam, 0, sizeof(struct aml_cam_info_s)); |
| |
| if (fill_cam_dev(child, temp_cam)) |
| continue; |
| |
| /*register exist camera*/ |
| memset(&board_info, 0, sizeof(board_info)); |
| strlcpy(board_info.type, temp_cam->name, I2C_NAME_SIZE); |
| |
| adapter_node = of_parse_phandle(child, "camera-i2c-bus", 0); |
| if (adapter_node) { |
| adapter = of_get_i2c_adapter_by_node(adapter_node); |
| of_node_put(adapter_node); |
| if (adapter == NULL) { |
| pr_err("%s, failed parse camera-i2c-bus\n", |
| __func__); |
| return -1; |
| } |
| } else { |
| pr_err("adapter node is NULL.\n"); |
| return -1; |
| } |
| board_info.addr = temp_cam->i2c_addr; |
| board_info.platform_data = temp_cam; |
| pr_info("new i2c device\n"); |
| /*i2c_new_existing_device(adapter, &board_info)*/ |
| i2c_new_device(adapter, &board_info); |
| } |
| do_gettimeofday(&camera_end); |
| time_use = (camera_end.tv_sec - camera_start.tv_sec) * 1000 + |
| (camera_end.tv_usec - camera_start.tv_usec) / 1000; |
| pr_info("camera probe cost time = %ldms\n", time_use); |
| |
| pr_info("aml probe finish\n"); |
| cam_clsp = class_create(THIS_MODULE, "aml_camera"); |
| for (i = 0; aml_cam_attrs[i].attr.name; i++) { |
| if (class_create_file(cam_clsp, &aml_cam_attrs[i]) < 0) |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| static int aml_cams_remove(struct platform_device *pdev) |
| { |
| if (camera0_pwdn_pin != 0) |
| gpio_free(camera0_pwdn_pin); |
| if (camera0_rst_pin != 0) |
| gpio_free(camera0_rst_pin); |
| if (camera1_pwdn_pin != 0) |
| gpio_free(camera1_pwdn_pin); |
| if (camera1_rst_pin != 0) |
| gpio_free(camera1_rst_pin); |
| |
| kfree(temp_cam); |
| temp_cam = NULL; |
| |
| return 0; |
| } |
| |
| static const struct of_device_id cams_prober_dt_match[] = {{ |
| .compatible = |
| "amlogic, cams_prober", |
| }, {}, |
| }; |
| |
| static struct platform_driver aml_cams_prober_driver = { |
| .probe = aml_cams_probe, .remove = aml_cams_remove, .driver = { |
| .name = |
| "aml_cams_prober", .owner = THIS_MODULE, .of_match_table = |
| cams_prober_dt_match, |
| }, |
| }; |
| |
| static int __init aml_cams_prober_init(void) |
| { |
| if (platform_driver_register(&aml_cams_prober_driver)) { |
| pr_err("aml_cams_probre_driver register failed\n"); |
| return -ENODEV; |
| } |
| |
| return 0; |
| } |
| |
| static void __exit aml_cams_prober_exit(void) |
| { |
| bt_path_count = 0; |
| platform_driver_unregister(&aml_cams_prober_driver); |
| } |
| |
| module_init(aml_cams_prober_init); |
| module_exit(aml_cams_prober_exit); |
| |
| MODULE_LICENSE("GPL v2"); |
| MODULE_DESCRIPTION("Amlogic Cameras prober driver"); |
| |