media: Hisilicon isp: add Hisilicon isp driver on Hikey970 board. support for yuv sensor ov5640 & D3 Camera board.
Signed-off-by: xwx495457 <xwx495457@notesmail.huawei.com>
This commit is contained in:
@@ -244,7 +244,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
|
||||
CONFIG_DEVTMPFS=y
|
||||
CONFIG_DEVTMPFS_MOUNT=y
|
||||
CONFIG_DMA_CMA=y
|
||||
# CONFIG_CMA_SIZE_MBYTES is not set
|
||||
CONFIG_CMA_SIZE_MBYTES=64
|
||||
CONFIG_MTD=y
|
||||
CONFIG_MTD_M25P80=y
|
||||
CONFIG_MTD_SPI_NOR=y
|
||||
@@ -442,9 +442,9 @@ CONFIG_REGULATOR_QCOM_SMD_RPM=y
|
||||
CONFIG_REGULATOR_QCOM_SPMI=y
|
||||
CONFIG_REGULATOR_S2MPS11=y
|
||||
CONFIG_MEDIA_SUPPORT=y
|
||||
# CONFIG_MEDIA_CAMERA_SUPPORT is not set
|
||||
# CONFIG_V4L_PLATFORM_DRIVERS is not set
|
||||
# CONFIG_VIDEO_HISI_ISP is not set
|
||||
CONFIG_MEDIA_CAMERA_SUPPORT=y
|
||||
CONFIG_V4L_PLATFORM_DRIVERS=y
|
||||
CONFIG_VIDEO_HISI_ISP=y
|
||||
CONFIG_DRM=y
|
||||
CONFIG_DRM_NOUVEAU=m
|
||||
CONFIG_DRM_TEGRA=m
|
||||
|
||||
@@ -33,6 +33,8 @@ source "drivers/media/platform/omap/Kconfig"
|
||||
|
||||
source "drivers/media/platform/blackfin/Kconfig"
|
||||
|
||||
source "drivers/media/platform/hisilicon/Kconfig"
|
||||
|
||||
config VIDEO_SH_VOU
|
||||
tristate "SuperH VOU video output driver"
|
||||
depends on MEDIA_CAMERA_SUPPORT
|
||||
|
||||
@@ -66,3 +66,5 @@ ccflags-y += -I$(srctree)/drivers/media/i2c
|
||||
obj-$(CONFIG_VIDEO_MEDIATEK_VPU) += mtk-vpu/
|
||||
|
||||
obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec/
|
||||
|
||||
obj-$(CONFIG_VIDEO_HISI_ISP) += hisilicon/
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# hisilicon isp device configuration.
|
||||
# Please keep this list sorted alphabetically
|
||||
|
||||
source "drivers/media/platform/hisilicon/isp/Kconfig"
|
||||
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# Makefile for hisilicon isp drivers.
|
||||
# Please keep this list sorted alphabetically
|
||||
|
||||
obj-$(CONFIG_VIDEO_HISI_ISP) += isp/
|
||||
@@ -0,0 +1,6 @@
|
||||
config VIDEO_HISI_ISP
|
||||
tristate "ISP Support for Hisilicon Kirin Platform"
|
||||
depends on V4L_PLATFORM_DRIVERS
|
||||
default n
|
||||
help
|
||||
ISP Support for Hisilicon Kirin Platform
|
||||
@@ -0,0 +1,20 @@
|
||||
# Makefile for hisi ISP driver
|
||||
|
||||
hisi_isp-objs := hisi_isp_core.o \
|
||||
hisi_isp_common.o \
|
||||
hisi_isp_csi.o \
|
||||
hisi_isp_sr.o \
|
||||
hisi_isp_cvdr.o \
|
||||
hisi_isp_isr.o \
|
||||
hisi_isp_i2c.o
|
||||
|
||||
hisi_ov5645-objs := ov5645.o
|
||||
|
||||
hisi_ov5640_main-objs := ov5640_main.o
|
||||
|
||||
hisi_ov5640_sub-objs := ov5640_sub.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_HISI_ISP) += hisi_isp.o
|
||||
obj-$(CONFIG_VEDIO_HISI_ISP) += hisi_ov5645.o
|
||||
obj-$(CONFIG_VIDEO_HISI_ISP) += hisi_ov5640_main.o
|
||||
obj-$(CONFIG_VIDEO_HISI_ISP) += hisi_ov5640_sub.o
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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 "hisi_isp_common.h"
|
||||
#include "hisi_isp_cvdr.h"
|
||||
#include "hisi_isp_sr.h"
|
||||
#include "hisi_isp_csi.h"
|
||||
#include "hisi_isp_isr.h"
|
||||
|
||||
int frame_num2Offset(struct isp_device *dev, int frame_num)
|
||||
{
|
||||
return (dev->frame_size * (frame_num % dev->frame_count));
|
||||
}
|
||||
|
||||
void isp_config_smmu_bypass(struct isp_device *dev)
|
||||
{
|
||||
REG_SET(dev->base + ISP_BASE_ADDR_SMMU, 0x1);
|
||||
}
|
||||
|
||||
int isp_ispss_reset_all(struct isp_device *dev)
|
||||
{
|
||||
char __iomem *base = dev->base;
|
||||
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x060, 0xFFFFFFFF);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x064, 0xFFFFFFFF);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x068, 0xFFFFFFFF);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x06C, 0xFFFFFFFF);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x070, 0xFFFFFFFF);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x074, 0xFFFFFFFF);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x078, 0xFFFFFFFF);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x374, 0x00000003);
|
||||
mdelay(1);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x060, 0x00000000);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x064, 0x00000000);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x068, 0x00000000);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x06C, 0x00000000);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x070, 0x00000000);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x074, 0x00000000);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x078, 0x00000000);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x374, 0x00000000);
|
||||
mdelay(1);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(isp_ispss_reset_all);
|
||||
|
||||
void isp_ispss_enable_clock(struct isp_device *dev)
|
||||
{
|
||||
char __iomem *base = dev->base;
|
||||
/* enable all clock of isp sub-modules */
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x010, 0xffffffff);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x014, 0xffffffff);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x018, 0xffffffff);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x01C, 0xffffffff);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x020, 0xffffffff);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x024, 0xffffffff);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x028, 0xffffffff);
|
||||
REG_SET(base + ISP_BASE_ADDR_ISPSS_CTRL + 0x364, 0x00000003);
|
||||
mdelay(1);
|
||||
}
|
||||
EXPORT_SYMBOL(isp_ispss_enable_clock);
|
||||
|
||||
int isp_start_streaming(struct isp_device *dev, int index)
|
||||
{
|
||||
int ret;
|
||||
struct isp_i2c_client_t *i2c_client = NULL;
|
||||
|
||||
dev->addr = dev->sensor[index].addr;
|
||||
dev->flag = dev->sensor[index].flag;
|
||||
dev->speed_cfg = dev->sensor[index].speed_cfg;
|
||||
dev->csi_index = dev->sensor[index].csi_index;
|
||||
dev->dt = dev->sensor[index].dt;
|
||||
dev->pf = dev->sensor[index].pf;
|
||||
dev->csi_lane = dev->sensor[index].csi_lane;
|
||||
dev->pwdn_gpio = dev->sensor[index].pwdn_gpio;
|
||||
dev->rst_gpio = dev->sensor[index].rst_gpio;
|
||||
|
||||
isp_ispss_enable_clock(dev);
|
||||
|
||||
mdelay(100);
|
||||
|
||||
isp_ispss_reset_all(dev);
|
||||
|
||||
mdelay(100);
|
||||
|
||||
dev->client = create_isp_i2c_client(dev);
|
||||
if (!dev->client)
|
||||
return -ENODEV;
|
||||
|
||||
i2c_client = dev->client;
|
||||
ret = i2c_client->ops->open(i2c_client);
|
||||
if (ret) {
|
||||
destroy_isp_i2c_client(i2c_client);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
isp_csi_enable(dev, dev->csi_lane, 0);
|
||||
|
||||
ret = dev->sensor[index].camera_sensor_power(i2c_client, 1);
|
||||
ret += dev->sensor[index].camera_sensor_set_fmt(i2c_client,
|
||||
dev->w, dev->h);
|
||||
ret += dev->sensor[index].camera_stream_on_off(i2c_client, 1);
|
||||
if (ret) {
|
||||
dev->sensor[index].camera_sensor_power(i2c_client, 0);
|
||||
destroy_isp_i2c_client(i2c_client);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
isp_clear_irq_state(dev);
|
||||
|
||||
enable_irq(dev->isp_irq_frproc0);
|
||||
enable_irq(dev->isp_irq_vic1);
|
||||
|
||||
isp_enable_irq(dev);
|
||||
|
||||
isp_cvdr_init(dev);
|
||||
isp_cvdr_config(dev, dev->hw_addr);
|
||||
|
||||
isp_config_smmu_bypass(dev);
|
||||
|
||||
isp_sr_config(dev);
|
||||
isp_sr_go(dev, (1 << (4*dev->csi_index)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isp_stop_streaming(struct isp_device *dev, int index)
|
||||
{
|
||||
struct isp_i2c_client_t *i2c_client = dev->client;
|
||||
|
||||
if (!i2c_client)
|
||||
return -ENODEV;
|
||||
|
||||
disable_irq(dev->isp_irq_frproc0);
|
||||
disable_irq(dev->isp_irq_vic1);
|
||||
|
||||
dev->sensor[index].camera_stream_on_off(i2c_client, 0);
|
||||
dev->sensor[index].camera_sensor_power(i2c_client, 0);
|
||||
i2c_client->ops->close(i2c_client);
|
||||
destroy_isp_i2c_client(i2c_client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef HISI_ISP_COMMON_DEF_H
|
||||
#define HISI_ISP_COMMON_DEF_H
|
||||
|
||||
#include "hisi_isp_core.h"
|
||||
#include "hisi_isp_i2c.h"
|
||||
|
||||
enum yuv_data_type_e {
|
||||
YUV_DT_420_8BITS = 0x18,
|
||||
YUV_DT_420_10BITS = 0x19,
|
||||
YUV_DT_LEGACY_420_8BITS = 0x1A,
|
||||
YUV_DT_420_8BITS_C = 0x1C,
|
||||
YUV_DT_420_10BITS_C = 0x1D,
|
||||
YUV_DT_422_8BITS = 0x1E,
|
||||
YUV_DT_422_10BITS = 0x1F,
|
||||
};
|
||||
|
||||
enum raw_data_type_e {
|
||||
RAW_DT_RAW6 = 0x28,
|
||||
RAW_DT_RAW7 = 0x29,
|
||||
RAW_DT_RAW8 = 0x2A,
|
||||
RAW_DT_RAW10 = 0x2B,
|
||||
RAW_DT_RAW12 = 0x2C,
|
||||
RAW_DT_RAW14 = 0x2D,
|
||||
};
|
||||
|
||||
int frame_num2Offset(struct isp_device *dev, int frame_num);
|
||||
int isp_ispss_reset_all(struct isp_device *dev);
|
||||
void isp_ispss_enable_clock(struct isp_device *dev);
|
||||
int isp_start_streaming(struct isp_device *dev, int index);
|
||||
int isp_stop_streaming(struct isp_device *dev, int index);
|
||||
|
||||
#endif /* HISI_ISP_COMMON_DEF_H */
|
||||
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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 "hisi_isp_core.h"
|
||||
#include "hisi_isp_isr.h"
|
||||
#include "hisi_isp_common.h"
|
||||
#include <linux/kthread.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <linux/dma-contiguous.h>
|
||||
|
||||
#define DOVDD_VOLTAGE_DIGITAL_IO 1800000
|
||||
|
||||
static int isp_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
unsigned long pfn;
|
||||
struct miscdevice *miscdev = file->private_data;
|
||||
struct isp_device *dev = container_of(miscdev, struct isp_device, dev);
|
||||
|
||||
ISP_ERR("enter\n");
|
||||
if (vma->vm_end - vma->vm_start > dev->pool_size) {
|
||||
ISP_ERR("over pool size\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pfn = __phys_to_pfn(dev->hw_addr);
|
||||
|
||||
return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff,
|
||||
vma->vm_end - vma->vm_start, vma->vm_page_prot);
|
||||
}
|
||||
|
||||
static int isp_stream_on(struct isp_device *dev, struct stream_info *info)
|
||||
{
|
||||
int total;
|
||||
|
||||
if (info->cam_id >= 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->sensor[info->cam_id].probe == false) {
|
||||
ISP_ERR("cam_id:%d is not support", info->cam_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev->w = info->w;
|
||||
dev->h = info->h;
|
||||
dev->frame_size = PAGE_ALIGN(info->w * info->h * 2);
|
||||
total = dev->pool_size / dev->frame_size;
|
||||
if (total < 3) {
|
||||
dev->streaming = false;
|
||||
ISP_ERR("pool is too small or frame size is too large");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev->frame_count = total;
|
||||
dev->isp_frame_num = 0;
|
||||
dev->hal_frame_num = 0;
|
||||
dev->streaming = true;
|
||||
dev->cur_frame_num = 0;
|
||||
|
||||
isp_start_streaming(dev, info->cam_id);
|
||||
|
||||
info->pool_size = dev->pool_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
isp_flush_frame_range(struct isp_device *dev, struct frame_info *info)
|
||||
{
|
||||
int page_num = 0;
|
||||
int num = 0;
|
||||
struct page *p;
|
||||
|
||||
page_num = dev->frame_size / PAGE_SIZE;
|
||||
if (dev->frame_size % PAGE_SIZE > 0)
|
||||
page_num++;
|
||||
|
||||
for (num = 0; num < page_num; num++) {
|
||||
p = phys_to_page(dev->hw_addr + info->offset + PAGE_SIZE * num);
|
||||
flush_dcache_page(p);
|
||||
}
|
||||
}
|
||||
|
||||
static int isp_frame_request(struct isp_device *dev, struct frame_info *info)
|
||||
{
|
||||
|
||||
ISP_ERR("frame request enter %d\n", info->frame_num);
|
||||
|
||||
if (info->frame_num != 0 && info->frame_num != dev->hal_frame_num + 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (info->frame_num >= dev->isp_frame_num) {
|
||||
ISP_ERR("wait for frame complete+++\n");
|
||||
wait_for_completion(&dev->frame_comp);
|
||||
ISP_ERR("frame complete---\n");
|
||||
}
|
||||
|
||||
info->offset = frame_num2Offset(dev, info->frame_num);
|
||||
|
||||
isp_flush_frame_range(dev, info);
|
||||
|
||||
dev->hal_frame_num = info->frame_num;
|
||||
ISP_ERR("frame request exit %d\n", info->frame_num);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isp_stream_off(struct isp_device *dev, struct stream_info *info)
|
||||
{
|
||||
if (info->cam_id >= 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->sensor[info->cam_id].probe == false)
|
||||
return -EINVAL;
|
||||
|
||||
isp_stop_streaming(dev, info->cam_id);
|
||||
|
||||
dev->streaming = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long isp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct miscdevice *miscdev = filp->private_data;
|
||||
struct isp_device *dev = container_of(miscdev, struct isp_device, dev);
|
||||
int ret;
|
||||
struct stream_info stream;
|
||||
struct frame_info frame;
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
switch (cmd) {
|
||||
case ISP_IOC_STREAM_ON:
|
||||
{
|
||||
if (dev->streaming == true)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&stream, (void __user *)arg,
|
||||
sizeof(stream))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
ret = isp_stream_on(dev, &stream);
|
||||
if (ret)
|
||||
return -EFAULT;
|
||||
if (copy_to_user((void __user *)arg,
|
||||
&stream, _IOC_SIZE(cmd))) {
|
||||
ISP_ERR("copy to user failed!\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ISP_IOC_FRAME_REQUEST:
|
||||
{
|
||||
if (dev->streaming == false)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&frame, (void __user *)arg,
|
||||
sizeof(frame))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ret = isp_frame_request(dev, &frame);
|
||||
if (ret)
|
||||
return -EFAULT;
|
||||
|
||||
if (copy_to_user((void __user *)arg,
|
||||
&frame, _IOC_SIZE(cmd))) {
|
||||
ISP_ERR("copy to user failed!\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ISP_IOC_STREAM_OFF:
|
||||
{
|
||||
if (dev->streaming == false)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&stream, (void __user *)arg,
|
||||
sizeof(stream))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
ret = isp_stream_off(dev, &stream);
|
||||
if (ret)
|
||||
return -EFAULT;
|
||||
if (copy_to_user((void __user *)arg,
|
||||
&stream, _IOC_SIZE(cmd))) {
|
||||
ISP_ERR("copy to user failed!\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ISP_ERR("unknown cmd!\n");
|
||||
return -ENOTTY;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isp_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct miscdevice *miscdev = file->private_data;
|
||||
struct isp_device *dev = container_of(miscdev, struct isp_device, dev);
|
||||
|
||||
dev->streaming = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isp_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations isp_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = isp_open,
|
||||
.release = isp_release,
|
||||
.unlocked_ioctl = isp_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = NULL,
|
||||
#endif
|
||||
.mmap = isp_mmap,
|
||||
};
|
||||
|
||||
static int isp_getdts(struct platform_device *pdev, struct isp_device *dev)
|
||||
{
|
||||
struct device *device = &pdev->dev;
|
||||
struct device_node *np = device->of_node;
|
||||
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
dev->isp_irq_vic1 = irq_of_parse_and_map(np, 0);
|
||||
if (!dev->isp_irq_vic1)
|
||||
return -ENXIO;
|
||||
|
||||
dev->isp_irq_frproc0 = irq_of_parse_and_map(np, 1);
|
||||
if (!dev->isp_irq_frproc0)
|
||||
return -ENXIO;
|
||||
|
||||
of_property_read_u32(np, "clock-rates",
|
||||
&dev->xclk_freq);
|
||||
|
||||
of_property_read_u32(np, "pool-size",
|
||||
&dev->pool_size);
|
||||
|
||||
ISP_INFO("clock rate %d, pool size 0x%x",
|
||||
dev->xclk_freq, dev->pool_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isp_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct isp_device *idev;
|
||||
struct device *device = &pdev->dev;
|
||||
struct device_node *np = device->of_node;
|
||||
|
||||
ISP_INFO("enter!\n");
|
||||
|
||||
idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL);
|
||||
if (!idev)
|
||||
return -ENOMEM;
|
||||
|
||||
if (isp_getdts(pdev, idev)) {
|
||||
ISP_ERR("failed to dts info.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
idev->base = of_iomap(np, 0);
|
||||
if (!idev->base) {
|
||||
ISP_ERR("failed to get base resource.\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, idev->isp_irq_vic1,
|
||||
isp_vic1_handler, 0, "isp-vic1", idev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, idev->isp_irq_frproc0,
|
||||
isp_frproc0_handler, 0, "isp-frproc0", idev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
disable_irq(idev->isp_irq_frproc0);
|
||||
disable_irq(idev->isp_irq_vic1);
|
||||
|
||||
idev->io_regulator = devm_regulator_get(&pdev->dev, "DOVDD");
|
||||
if (IS_ERR(idev->io_regulator)) {
|
||||
idev->io_regulator = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
regulator_set_voltage(idev->io_regulator,
|
||||
DOVDD_VOLTAGE_DIGITAL_IO,
|
||||
DOVDD_VOLTAGE_DIGITAL_IO);
|
||||
|
||||
idev->xclk = devm_clk_get(&pdev->dev, "clk_gate_isp_snclk0");
|
||||
if (IS_ERR(idev->xclk)) {
|
||||
ISP_ERR("could not get xclk\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
clk_set_rate(idev->xclk, idev->xclk_freq);
|
||||
|
||||
idev->xclk1 = devm_clk_get(&pdev->dev, "clk_gate_isp_snclk1");
|
||||
if (IS_ERR(idev->xclk1)) {
|
||||
ISP_ERR("could not get xclk1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
clk_set_rate(idev->xclk1, idev->xclk_freq);
|
||||
|
||||
idev->virt_addr = dma_alloc_coherent(device,
|
||||
idev->pool_size, &(idev->hw_addr), GFP_KERNEL);
|
||||
if (!idev->virt_addr) {
|
||||
ISP_ERR("dma_alloc_coherent (ISP) alloc err!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(idev->virt_addr, 0, idev->pool_size);
|
||||
|
||||
idev->dev.minor = MISC_DYNAMIC_MINOR;
|
||||
idev->dev.name = "isp";
|
||||
idev->dev.fops = &isp_fops;
|
||||
idev->dev.parent = NULL;
|
||||
ret = misc_register(&idev->dev);
|
||||
if (ret) {
|
||||
dma_free_coherent(device,
|
||||
idev->pool_size, idev->virt_addr, idev->hw_addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
init_completion(&idev->frame_comp);
|
||||
|
||||
platform_set_drvdata(pdev, idev);
|
||||
|
||||
ISP_INFO("exit!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isp_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *device = &pdev->dev;
|
||||
struct isp_device *idev = platform_get_drvdata(pdev);
|
||||
|
||||
if (!idev) {
|
||||
pr_err("%s: get drvdata failed\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
ISP_INFO("enter!\n");
|
||||
|
||||
dma_free_coherent(device,
|
||||
idev->pool_size, idev->virt_addr, idev->hw_addr);
|
||||
|
||||
misc_deregister(&idev->dev);
|
||||
|
||||
ISP_INFO("exit!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id hisi_isp_match_table[] = {
|
||||
{
|
||||
.compatible = COMP_HISI_ISP_NAME,
|
||||
.data = NULL,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, hisi_isp_match_table);
|
||||
|
||||
static struct platform_driver isp_driver = {
|
||||
.probe = isp_probe,
|
||||
.remove = isp_remove,
|
||||
.driver = {
|
||||
.name = DEV_NAME_ISP,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(hisi_isp_match_table),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init isp_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ISP_INFO("enter!\n");
|
||||
|
||||
ret = platform_driver_register(&isp_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ISP_INFO("exit!\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit isp_exit(void)
|
||||
{
|
||||
ISP_INFO("enter!\n");
|
||||
|
||||
platform_driver_unregister(&isp_driver);
|
||||
|
||||
ISP_INFO("exit!\n");
|
||||
}
|
||||
|
||||
module_init(isp_init);
|
||||
module_exit(isp_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Hisilicon Isp Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef HISI_ISP_CORE_DEF_H
|
||||
#define HISI_ISP_CORE_DEF_H
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include "hisi_isp_reg_offset.h"
|
||||
#include "hisi_isp_i2c.h"
|
||||
|
||||
#define COMP_HISI_ISP_NAME "hisilicon,hisi-isp"
|
||||
#define DEV_NAME_ISP "hisi_isp"
|
||||
|
||||
#define USED 0x01
|
||||
#define UNUSED 0x00
|
||||
|
||||
/* #define HISP_DEBUG */
|
||||
|
||||
#if defined(HISP_DEBUG)
|
||||
#define ISP_ERR(msg, ...) \
|
||||
pr_err("[ISP] %s: "msg, __func__, ## __VA_ARGS__)
|
||||
#define ISP_WARNING(msg, ...) \
|
||||
pr_warn("[ISP] %s: "msg, __func__, ## __VA_ARGS__)
|
||||
#define ISP_INFO(msg, ...) \
|
||||
pr_info("[ISP] %s: "msg, __func__, ## __VA_ARGS__)
|
||||
#define ISP_DEBUG(msg, ...) \
|
||||
pr_debug("[ISP] %s: "msg, __func__, ## __VA_ARGS__)
|
||||
#else
|
||||
#define ISP_ERR(msg, ...) \
|
||||
pr_err("[ISP] %s: "msg, __func__, ## __VA_ARGS__)
|
||||
#define ISP_WARNING(msg, ...) \
|
||||
pr_warn("[ISP] %s: "msg, __func__, ## __VA_ARGS__)
|
||||
#define ISP_INFO(msg, ...) \
|
||||
pr_info("[ISP] %s: "msg, __func__, ## __VA_ARGS__)
|
||||
#define ISP_DEBUG(msg, ...)
|
||||
#endif
|
||||
|
||||
#define REG_SET(addr, val) writel(val, addr)
|
||||
#define REG_GET(addr) readl(addr)
|
||||
|
||||
#define MASK0(name) ((1<<(name##_LEN))-1)
|
||||
#define MASK1(name) (((1<<(name##_LEN))-1) << (name##_OFFSET))
|
||||
|
||||
/* operation on the field of a variable */
|
||||
#define REG_GET_FIELD(reg, name) \
|
||||
(((reg) >> (name##_OFFSET)) & MASK0(name))
|
||||
|
||||
#define REG_SET_FIELD(reg, name, val) \
|
||||
(reg = ((reg) & ~MASK1(name)) | \
|
||||
(((val) & MASK0(name)) << (name##_OFFSET)))
|
||||
|
||||
struct stream_info {
|
||||
int cam_id;
|
||||
int w;
|
||||
int h;
|
||||
int format;
|
||||
int pool_size;
|
||||
};
|
||||
|
||||
struct frame_info {
|
||||
int cam_id;
|
||||
int frame_num;
|
||||
int offset;
|
||||
};
|
||||
|
||||
#define ISP_IOC_MAGIC 'I'
|
||||
|
||||
#define ISP_IOC_STREAM_ON _IOWR(ISP_IOC_MAGIC, 0, struct stream_info)
|
||||
|
||||
#define ISP_IOC_FRAME_REQUEST _IOWR(ISP_IOC_MAGIC, 1, struct frame_info)
|
||||
|
||||
#define ISP_IOC_STREAM_OFF _IOWR(ISP_IOC_MAGIC, 2, struct stream_info)
|
||||
|
||||
struct isp_device {
|
||||
struct miscdevice dev;
|
||||
char __iomem *base;
|
||||
char __iomem *base_gpio;
|
||||
uint32_t isp_irq_vic1;
|
||||
uint32_t isp_irq_frproc0;
|
||||
struct clk *xclk;
|
||||
struct clk *xclk1;
|
||||
int xclk_freq;
|
||||
struct regulator *io_regulator;
|
||||
|
||||
void *virt_addr;
|
||||
dma_addr_t hw_addr;
|
||||
unsigned int pool_size;
|
||||
size_t frame_size;
|
||||
size_t frame_count;
|
||||
size_t isp_frame_num;
|
||||
size_t hal_frame_num;
|
||||
size_t cur_frame_num;
|
||||
struct completion frame_comp;
|
||||
bool streaming;
|
||||
|
||||
unsigned short addr;
|
||||
unsigned int flag;
|
||||
unsigned int speed_cfg;
|
||||
|
||||
int csi_index;
|
||||
int dt;
|
||||
int pf;
|
||||
int w;
|
||||
int h;
|
||||
|
||||
int csi_lane;
|
||||
int pwdn_gpio;
|
||||
int rst_gpio;
|
||||
struct isp_i2c_client_t *client;
|
||||
struct sensor_info {
|
||||
unsigned short addr;
|
||||
unsigned int flag;
|
||||
unsigned int speed_cfg;
|
||||
|
||||
int csi_index;
|
||||
int dt;
|
||||
int pf;
|
||||
int csi_lane;
|
||||
|
||||
int pwdn_gpio;
|
||||
int rst_gpio;
|
||||
|
||||
int (*camera_sensor_power)(struct isp_i2c_client_t *, int);
|
||||
int (*camera_sensor_set_fmt)(struct isp_i2c_client_t *,
|
||||
unsigned int, unsigned int);
|
||||
int (*camera_stream_on_off)(struct isp_i2c_client_t *, int);
|
||||
bool probe;
|
||||
} sensor[2];
|
||||
};
|
||||
#endif /* HISI_ISP_CORE_DEF_H */
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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 "hisi_isp_csi.h"
|
||||
#include "hisi_isp_csi2if_reg_offset.h"
|
||||
|
||||
#define CSI2IF_PHY_STOPSTATEDATA_0_OFFSET 0
|
||||
#define CSI2IF_PHY_STOPSTATEDATA_0_LEN 1
|
||||
#define CSI2IF_PHY_STOPSTATECLK_OFFSET 16
|
||||
#define CSI2IF_PHY_STOPSTATECLK_LEN 1
|
||||
#define CSI2IF_PHY_RXCLKACTIVEHS_OFFSET 17
|
||||
#define CSI2IF_PHY_RXCLKACTIVEHS_LEN 1
|
||||
|
||||
#define CSI_INDEX_CNT (3)
|
||||
|
||||
#define CFG_CLK_ATTR (0x01)
|
||||
#define CFG_CLK_DETECT (0x0A)
|
||||
#define CFG_DESKEW_1 (0x0B)
|
||||
#define CFG_DESKEW_2 (0x0F)
|
||||
#define LANE0_SETTLE (0x30)
|
||||
#define LANE0_MISC (0x31)
|
||||
#define LANE0_ADDITION (0x32)
|
||||
#define LANE0_DESKEW_1 (0x3A)
|
||||
#define LANE0_DESKEW_2 (0x3B)
|
||||
#define LANE0_DESKEW_3 (0x3C)
|
||||
#define LANE1_SETTLE (0x40)
|
||||
#define LANE1_MISC (0x41)
|
||||
#define LANE1_ADDITION (0x42)
|
||||
#define LANE1_DESKEW_1 (0x4A)
|
||||
#define LANE1_DESKEW_2 (0x4B)
|
||||
#define LANE1_DESKEW_3 (0x4C)
|
||||
#define LANE2_SETTLE (0x50)
|
||||
#define LANE2_MISC (0x51)
|
||||
#define LANE2_ADDITION (0x52)
|
||||
#define LANE2_DESKEW_1 (0x5A)
|
||||
#define LANE2_DESKEW_2 (0x5B)
|
||||
#define LANE2_DESKEW_3 (0x5C)
|
||||
#define LANE3_SETTLE (0x60)
|
||||
#define LANE3_MISC (0x61)
|
||||
#define LANE3_ADDITION (0x62)
|
||||
#define LANE3_DESKEW_1 (0x6A)
|
||||
#define LANE3_DESKEW_2 (0x6B)
|
||||
#define LANE3_DESKEW_3 (0x6C)
|
||||
|
||||
#define TSTCODE_SETREG8(reg_base, addr, value) \
|
||||
do { \
|
||||
REG_SET((reg_base+CSI2IF_PHY_TEST_CTRL1_REG),\
|
||||
(1 << 16) | addr); \
|
||||
REG_SET((reg_base+CSI2IF_PHY_TEST_CTRL0_REG), 2); \
|
||||
REG_SET((reg_base+CSI2IF_PHY_TEST_CTRL0_REG), 0); \
|
||||
REG_SET((reg_base+CSI2IF_PHY_TEST_CTRL1_REG), value); \
|
||||
REG_SET((reg_base+CSI2IF_PHY_TEST_CTRL0_REG), 2); \
|
||||
REG_SET((reg_base+CSI2IF_PHY_TEST_CTRL0_REG), 0); \
|
||||
} while (0)
|
||||
|
||||
#define TSTCODE_GETREG8(reg_base, addr, value)\
|
||||
do { \
|
||||
REG_SET((reg_base+CSI2IF_PHY_TEST_CTRL1_REG),\
|
||||
(1 << 16) | addr); \
|
||||
REG_SET((reg_base+CSI2IF_PHY_TEST_CTRL0_REG), 2); \
|
||||
REG_SET((reg_base+CSI2IF_PHY_TEST_CTRL0_REG), 0); \
|
||||
(value) = \
|
||||
((REG_GET(reg_base+CSI2IF_PHY_TEST_CTRL1_REG) >> 8) &\
|
||||
(0x000000ff)); \
|
||||
} while (0)
|
||||
|
||||
static int csi2if_dphy_init(char __iomem *base, unsigned char settle_time)
|
||||
{
|
||||
unsigned char value = 0;
|
||||
|
||||
if (settle_time > 0) { /* configure settle time mannually */
|
||||
TSTCODE_SETREG8(base, LANE0_SETTLE, settle_time);
|
||||
TSTCODE_SETREG8(base, LANE1_SETTLE, settle_time);
|
||||
TSTCODE_SETREG8(base, LANE2_SETTLE, settle_time);
|
||||
TSTCODE_SETREG8(base, LANE3_SETTLE, settle_time);
|
||||
TSTCODE_SETREG8(base, CFG_CLK_DETECT, 0x01);
|
||||
} else { /* enable clock detect */
|
||||
TSTCODE_SETREG8(base, LANE0_SETTLE, 0x01);
|
||||
TSTCODE_SETREG8(base, LANE0_ADDITION, 0x05);
|
||||
TSTCODE_SETREG8(base, LANE1_SETTLE, 0x01);
|
||||
TSTCODE_SETREG8(base, LANE1_ADDITION, 0x05);
|
||||
TSTCODE_SETREG8(base, LANE2_SETTLE, 0x01);
|
||||
TSTCODE_SETREG8(base, LANE2_ADDITION, 0x05);
|
||||
TSTCODE_SETREG8(base, LANE3_SETTLE, 0x01);
|
||||
TSTCODE_SETREG8(base, LANE3_ADDITION, 0x05);
|
||||
}
|
||||
|
||||
/* setup time and hold time for dphy v1.2 */
|
||||
TSTCODE_SETREG8(base, LANE0_DESKEW_1, 0x0D);
|
||||
TSTCODE_SETREG8(base, LANE1_DESKEW_1, 0x0D);
|
||||
TSTCODE_SETREG8(base, LANE2_DESKEW_1, 0x0D);
|
||||
TSTCODE_SETREG8(base, LANE3_DESKEW_1, 0x0D);
|
||||
TSTCODE_SETREG8(base, LANE0_DESKEW_3, 0x03);
|
||||
TSTCODE_SETREG8(base, LANE1_DESKEW_3, 0x03);
|
||||
TSTCODE_SETREG8(base, LANE2_DESKEW_3, 0x03);
|
||||
TSTCODE_SETREG8(base, LANE3_DESKEW_3, 0x03);
|
||||
|
||||
TSTCODE_SETREG8(base, CFG_CLK_ATTR, 0x50);
|
||||
|
||||
TSTCODE_GETREG8(base, LANE0_SETTLE, value);
|
||||
ISP_DEBUG("### LANE0_SETTLE = %d", value);
|
||||
|
||||
TSTCODE_GETREG8(base, LANE1_SETTLE, value);
|
||||
ISP_DEBUG("### LANE1_SETTLE = %d", value);
|
||||
|
||||
TSTCODE_GETREG8(base, LANE2_SETTLE, value);
|
||||
ISP_DEBUG("### LANE2_SETTLE = %d", value);
|
||||
|
||||
TSTCODE_GETREG8(base, LANE3_SETTLE, value);
|
||||
ISP_DEBUG("### LANE3_SETTLE = %d", value);
|
||||
|
||||
TSTCODE_GETREG8(base, CFG_CLK_DETECT, value);
|
||||
ISP_DEBUG("### CFG_CLK_DETECT = 0x%x", value);
|
||||
|
||||
TSTCODE_GETREG8(base, CFG_CLK_ATTR, value);
|
||||
ISP_DEBUG("### CFG_CLK_ATTR = 0x%x", value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int csi2if_enable(char __iomem *base,
|
||||
unsigned char num_lanes,
|
||||
unsigned char settle_time)
|
||||
{
|
||||
unsigned int phy_rx;
|
||||
unsigned int phy_state;
|
||||
char __iomem *base_addr = base;
|
||||
|
||||
if (num_lanes > 4 || 0 == num_lanes) {
|
||||
ISP_ERR("number of lanes %d out of range!!\n", num_lanes);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* de-assert the shutdown signal*/
|
||||
REG_SET(base_addr + CSI2IF_PHY_SHUTDOWNZ_REG, 0);
|
||||
REG_SET(base_addr + CSI2IF_DPHY_RSTZ_REG, 0);
|
||||
REG_SET(base_addr + CSI2IF_CSI2_RESETN_REG, 0);
|
||||
|
||||
REG_SET(base_addr + CSI2IF_PHY_TEST_CTRL0_REG, 1);
|
||||
REG_SET(base_addr + CSI2IF_PHY_TEST_CTRL0_REG, 0);
|
||||
mdelay(1);
|
||||
|
||||
REG_SET(base_addr + CSI2IF_PHY_SHUTDOWNZ_REG, 1);
|
||||
REG_SET(base_addr + CSI2IF_N_LANES_REG, (num_lanes-1));
|
||||
|
||||
REG_SET(base_addr + CSI2IF_DPHY_RSTZ_REG, 1);
|
||||
REG_SET(base_addr + CSI2IF_CSI2_RESETN_REG, 1);
|
||||
|
||||
/* Configure HUAWEI D-PHY */
|
||||
if (csi2if_dphy_init(base_addr, settle_time) < 0)
|
||||
return -1;
|
||||
|
||||
/* confirm the D-PHY is in right state */
|
||||
phy_rx = REG_GET(base_addr + CSI2IF_PHY_RX_REG);
|
||||
phy_state = REG_GET(base_addr + CSI2IF_PHY_STOPSTATE_REG);
|
||||
|
||||
if ((REG_GET_FIELD(phy_state, CSI2IF_PHY_STOPSTATEDATA_0) == 0) &&
|
||||
(REG_GET_FIELD(phy_state, CSI2IF_PHY_STOPSTATECLK) == 0)) {
|
||||
|
||||
ISP_INFO("### not all data and clock lanes in stop state!\n");
|
||||
ISP_INFO("phy_rx = 0x%x, phy_state = %x\n", phy_rx, phy_state);
|
||||
}
|
||||
|
||||
if (REG_GET_FIELD(phy_state, CSI2IF_PHY_RXCLKACTIVEHS) == 0)
|
||||
ISP_INFO("### D-PHY is not receiving a clock!\n");
|
||||
|
||||
mdelay(1);
|
||||
|
||||
phy_rx = REG_GET(base_addr + CSI2IF_PHY_RX_REG);
|
||||
phy_state = REG_GET(base_addr + CSI2IF_PHY_STOPSTATE_REG);
|
||||
ISP_INFO("### D-PHY state: phy_rx = 0x%x, phy_state = 0x%x\n",
|
||||
phy_rx, phy_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int csi2if_disable(char __iomem *base)
|
||||
{
|
||||
REG_SET(base + CSI2IF_CSI2_RESETN_REG, 0);
|
||||
REG_SET(base + CSI2IF_PHY_SHUTDOWNZ_REG, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isp_csi_get_reg_offset(int csi_index)
|
||||
{
|
||||
switch (csi_index) {
|
||||
case 0:
|
||||
return ISP_BASE_ADDR_CSI2IF_A;
|
||||
case 1:
|
||||
return ISP_BASE_ADDR_CSI2IF_B;
|
||||
case 2:
|
||||
return ISP_BASE_ADDR_CSI2IF_C;
|
||||
default:
|
||||
ISP_ERR("csi_index=%d error\n", csi_index);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int isp_csi_enable(struct isp_device *dev,
|
||||
unsigned char num_lanes, unsigned char settle_time)
|
||||
{
|
||||
csi2if_enable(dev->base + isp_csi_get_reg_offset(dev->csi_index),
|
||||
num_lanes, settle_time);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isp_csi_disable(struct isp_device *dev)
|
||||
{
|
||||
csi2if_disable(dev->base + isp_csi_get_reg_offset(dev->csi_index));
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef HISI_ISP_CSI_DEF_H
|
||||
#define HISI_ISP_CSI_DEF_H
|
||||
|
||||
#include "hisi_isp_core.h"
|
||||
|
||||
int isp_csi_enable(struct isp_device *dev,
|
||||
unsigned char num_lanes, unsigned char settle_time);
|
||||
int isp_csi_disable(struct isp_device *dev);
|
||||
|
||||
#endif /* HISI_ISP_CSI_DEF_H */
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef __CSI2IF_REG_OFFSET_H__
|
||||
#define __CSI2IF_REG_OFFSET_H__
|
||||
|
||||
#define CSI2IF_VERSION_REG 0x0
|
||||
#define CSI2IF_N_LANES_REG 0x4
|
||||
#define CSI2IF_CSI2_RESETN_REG 0x8
|
||||
#define CSI2IF_INT_ST_MAIN_REG 0xC
|
||||
#define CSI2IF_DATA_IDS_1_REG 0x10
|
||||
#define CSI2IF_PHY_SHUTDOWNZ_REG 0x40
|
||||
#define CSI2IF_DPHY_RSTZ_REG 0x44
|
||||
#define CSI2IF_PHY_RX_REG 0x48
|
||||
#define CSI2IF_PHY_STOPSTATE_REG 0x4C
|
||||
#define CSI2IF_PHY_TEST_CTRL0_REG 0x50
|
||||
#define CSI2IF_PHY_TEST_CTRL1_REG 0x54
|
||||
#define CSI2IF_PHY_CAL_REG 0xCC
|
||||
#define CSI2IF_INT_ST_PHY_FATAL_REG 0xE0
|
||||
#define CSI2IF_INT_MSK_PHY_FATAL_REG 0xE4
|
||||
#define CSI2IF_INT_FORCE_PHY_FATAL_REG 0xE8
|
||||
#define CSI2IF_INT_ST_PKT_FATAL_REG 0xF0
|
||||
#define CSI2IF_INT_MSK_PKT_FATAL_REG 0xF4
|
||||
#define CSI2IF_INT_FORCE_PKT_FATAL_REG 0xF8
|
||||
#define CSI2IF_INT_ST_FRAME_FATAL_REG 0x100
|
||||
#define CSI2IF_INT_MSK_FRAME_FATAL_REG 0x104
|
||||
#define CSI2IF_INT_FORCE_FRAME_FATAL_REG 0x108
|
||||
#define CSI2IF_INT_ST_PHY_REG 0x110
|
||||
#define CSI2IF_INT_MSK_PHY_REG 0x114
|
||||
#define CSI2IF_INT_FORCE_PHY_REG 0x118
|
||||
#define CSI2IF_INT_ST_PKT_REG 0x120
|
||||
#define CSI2IF_INT_MSK_PKT_REG 0x124
|
||||
#define CSI2IF_INT_FORCE_PKT_REG 0x128
|
||||
#define CSI2IF_INT_ST_LINE_REG 0x130
|
||||
#define CSI2IF_INT_MSK_LINE_REG 0x134
|
||||
#define CSI2IF_INT_FORCE_LINE_REG 0x138
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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 "hisi_isp_cvdr.h"
|
||||
#include "hisi_isp_cvdr_reg_offset.h"
|
||||
#include "hisi_isp_cvdr_priv.h"
|
||||
|
||||
#define CVDR_VP_RD_NBR (22)
|
||||
#define CVDR_VP_WR_NBR (38)
|
||||
#define CVDR_NR_WR_NBR (4)
|
||||
#define CVDR_NR_RD_NBR (8)
|
||||
|
||||
#define ONE_REG_OFFSET (0x4)
|
||||
|
||||
#define VP_WR_REG_OFFSET (0x10)
|
||||
|
||||
#define ISP_CLK (480)
|
||||
#define DERATE (1.2)
|
||||
|
||||
#define CVDR_ALIGN_BYTES (16)
|
||||
|
||||
struct cvdr_smmu_cfg_t {
|
||||
unsigned char to_use;
|
||||
|
||||
unsigned int num;
|
||||
unsigned int smr_nscfg;
|
||||
};
|
||||
|
||||
struct cvdr_vp_wr_cfg_t {
|
||||
unsigned char to_use;
|
||||
unsigned char id;
|
||||
struct cvdr_wr_fmt_desc_t fmt;
|
||||
struct cvdr_bw_cfg_t bw;
|
||||
};
|
||||
|
||||
struct cvdr_rd_fmt_desc_t {
|
||||
unsigned int fs_addr;
|
||||
unsigned int last_page;
|
||||
enum cvdr_pix_fmt_e pix_fmt;
|
||||
unsigned char pix_expan;
|
||||
unsigned short allocated_du;
|
||||
unsigned short line_size;
|
||||
unsigned short hblank;
|
||||
unsigned short frame_size;
|
||||
unsigned short vblank;
|
||||
unsigned short line_stride;
|
||||
unsigned short line_wrap;
|
||||
};
|
||||
|
||||
struct cvdr_vp_rd_cfg_t {
|
||||
unsigned char to_use;
|
||||
unsigned char id;
|
||||
struct cvdr_rd_fmt_desc_t fmt;
|
||||
struct cvdr_bw_cfg_t bw;
|
||||
};
|
||||
|
||||
struct cvdr_nr_wr_cfg_t {
|
||||
unsigned char to_use;
|
||||
unsigned char nr_wr_stop_en_du_thr;
|
||||
unsigned char nr_wr_stop_en_flux_ctrl;
|
||||
unsigned char nr_wr_stop_en_pressure;
|
||||
unsigned char nr_wr_stop_ok;
|
||||
unsigned char nr_wr_stop;
|
||||
unsigned char en;
|
||||
struct cvdr_bw_cfg_t bw;
|
||||
};
|
||||
|
||||
struct cvdr_nr_rd_cfg_t {
|
||||
unsigned char to_use;
|
||||
unsigned short allocated_du;
|
||||
unsigned char nr_rd_stop_en_du_thr;
|
||||
unsigned char nr_rd_stop_en_flux_ctrl;
|
||||
unsigned char nr_rd_stop_en_pressure;
|
||||
unsigned char nr_rd_stop_ok;
|
||||
unsigned char nr_rd_stop;
|
||||
unsigned char en;
|
||||
struct cvdr_bw_cfg_t bw;
|
||||
};
|
||||
|
||||
struct cfg_tab_cvdr_t {
|
||||
struct cvdr_smmu_cfg_t smmu_nr_rd_cfg[CVDR_NR_RD_NBR];
|
||||
struct cvdr_smmu_cfg_t smmu_vp_wr_cfg[CVDR_VP_WR_NBR];
|
||||
struct cvdr_smmu_cfg_t smmu_vp_rd_cfg[CVDR_VP_RD_NBR];
|
||||
struct cvdr_vp_wr_cfg_t vp_wr_cfg[CVDR_VP_WR_NBR];
|
||||
struct cvdr_vp_rd_cfg_t vp_rd_cfg[CVDR_VP_RD_NBR];
|
||||
struct cvdr_nr_wr_cfg_t nr_wr_cfg[CVDR_NR_WR_NBR];
|
||||
struct cvdr_nr_rd_cfg_t nr_rd_cfg[CVDR_NR_RD_NBR];
|
||||
};
|
||||
|
||||
struct cvdr_opt_bw_t {
|
||||
unsigned int srt;
|
||||
unsigned int pclk;
|
||||
unsigned int throughput;
|
||||
};
|
||||
|
||||
enum cvdr_dev_e {
|
||||
CVDR_RT = 0,
|
||||
CVDR_SRT = 1,
|
||||
};
|
||||
|
||||
enum vp_rd_id_e {
|
||||
R3_1 = 0,
|
||||
R11_1 = 4,
|
||||
R12_1 = 5,
|
||||
R11_2 = 6,
|
||||
R12_2 = 7,
|
||||
R10_1 = 8,
|
||||
R10_2 = 9,
|
||||
R2_1 = 10,
|
||||
R8_1_1 = 11,
|
||||
R8_2_1 = 12,
|
||||
R8_1_2 = 13,
|
||||
R8_2_2 = 14,
|
||||
R13_1 = 15,
|
||||
R13_2 = 16,
|
||||
R5_1_4 = 19,
|
||||
R5_1_5 = 20,
|
||||
R5_1_6 = 21,
|
||||
};
|
||||
|
||||
static struct cvdr_opt_bw_t cvdr_vp_wr_bw[CVDR_VP_WR_NBR] = {
|
||||
[W12_1] = {CVDR_SRT, ISP_CLK, ISP_CLK},
|
||||
[W12_2] = {CVDR_SRT, ISP_CLK, ISP_CLK},
|
||||
[W6_1] = {CVDR_SRT, 480, (float)DERATE*480*2},
|
||||
[W6_2] = {CVDR_SRT, 480, (float)DERATE*480*2},
|
||||
[W5_1_1] = {CVDR_SRT, 480, (float)DERATE*480},
|
||||
[W5_1_2] = {CVDR_SRT, 480, (float)DERATE*480},
|
||||
[W4_1_1] = {CVDR_SRT, 480, (float)DERATE*480},
|
||||
[W4_1_2] = {CVDR_SRT, 480, (float)DERATE*480},
|
||||
[W4_2_1] = {CVDR_SRT, 480, (float)DERATE*480},
|
||||
[W4_2_2] = {CVDR_SRT, 480, (float)DERATE*480},
|
||||
[W7_1] = {CVDR_SRT, 480, (float)DERATE*480},
|
||||
[W13_1] = {CVDR_SRT, ISP_CLK, ISP_CLK},
|
||||
[W13_2] = {CVDR_SRT, ISP_CLK, ISP_CLK},
|
||||
[W1_1] = {CVDR_RT, 720, 720*2},
|
||||
[W1_2] = {CVDR_RT, 720, 720*2},
|
||||
[W14_1] = {CVDR_RT, 720, 720*2},
|
||||
[W14_2] = {CVDR_RT, 720, 720*2},
|
||||
[W11_1] = {CVDR_RT, 585, ISP_CLK},
|
||||
[W11_2] = {CVDR_RT, 585, ISP_CLK},
|
||||
[W2_3] = {CVDR_RT, 720, 720*2},
|
||||
[W2_4] = {CVDR_RT, 720, 720*2},
|
||||
[W2_5] = {CVDR_RT, 720, 720*2},
|
||||
[W8_1] = {CVDR_SRT, ISP_CLK, ISP_CLK},
|
||||
[W3_1] = {CVDR_RT, 480/4, 4*480/29},
|
||||
[W2_2] = {CVDR_RT, 720, 720*2},
|
||||
[W2_1] = {CVDR_RT, 720, 720*2},
|
||||
[W15_1] = {CVDR_RT, 585, 374},
|
||||
[W16_1] = {CVDR_RT, 585, 187},
|
||||
[W16_2] = {CVDR_RT, 585, 187},
|
||||
[W17_1] = {CVDR_RT, 585, ISP_CLK},
|
||||
[W17_2] = {CVDR_RT, 585, ISP_CLK},
|
||||
[W19_1] = {CVDR_RT, ISP_CLK, (float)DERATE*ISP_CLK*16/8},
|
||||
[W19_2] = {CVDR_RT, ISP_CLK, (float)DERATE*ISP_CLK*16/8},
|
||||
[W20_1] = {CVDR_RT, ISP_CLK, ISP_CLK},
|
||||
[W20_2] = {CVDR_RT, ISP_CLK, ISP_CLK},
|
||||
};
|
||||
|
||||
static struct cvdr_opt_bw_t cvdr_vp_rd_bw[CVDR_VP_RD_NBR] = {
|
||||
[R3_1] = {CVDR_SRT, ISP_CLK, ISP_CLK},
|
||||
[R11_1] = {CVDR_SRT, ISP_CLK, ISP_CLK},
|
||||
[R12_1] = {CVDR_SRT, ISP_CLK, ISP_CLK},
|
||||
[R11_2] = {CVDR_SRT, ISP_CLK, ISP_CLK},
|
||||
[R12_2] = {CVDR_SRT, ISP_CLK, ISP_CLK},
|
||||
[R10_1] = {CVDR_RT, ISP_CLK, ISP_CLK},
|
||||
[R10_2] = {CVDR_RT, ISP_CLK, ISP_CLK},
|
||||
[R2_1] = {CVDR_RT, ISP_CLK, ISP_CLK*2},
|
||||
[R8_1_1] = {CVDR_SRT, ISP_CLK, ISP_CLK*2*DERATE},
|
||||
[R8_2_1] = {CVDR_SRT, ISP_CLK, ISP_CLK*2*DERATE},
|
||||
[R8_1_2] = {CVDR_SRT, ISP_CLK, ISP_CLK*2*DERATE},
|
||||
[R8_2_2] = {CVDR_SRT, ISP_CLK, ISP_CLK*2*DERATE},
|
||||
[R13_1] = {CVDR_RT, ISP_CLK, ISP_CLK},
|
||||
[R13_2] = {CVDR_RT, ISP_CLK, ISP_CLK},
|
||||
[R5_1_4] = {CVDR_SRT, 240, (float)DERATE*2*240},
|
||||
[R5_1_5] = {CVDR_SRT, 240, (float)DERATE*1.5*240},
|
||||
[R5_1_6] = {CVDR_SRT, 240, (float)DERATE*1.5*240},
|
||||
};
|
||||
|
||||
#define CVDR_SRT_CVDR_CFG_REG 0x0
|
||||
#define CVDR_RT_CVDR_CFG_REG 0x0
|
||||
#define CVDR_SRT_VP_WR_IF_CFG_0_REG 0x28
|
||||
#define CVDR_SRT_VP_RD_IF_CFG_0_REG 0x514
|
||||
|
||||
int cvdr_set_vp_wr_ready(char __iomem *base,
|
||||
unsigned char port,
|
||||
struct cvdr_wr_fmt_desc_t *desc,
|
||||
struct cvdr_bw_cfg_t *bw)
|
||||
{
|
||||
union U_VP_WR_CFG tmp_cfg;
|
||||
union U_VP_WR_AXI_FS tmp_fs;
|
||||
union U_VP_WR_AXI_LINE tmp_line;
|
||||
union U_LIMITER_VP_WR tmp_limiter;
|
||||
char __iomem *reg_addr;
|
||||
|
||||
if (desc->fs_addr & 0xF) {
|
||||
ISP_ERR("failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp_cfg.u32 = 0;
|
||||
tmp_fs.u32 = 0;
|
||||
tmp_line.u32 = 0;
|
||||
tmp_limiter.u32 = 0;
|
||||
|
||||
if (!bw) {
|
||||
ISP_ERR("vdr_bw_cfg_t* bw NULL!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp_cfg.bits.vpwr_pixel_format = desc->pix_fmt;
|
||||
tmp_cfg.bits.vpwr_pixel_expansion = desc->pix_expan;
|
||||
tmp_cfg.bits.vpwr_last_page = desc->last_page;
|
||||
|
||||
tmp_fs.bits.vpwr_address_frame_start = desc->fs_addr >> 4;
|
||||
|
||||
tmp_line.bits.vpwr_line_stride = desc->line_stride;
|
||||
tmp_line.bits.vpwr_line_wrap = desc->line_wrap;
|
||||
|
||||
tmp_limiter.bits.vpwr_access_limiter_0 = bw->bw_limiter0;
|
||||
tmp_limiter.bits.vpwr_access_limiter_1 = bw->bw_limiter1;
|
||||
tmp_limiter.bits.vpwr_access_limiter_2 = bw->bw_limiter2;
|
||||
tmp_limiter.bits.vpwr_access_limiter_3 = bw->bw_limiter3;
|
||||
tmp_limiter.bits.vpwr_access_limiter_reload = bw->bw_limiter_reload;
|
||||
|
||||
switch (port) {
|
||||
/*VP_WR @CVDR_SRT&CMDLST TO CONFIG */
|
||||
case W4_1_1:
|
||||
case W4_1_2:
|
||||
case W4_2_1:
|
||||
case W4_2_2:
|
||||
case W5_1_1:
|
||||
case W5_1_2:
|
||||
case W19_1:
|
||||
case W19_2:
|
||||
case W6_1:
|
||||
case W6_2:
|
||||
case W7_1:
|
||||
case W3_1:
|
||||
ISP_ERR("not support yet\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
reg_addr = base + CVDR_CVDR_LIMITER_VP_WR_0_REG +
|
||||
ONE_REG_OFFSET * port;
|
||||
REG_SET(reg_addr, tmp_limiter.u32);
|
||||
reg_addr = base + CVDR_CVDR_VP_WR_CFG_0_REG +
|
||||
VP_WR_REG_OFFSET * port;
|
||||
REG_SET(reg_addr, tmp_cfg.u32);
|
||||
reg_addr = base + CVDR_CVDR_VP_WR_AXI_LINE_0_REG +
|
||||
VP_WR_REG_OFFSET * port;
|
||||
REG_SET(reg_addr, tmp_line.u32);
|
||||
reg_addr = base + CVDR_CVDR_VP_WR_AXI_FS_0_REG +
|
||||
VP_WR_REG_OFFSET * port;
|
||||
REG_SET(reg_addr, tmp_fs.u32);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isp_cvdr_config(struct isp_device *dev, dma_addr_t hw_addr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct cvdr_wr_fmt_desc_t cvdr_wr_fmt = {
|
||||
.fs_addr = hw_addr,
|
||||
.pix_fmt = dev->pf,
|
||||
.pix_expan = 0,
|
||||
.last_page = (dev->w * dev->h * 2 + hw_addr) >> 15,
|
||||
.line_stride = dev->w*2/CVDR_ALIGN_BYTES - 1,
|
||||
.line_wrap = 8000,
|
||||
};
|
||||
struct cvdr_bw_cfg_t cvdr_bw = {0xF, 0xF, 0xF, 0xF, 0xF};
|
||||
|
||||
ret = cvdr_set_vp_wr_ready(dev->base + ISP_BASE_ADDR_CVDR_RT,
|
||||
W2_4, &cvdr_wr_fmt, &cvdr_bw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int isp_cvdr_init(struct isp_device *dev)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int prefetch_bypass;
|
||||
char __iomem *base = dev->base;
|
||||
char __iomem *reg_addr;
|
||||
unsigned int reg_val;
|
||||
|
||||
prefetch_bypass = 1;
|
||||
|
||||
for (i = 0; i < CVDR_VP_WR_NBR; ++i) {
|
||||
reg_addr = ((cvdr_vp_wr_bw[i].srt == CVDR_SRT) ?
|
||||
(base + ISP_BASE_ADDR_CVDR_SRT) :
|
||||
(base + ISP_BASE_ADDR_CVDR_RT))
|
||||
+ CVDR_SRT_VP_WR_IF_CFG_0_REG + 0x10 * i;
|
||||
reg_val = REG_GET(reg_addr);
|
||||
reg_val = (reg_val & 0x7FFFFFFF) | (prefetch_bypass << 31);
|
||||
REG_SET(reg_addr, reg_val);
|
||||
}
|
||||
|
||||
for (i = 0; i < CVDR_VP_RD_NBR; ++i) {
|
||||
reg_addr = ((cvdr_vp_rd_bw[i].srt == CVDR_SRT) ?
|
||||
(base + ISP_BASE_ADDR_CVDR_SRT) :
|
||||
(base + ISP_BASE_ADDR_CVDR_RT))
|
||||
+ CVDR_SRT_VP_RD_IF_CFG_0_REG + 0x20 * i;
|
||||
reg_val = REG_GET(reg_addr);
|
||||
reg_val = (reg_val & 0x7FFFFFFF) | (prefetch_bypass << 31);
|
||||
REG_SET(reg_addr, reg_val);
|
||||
}
|
||||
|
||||
/* CVDR RT*/
|
||||
REG_SET(base + ISP_BASE_ADDR_CVDR_RT + CVDR_RT_CVDR_CFG_REG,
|
||||
(1 << 0)
|
||||
| (64 << 8)
|
||||
| (11 << 16)
|
||||
| (11 << 24)
|
||||
);
|
||||
|
||||
/* CVDR SRT*/
|
||||
REG_SET(base + ISP_BASE_ADDR_CVDR_SRT + CVDR_SRT_CVDR_CFG_REG,
|
||||
(1 << 0)
|
||||
| (34 << 8)
|
||||
| (19 << 16)
|
||||
| (11 << 24)
|
||||
);
|
||||
|
||||
REG_SET(base + 0x22000 + 0x00C, 0xf8765432);
|
||||
REG_SET(base + 0x22000 + 0x010, 0xf8122334);
|
||||
|
||||
REG_SET(base + 0x2E000 + 0x00C, 0xd0765432);
|
||||
REG_SET(base + 0x2E000 + 0x010, 0xd0122334);
|
||||
|
||||
REG_SET(base + SUB_CTRL_BASE_ADDR + 0x190, 0x00026e10);
|
||||
REG_SET(base + SUB_CTRL_BASE_ADDR + 0x194, 0x0000021f);
|
||||
|
||||
REG_SET(base + SUB_CTRL_BASE_ADDR + 0x198, 0x00027210);
|
||||
REG_SET(base + SUB_CTRL_BASE_ADDR + 0x19C, 0x0000024e);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef HISI_ISP_CVDR_DEF_H
|
||||
#define HISI_ISP_CVDR_DEF_H
|
||||
|
||||
#include "hisi_isp_core.h"
|
||||
|
||||
enum cvdr_pix_fmt_e {
|
||||
DF_1PF8 = 0x0,
|
||||
DF_1PF10 = 0x1,
|
||||
DF_1PF12 = 0x2,
|
||||
DF_1PF14 = 0x3,
|
||||
DF_2PF8 = 0x4,
|
||||
DF_2PF10 = 0x5,
|
||||
DF_2PF12 = 0x6,
|
||||
DF_2PF14 = 0x7,
|
||||
DF_3PF8 = 0x8,
|
||||
DF_3PF10 = 0x9,
|
||||
DF_3PF12 = 0xA,
|
||||
DF_3PF14 = 0xB,
|
||||
DF_D32 = 0xC,
|
||||
DF_D48 = 0xD,
|
||||
DF_D64 = 0xE,
|
||||
DF_FMT_INVALID,
|
||||
};
|
||||
|
||||
enum vp_wr_id_e {
|
||||
W12_1 = 0,
|
||||
W12_2 = 1,
|
||||
W6_1 = 2,
|
||||
W6_2 = 3,
|
||||
W5_1_1 = 4,
|
||||
W5_1_2 = 5,
|
||||
W4_1_1 = 8,
|
||||
W4_1_2 = 9,
|
||||
W4_2_1 = 10,
|
||||
W4_2_2 = 11,
|
||||
W7_1 = 12,
|
||||
W13_1 = 14,
|
||||
W13_2 = 15,
|
||||
W1_1 = 16,
|
||||
W1_2 = 17,
|
||||
W14_1 = 18,
|
||||
W14_2 = 19,
|
||||
W11_1 = 20,
|
||||
W11_2 = 21,
|
||||
W2_3 = 22,
|
||||
W2_4 = 23,
|
||||
W2_5 = 24,
|
||||
W8_1 = 25,
|
||||
W3_1 = 26,
|
||||
W2_2 = 27,
|
||||
W2_1 = 28,
|
||||
W15_1 = 29,
|
||||
W16_1 = 30,
|
||||
W16_2 = 31,
|
||||
W17_1 = 32,
|
||||
W17_2 = 33,
|
||||
W19_1 = 34,
|
||||
W19_2 = 35,
|
||||
W20_1 = 36,
|
||||
W20_2 = 37,
|
||||
};
|
||||
|
||||
struct cvdr_wr_fmt_desc_t {
|
||||
unsigned int fs_addr;
|
||||
unsigned int last_page;
|
||||
|
||||
enum cvdr_pix_fmt_e pix_fmt;
|
||||
unsigned char pix_expan;
|
||||
unsigned short line_stride;
|
||||
unsigned short line_wrap;
|
||||
};
|
||||
|
||||
struct cvdr_bw_cfg_t {
|
||||
unsigned char bw_limiter0;
|
||||
unsigned char bw_limiter1;
|
||||
unsigned char bw_limiter2;
|
||||
unsigned char bw_limiter3;
|
||||
unsigned char bw_limiter_reload;
|
||||
};
|
||||
|
||||
int isp_cvdr_config(struct isp_device *dev, dma_addr_t hw_addr);
|
||||
int isp_cvdr_init(struct isp_device *dev);
|
||||
|
||||
#endif /* HISI_ISP_CVDR_DEF_H */
|
||||
@@ -0,0 +1,583 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef __CVDR_DRV_PRIV_H__
|
||||
#define __CVDR_DRV_PRIV_H__
|
||||
|
||||
/* Define the union U_CVDR_CFG */
|
||||
union U_CVDR_CFG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int axiwrite_du_threshold : 6; /* [5..0] */
|
||||
unsigned int reserved_0 : 2; /* [7..6] */
|
||||
unsigned int du_threshold_reached : 8; /* [15..8] */
|
||||
unsigned int max_axiread_id : 5; /* [20..16] */
|
||||
unsigned int reserved_1 : 3; /* [23..21] */
|
||||
unsigned int max_axiwrite_id : 5; /* [28..24] */
|
||||
unsigned int reserved_2 : 1; /* [29] */
|
||||
unsigned int force_rd_clk_on : 1; /* [30] */
|
||||
unsigned int force_wr_clk_on : 1; /* [31] */
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_CVDR_DEBUG_EN */
|
||||
union U_CVDR_DEBUG_EN {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int wr_peak_en : 1;
|
||||
unsigned int reserved_0 : 7;
|
||||
unsigned int rd_peak_en : 1;
|
||||
unsigned int reserved_1 : 23;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_CVDR_DEBUG */
|
||||
union U_CVDR_DEBUG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int wr_peak : 8;
|
||||
unsigned int rd_peak : 8;
|
||||
unsigned int reserved_0 : 16;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_CVDR_WR_QOS_CFG */
|
||||
union U_CVDR_WR_QOS_CFG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int wr_qos_threshold_01_stop : 4;
|
||||
unsigned int wr_qos_threshold_01_start : 4;
|
||||
unsigned int wr_qos_threshold_10_stop : 4;
|
||||
unsigned int wr_qos_threshold_10_start : 4;
|
||||
unsigned int wr_qos_threshold_11_stop : 4;
|
||||
unsigned int wr_qos_threshold_11_start : 4;
|
||||
unsigned int reserved_0 : 2;
|
||||
unsigned int wr_qos_min : 2;
|
||||
unsigned int wr_qos_max : 2;
|
||||
unsigned int wr_qos_sr : 2;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_CVDR_RD_QOS_CFG */
|
||||
union U_CVDR_RD_QOS_CFG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int rd_qos_threshold_01_stop : 4;
|
||||
unsigned int rd_qos_threshold_01_start : 4;
|
||||
unsigned int rd_qos_threshold_10_stop : 4;
|
||||
unsigned int rd_qos_threshold_10_start : 4;
|
||||
unsigned int rd_qos_threshold_11_stop : 4;
|
||||
unsigned int rd_qos_threshold_11_start : 4;
|
||||
unsigned int reserved_0 : 2;
|
||||
unsigned int rd_qos_min : 2;
|
||||
unsigned int rd_qos_max : 2;
|
||||
unsigned int rd_qos_sr : 2;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_OTHER_RO */
|
||||
union U_CVDR_OTHER_RO {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int other_ro : 32;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_OTHER_RW */
|
||||
union U_CVDR_OTHER_RW {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int other_rw : 32;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
|
||||
/* Define the union U_VP_WR_CFG */
|
||||
union U_VP_WR_CFG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int vpwr_pixel_format : 4;
|
||||
unsigned int vpwr_pixel_expansion : 1;
|
||||
unsigned int reserved_0 : 10;
|
||||
unsigned int vpwr_last_page : 17;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_VP_WR_AXI_FS */
|
||||
union U_VP_WR_AXI_FS {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int reserved_0 : 4;
|
||||
unsigned int vpwr_address_frame_start : 28;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_VP_WR_AXI_LINE */
|
||||
union U_VP_WR_AXI_LINE {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int vpwr_line_stride : 10;
|
||||
unsigned int reserved_0 : 5;
|
||||
unsigned int vpwr_line_wrap : 14;
|
||||
unsigned int reserved_1 : 3;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_CVDR_RT_VP_WR_IF_CFG */
|
||||
union U_VP_WR_IF_CFG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int reserved_0 : 16;
|
||||
unsigned int vp_wr_stop_enable_du_threshold_reached : 1;
|
||||
unsigned int vp_wr_stop_enable_flux_ctrl : 1;
|
||||
unsigned int vp_wr_stop_enable_pressure : 1;
|
||||
unsigned int reserved_1 : 5;
|
||||
unsigned int vp_wr_stop_ok : 1;
|
||||
unsigned int vp_wr_stop : 1;
|
||||
unsigned int reserved_2 : 5;
|
||||
unsigned int vpwr_prefetch_bypass : 1;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
|
||||
/* Define the union U_LIMITER_VP_WR */
|
||||
union U_LIMITER_VP_WR {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int vpwr_access_limiter_0 : 4;
|
||||
unsigned int vpwr_access_limiter_1 : 4;
|
||||
unsigned int vpwr_access_limiter_2 : 4;
|
||||
unsigned int vpwr_access_limiter_3 : 4;
|
||||
unsigned int reserved_0 : 8;
|
||||
unsigned int vpwr_access_limiter_reload : 4;
|
||||
unsigned int reserved_1 : 4;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_VP_RD_CFG */
|
||||
union U_VP_RD_CFG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int vprd_pixel_format : 4;
|
||||
unsigned int vprd_pixel_expansion : 1;
|
||||
unsigned int vprd_allocated_du : 5;
|
||||
unsigned int reserved_0 : 5;
|
||||
unsigned int vprd_last_page : 17;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
|
||||
};
|
||||
|
||||
/* Define the union U_VP_RD_LWG */
|
||||
union U_VP_RD_LWG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int vprd_line_size : 13;
|
||||
unsigned int reserved_0 : 3;
|
||||
unsigned int vprd_horizontal_blanking : 8;
|
||||
unsigned int reserved_1 : 8;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_VP_RD_FHG */
|
||||
union U_VP_RD_FHG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int vprd_frame_size : 13;
|
||||
unsigned int reserved_0 : 3;
|
||||
unsigned int vprd_vertical_blanking : 8;
|
||||
unsigned int reserved_1 : 8;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_VP_RD_AXI_FS */
|
||||
union U_VP_RD_AXI_FS {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int reserved_0 : 4;
|
||||
unsigned int vprd_axi_frame_start : 28;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_VP_RD_AXI_LINE */
|
||||
union U_VP_RD_AXI_LINE {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int vprd_line_stride : 10;
|
||||
unsigned int reserved_0 : 6;
|
||||
unsigned int vprd_line_wrap : 13;
|
||||
unsigned int reserved_1 : 3;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_VP_RD_IF_CFG */
|
||||
union U_VP_RD_IF_CFG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int reserved_0 : 16;
|
||||
unsigned int vp_rd_stop_enable_du_threshold_reached : 1;
|
||||
unsigned int vp_rd_stop_enable_flux_ctrl : 1;
|
||||
unsigned int vp_rd_stop_enable_pressure : 1;
|
||||
unsigned int reserved_1 : 5;
|
||||
unsigned int vp_rd_stop_ok : 1;
|
||||
unsigned int vp_rd_stop : 1;
|
||||
unsigned int reserved_2 : 5;
|
||||
unsigned int vprd_prefetch_bypass : 1;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_VP_RD_DEBUG */
|
||||
union U_VP_RD_DEBUG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int vp_rd_debug : 32;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_LIMITER_VP_RD */
|
||||
union U_LIMITER_VP_RD {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int vprd_access_limiter_0 : 4;
|
||||
unsigned int vprd_access_limiter_1 : 4;
|
||||
unsigned int vprd_access_limiter_2 : 4;
|
||||
unsigned int vprd_access_limiter_3 : 4;
|
||||
unsigned int reserved_0 : 8;
|
||||
unsigned int vprd_access_limiter_reload : 4;
|
||||
unsigned int reserved_1 : 4;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_NR_WR_CFG */
|
||||
union U_NR_WR_CFG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int reserved_0 : 16;
|
||||
unsigned int nr_wr_stop_enable_du_threshold_reached : 1;
|
||||
unsigned int nr_wr_stop_enable_flux_ctrl : 1;
|
||||
unsigned int nr_wr_stop_enable_pressure : 1;
|
||||
unsigned int reserved_1 : 5;
|
||||
unsigned int nr_wr_stop_ok : 1;
|
||||
unsigned int nr_wr_stop : 1;
|
||||
unsigned int reserved_2 : 5;
|
||||
unsigned int nrwr_enable : 1;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_NR_WR_DEBUG */
|
||||
union U_NR_WR_DEBUG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int nr_wr_debug : 32;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_LIMITER_NR_WR */
|
||||
union U_LIMITER_NR_WR {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int nrwr_access_limiter_0 : 4;
|
||||
unsigned int nrwr_access_limiter_1 : 4;
|
||||
unsigned int nrwr_access_limiter_2 : 4;
|
||||
unsigned int nrwr_access_limiter_3 : 4;
|
||||
unsigned int reserved_0 : 8;
|
||||
unsigned int nrwr_access_limiter_reload : 4;
|
||||
unsigned int reserved_1 : 4;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_NR_RD_CFG */
|
||||
union U_NR_RD_CFG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int reserved_0 : 5;
|
||||
unsigned int nrrd_allocated_du : 5;
|
||||
unsigned int reserved_1 : 6;
|
||||
unsigned int nr_rd_stop_enable_du_threshold_reached : 1;
|
||||
unsigned int nr_rd_stop_enable_flux_ctrl : 1;
|
||||
unsigned int nr_rd_stop_enable_pressure : 1;
|
||||
unsigned int reserved_2 : 5;
|
||||
unsigned int nr_rd_stop_ok : 1;
|
||||
unsigned int nr_rd_stop : 1;
|
||||
unsigned int reserved_3 : 5;
|
||||
unsigned int nrrd_enable : 1;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_NR_RD_DEBUG */
|
||||
union U_NR_RD_DEBUG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int nr_rd_debug : 32;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_LIMITER_NR_RD */
|
||||
union U_LIMITER_NR_RD {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int nrrd_access_limiter_0 : 4;
|
||||
unsigned int nrrd_access_limiter_1 : 4;
|
||||
unsigned int nrrd_access_limiter_2 : 4;
|
||||
unsigned int nrrd_access_limiter_3 : 4;
|
||||
unsigned int reserved_0 : 8;
|
||||
unsigned int nrrd_access_limiter_reload : 4;
|
||||
unsigned int reserved_1 : 4;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_DEBUG */
|
||||
union U_DEBUG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int debug : 32 ; /* [31..0] */
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_AXI_CFG_NR_WR */
|
||||
union U_AXI_CFG_NR_WR {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int nr_wr_mid : 6;
|
||||
unsigned int reserved_0 : 26;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
/* Define the union U_AXI_CFG_NR_RD */
|
||||
union U_AXI_CFG_NR_RD {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int nr_rd_mid : 6;
|
||||
unsigned int reserved_0 : 26;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
|
||||
};
|
||||
|
||||
/* Define the union U_AXI_CFG_VP_WR */
|
||||
union U_AXI_CFG_VP_WR {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int vp_wr_mid : 6;
|
||||
unsigned int reserved_0 : 26;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
|
||||
};
|
||||
|
||||
/* Define the union U_AXI_CFG_VP_RD */
|
||||
union U_AXI_CFG_VP_RD {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int vp_rd_mid : 6;
|
||||
unsigned int reserved_0 : 26;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
|
||||
};
|
||||
|
||||
/* Define the union U_SPARE */
|
||||
union U_SPARE {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int spare : 32;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
|
||||
};
|
||||
|
||||
/* Define the union U_VP_WR_SMOOTHING */
|
||||
union U_VP_WR_SMOOTHING {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int vpwr_smoothing_access_limiter_0 : 4;
|
||||
unsigned int vpwr_smoothing_access_limiter_1 : 4;
|
||||
unsigned int vpwr_smoothing_access_limiter_2 : 4;
|
||||
unsigned int vpwr_smoothing_access_limiter_3 : 4;
|
||||
unsigned int vpwr_smoothing_threshold : 7;
|
||||
unsigned int reserved_0 : 9;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
|
||||
};
|
||||
|
||||
/* Define the union U_VP_WR_DEBUG */
|
||||
union U_VP_WR_DEBUG {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int vp_wr_debug : 32;
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
|
||||
};
|
||||
|
||||
struct S_VP_WR {
|
||||
union U_VP_WR_CFG VP_WR_CFG;
|
||||
union U_VP_WR_AXI_FS VP_WR_AXI_FS;
|
||||
union U_VP_WR_AXI_LINE VP_WR_AXI_LINE;
|
||||
union U_VP_WR_IF_CFG VP_WR_IF_CFG;
|
||||
};
|
||||
|
||||
struct S_VP_RD {
|
||||
union U_VP_RD_CFG VP_RD_CFG;
|
||||
union U_VP_RD_LWG VP_RD_LWG;
|
||||
union U_VP_RD_FHG VP_RD_FHG;
|
||||
union U_VP_RD_AXI_FS VP_RD_AXI_FS;
|
||||
union U_VP_RD_AXI_LINE VP_RD_AXI_LINE;
|
||||
union U_VP_RD_IF_CFG VP_RD_IF_CFG;
|
||||
unsigned int VP_RD_DEBUG;
|
||||
};
|
||||
|
||||
struct S_NR_WR {
|
||||
union U_NR_WR_CFG NR_WR_CFG;
|
||||
union U_NR_WR_DEBUG NR_WR_DEBUG;
|
||||
union U_LIMITER_NR_WR LIMITER_NR_WR;
|
||||
unsigned int reserved_0;
|
||||
};
|
||||
|
||||
struct S_NR_RD {
|
||||
union U_NR_RD_CFG NR_RD_CFG;
|
||||
union U_NR_RD_DEBUG NR_RD_DEBUG;
|
||||
union U_LIMITER_NR_RD LIMITER_NR_RD;
|
||||
unsigned int reserved_0;
|
||||
};
|
||||
|
||||
/* Define the global struct */
|
||||
struct S_CVDR_REGS_TYPE {
|
||||
union U_CVDR_CFG CVDR_CFG ; /* 0x0 */
|
||||
union U_CVDR_DEBUG_EN CVDR_DEBUG_EN ; /* 0x4 */
|
||||
union U_CVDR_DEBUG CVDR_DEBUG ; /* 0x8 */
|
||||
union U_CVDR_WR_QOS_CFG CVDR_WR_QOS_CFG ; /* 0xc */
|
||||
union U_CVDR_RD_QOS_CFG CVDR_RD_QOS_CFG ; /* 0x10 */
|
||||
union U_CVDR_OTHER_RO CVDR_OTHER_RO ; /* 0x14 */
|
||||
union U_CVDR_OTHER_RW CVDR_OTHER_RW ; /* 0x18 */
|
||||
struct S_VP_WR VP_WR[38] ; /* 0x1c~0x278 */
|
||||
unsigned int reserved_0[73] ; /* 0x27c~0x39c */
|
||||
union U_LIMITER_VP_WR LIMITER_VP_WR[38] ; /* 0x400~0x494 */
|
||||
unsigned int reserved_1[2] ; /* 0x498~0x49c */
|
||||
struct S_VP_RD VP_RD[22] ; /* 0x500~0x7bc */
|
||||
unsigned int reserved_2[48] ; /* 0x7c0~0x87c */
|
||||
union U_LIMITER_VP_RD LIMITER_VP_RD[22] ; /* 0x880~0x8d4 */
|
||||
unsigned int reserved_3[10] ; /* 0x8d8~0x8fc */
|
||||
struct S_NR_WR NR_WR[4] ; /* 0x900~0x93c */
|
||||
unsigned int reserved_4[48] ; /* 0x940~0x9fc */
|
||||
struct S_NR_RD NR_RD[8] ; /* 0xa00~0xa7c */
|
||||
unsigned int reserved_5[32] ; /* 0xa80~0xafc */
|
||||
union U_DEBUG DEBUG[16] ; /* 0xb00~0xb3c */
|
||||
unsigned int reserved_6[48] ; /* 0xb40~0xbfc */
|
||||
union U_AXI_CFG_NR_WR AXI_CFG_NR_WR[4] ; /* 0xc00~0xc0c */
|
||||
unsigned int reserved_7[12] ; /* 0xc10~0xc3c */
|
||||
union U_AXI_CFG_NR_RD AXI_CFG_NR_RD[8] ; /* 0xc40~0xc5c */
|
||||
unsigned int reserved_8[8] ; /* 0xc60~0xc7c */
|
||||
union U_AXI_CFG_VP_WR AXI_CFG_VP_WR[38] ; /* 0xc80~0xd14 */
|
||||
unsigned int reserved_9[26] ; /* 0xd18~0xd7c */
|
||||
union U_AXI_CFG_VP_RD AXI_CFG_VP_RD[22] ; /* 0xd80~0xdd4 */
|
||||
unsigned int reserved_10[10] ; /* 0xdd8~0xdfc */
|
||||
union U_SPARE SPARE[4] ; /* 0xe00~0xe0c */
|
||||
union U_VP_WR_SMOOTHING VP_WR_SMOOTHING[20] ; /* 0xe10~0xe5c */
|
||||
unsigned int reserved_11[40] ; /* 0xe60~0xefc */
|
||||
union U_VP_WR_DEBUG VP_WR_DEBUG[38] ; /* 0xf00~0xf94 */
|
||||
};
|
||||
|
||||
#endif /* __CVDR_DRV_PRIV_H__ */
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef __CVDR_REG_OFFSET_H__
|
||||
#define __CVDR_REG_OFFSET_H__
|
||||
|
||||
#define CVDR_CVDR_CVDR_CFG_REG 0x0
|
||||
#define CVDR_CVDR_CVDR_DEBUG_EN_REG 0x4
|
||||
#define CVDR_CVDR_CVDR_DEBUG_REG 0x8
|
||||
#define CVDR_CVDR_CVDR_WR_QOS_CFG_REG 0xC
|
||||
#define CVDR_CVDR_CVDR_RD_QOS_CFG_REG 0x10
|
||||
#define CVDR_CVDR_OTHER_RO_REG 0x14
|
||||
#define CVDR_CVDR_OTHER_RW_REG 0x18
|
||||
#define CVDR_CVDR_VP_WR_CFG_0_REG 0x1C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_0_REG 0x20
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_0_REG 0x24
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_0_REG 0x28
|
||||
#define CVDR_CVDR_VP_WR_CFG_1_REG 0x2C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_1_REG 0x30
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_1_REG 0x34
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_1_REG 0x38
|
||||
#define CVDR_CVDR_VP_WR_CFG_2_REG 0x3C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_2_REG 0x40
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_2_REG 0x44
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_2_REG 0x48
|
||||
#define CVDR_CVDR_VP_WR_CFG_3_REG 0x4C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_3_REG 0x50
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_3_REG 0x54
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_3_REG 0x58
|
||||
#define CVDR_CVDR_VP_WR_CFG_4_REG 0x5C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_4_REG 0x60
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_4_REG 0x64
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_4_REG 0x68
|
||||
#define CVDR_CVDR_VP_WR_CFG_5_REG 0x6C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_5_REG 0x70
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_5_REG 0x74
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_5_REG 0x78
|
||||
#define CVDR_CVDR_VP_WR_CFG_8_REG 0x9C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_8_REG 0xA0
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_8_REG 0xA4
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_8_REG 0xA8
|
||||
#define CVDR_CVDR_VP_WR_CFG_9_REG 0xAC
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_9_REG 0xB0
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_9_REG 0xB4
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_9_REG 0xB8
|
||||
#define CVDR_CVDR_VP_WR_CFG_10_REG 0xBC
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_10_REG 0xC0
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_10_REG 0xC4
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_10_REG 0xC8
|
||||
#define CVDR_CVDR_VP_WR_CFG_11_REG 0xCC
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_11_REG 0xD0
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_11_REG 0xD4
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_11_REG 0xD8
|
||||
#define CVDR_CVDR_VP_WR_CFG_12_REG 0xDC
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_12_REG 0xE0
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_12_REG 0xE4
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_12_REG 0xE8
|
||||
#define CVDR_CVDR_VP_WR_CFG_14_REG 0xFC
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_14_REG 0x100
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_14_REG 0x104
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_14_REG 0x108
|
||||
#define CVDR_CVDR_VP_WR_CFG_15_REG 0x10C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_15_REG 0x110
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_15_REG 0x114
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_15_REG 0x118
|
||||
#define CVDR_CVDR_VP_WR_CFG_16_REG 0x11C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_16_REG 0x120
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_16_REG 0x124
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_16_REG 0x128
|
||||
#define CVDR_CVDR_VP_WR_CFG_17_REG 0x12C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_17_REG 0x130
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_17_REG 0x134
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_17_REG 0x138
|
||||
#define CVDR_CVDR_VP_WR_CFG_18_REG 0x13C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_18_REG 0x140
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_18_REG 0x144
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_18_REG 0x148
|
||||
#define CVDR_CVDR_VP_WR_CFG_19_REG 0x14C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_19_REG 0x150
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_19_REG 0x154
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_19_REG 0x158
|
||||
#define CVDR_CVDR_VP_WR_CFG_20_REG 0x15C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_20_REG 0x160
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_20_REG 0x164
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_20_REG 0x168
|
||||
#define CVDR_CVDR_VP_WR_CFG_21_REG 0x16C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_21_REG 0x170
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_21_REG 0x174
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_21_REG 0x178
|
||||
#define CVDR_CVDR_VP_WR_CFG_22_REG 0x17C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_22_REG 0x180
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_22_REG 0x184
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_22_REG 0x188
|
||||
#define CVDR_CVDR_VP_WR_CFG_23_REG 0x18C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_23_REG 0x190
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_23_REG 0x194
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_23_REG 0x198
|
||||
#define CVDR_CVDR_VP_WR_CFG_24_REG 0x19C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_24_REG 0x1A0
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_24_REG 0x1A4
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_24_REG 0x1A8
|
||||
#define CVDR_CVDR_VP_WR_CFG_25_REG 0x1AC
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_25_REG 0x1B0
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_25_REG 0x1B4
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_25_REG 0x1B8
|
||||
#define CVDR_CVDR_VP_WR_CFG_26_REG 0x1BC
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_26_REG 0x1C0
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_26_REG 0x1C4
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_26_REG 0x1C8
|
||||
#define CVDR_CVDR_VP_WR_CFG_27_REG 0x1CC
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_27_REG 0x1D0
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_27_REG 0x1D4
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_27_REG 0x1D8
|
||||
#define CVDR_CVDR_VP_WR_CFG_28_REG 0x1DC
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_28_REG 0x1E0
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_28_REG 0x1E4
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_28_REG 0x1E8
|
||||
#define CVDR_CVDR_VP_WR_CFG_29_REG 0x1EC
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_29_REG 0x1F0
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_29_REG 0x1F4
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_29_REG 0x1F8
|
||||
#define CVDR_CVDR_VP_WR_CFG_30_REG 0x1FC
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_30_REG 0x200
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_30_REG 0x204
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_30_REG 0x208
|
||||
#define CVDR_CVDR_VP_WR_CFG_31_REG 0x20C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_31_REG 0x210
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_31_REG 0x214
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_31_REG 0x218
|
||||
#define CVDR_CVDR_VP_WR_CFG_32_REG 0x21C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_32_REG 0x220
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_32_REG 0x224
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_32_REG 0x228
|
||||
#define CVDR_CVDR_VP_WR_CFG_33_REG 0x22C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_33_REG 0x230
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_33_REG 0x234
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_33_REG 0x238
|
||||
#define CVDR_CVDR_VP_WR_CFG_34_REG 0x23C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_34_REG 0x240
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_34_REG 0x244
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_34_REG 0x248
|
||||
#define CVDR_CVDR_VP_WR_CFG_35_REG 0x24C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_35_REG 0x250
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_35_REG 0x254
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_35_REG 0x258
|
||||
#define CVDR_CVDR_VP_WR_CFG_36_REG 0x25C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_36_REG 0x260
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_36_REG 0x264
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_36_REG 0x268
|
||||
#define CVDR_CVDR_VP_WR_CFG_37_REG 0x26C
|
||||
#define CVDR_CVDR_VP_WR_AXI_FS_37_REG 0x270
|
||||
#define CVDR_CVDR_VP_WR_AXI_LINE_37_REG 0x274
|
||||
#define CVDR_CVDR_VP_WR_IF_CFG_37_REG 0x278
|
||||
#define CVDR_CVDR_LIMITER_VP_WR_0_REG 0x400
|
||||
|
||||
#endif /* __CVDR_REG_OFFSET_H__ */
|
||||
@@ -0,0 +1,762 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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 "hisi_isp_i2c.h"
|
||||
#include "hisi_isp_common.h"
|
||||
|
||||
/* Registers offset */
|
||||
#define I2C_CON 0x0
|
||||
#define I2C_TAR 0x4
|
||||
#define I2C_DATA_CMD 0x10
|
||||
#define I2C_SS_SCL_HCNT 0x14
|
||||
#define I2C_SS_SCL_LCNT 0x18
|
||||
#define I2C_FS_SCL_HCNT 0x1c
|
||||
#define I2C_FS_SCL_LCNT 0x20
|
||||
#define I2C_HS_SCL_HCNT 0x24
|
||||
#define I2C_HS_SCL_LCNT 0x28
|
||||
#define I2C_SDA_HOLD 0x7C
|
||||
#define I2C_FS_SPKLEN 0xA0
|
||||
#define I2C_HS_SPKLEN 0xA4
|
||||
|
||||
#define I2C_INTR_STAT 0x2c
|
||||
#define I2C_INTR_MASK 0x30
|
||||
#define I2C_RAW_INTR_STAT 0x34
|
||||
#define I2C_RX_TL 0x38
|
||||
#define I2C_TX_TL 0x3c
|
||||
#define I2C_CLR_INTR 0x40
|
||||
#define I2C_CLR_RX_UNDER 0x44
|
||||
#define I2C_CLR_RX_OVER 0x48
|
||||
#define I2C_CLR_TX_OVER 0x4c
|
||||
#define I2C_CLR_RD_REQ 0x50
|
||||
#define I2C_CLR_TX_ABRT 0x54
|
||||
#define I2C_CLR_RX_DONE 0x58
|
||||
#define I2C_CLR_ACTIVITY 0x5c
|
||||
#define I2C_CLR_STOP_DET 0x60
|
||||
#define I2C_CLR_START_DET 0x64
|
||||
#define I2C_CLR_GEN_CALL 0x68
|
||||
#define I2C_ENABLE 0x6c
|
||||
#define I2C_STATUS 0x70
|
||||
#define I2C_TXFLR 0x74
|
||||
#define I2C_RXFLR 0x78
|
||||
#define I2C_TX_ABRT_SOURCE 0x80
|
||||
#define I2C_ENABLE_STATUS 0x9c
|
||||
#define I2C_COMP_TYPE 0xfc
|
||||
#define I2C_COMP_TYPE_VALUE 0x44570140
|
||||
|
||||
#define I2C_INTR_RX_UNDER 0x001
|
||||
#define I2C_INTR_RX_OVER 0x002
|
||||
#define I2C_INTR_RX_FULL 0x004
|
||||
#define I2C_INTR_TX_OVER 0x008
|
||||
#define I2C_INTR_TX_EMPTY 0x010
|
||||
#define I2C_INTR_RD_REQ 0x020
|
||||
#define I2C_INTR_TX_ABRT 0x040
|
||||
#define I2C_INTR_RX_DONE 0x080
|
||||
#define I2C_INTR_ACTIVITY 0x100
|
||||
#define I2C_INTR_STOP_DET 0x200
|
||||
#define I2C_INTR_START_DET 0x400
|
||||
#define I2C_INTR_GEN_CALL 0x800
|
||||
|
||||
#define I2C_INTR_DEFAULT_MASK (I2C_INTR_RX_FULL | \
|
||||
I2C_INTR_TX_EMPTY | \
|
||||
I2C_INTR_TX_ABRT | \
|
||||
I2C_INTR_STOP_DET)
|
||||
|
||||
#define I2C_STATUS_ACTIVITY 0x1
|
||||
#define I2C_ERR_TX_ABRT 0x1
|
||||
#define I2C_IC_EN 0x1
|
||||
|
||||
#define I2C_M_RD 0x01
|
||||
|
||||
#define I2C_CON_MASTER 0x1
|
||||
#define I2C_CON_SPEED_STD 0x2
|
||||
#define I2C_CON_SPEED_FAST 0x4
|
||||
#define I2C_CON_SPEED_HIGH 0x6
|
||||
#define I2C_CON_10BITADDR_MASTER 0x10
|
||||
#define I2C_CON_RESTART_EN 0x20
|
||||
#define I2C_CON_SLAVE_DISABLE 0x40
|
||||
|
||||
#define I2C_COMP_PARAM_1 0xf4
|
||||
|
||||
/* status codes */
|
||||
#define STATUS_IDLE 0x0
|
||||
#define STATUS_WRITE_IN_PROGRESS 0x1
|
||||
#define STATUS_READ_IN_PROGRESS 0x2
|
||||
|
||||
#define ISPSS_CTRL_MODULE_RESET_TOP_REG 0x60
|
||||
|
||||
static unsigned int isp_i2c_reg_read(struct isp_i2c_dev_t *dev, int offset)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
value = readl(dev->base + offset);
|
||||
return value;
|
||||
}
|
||||
|
||||
static void isp_i2c_reg_write(struct isp_i2c_dev_t *dev,
|
||||
int offset, unsigned int b)
|
||||
{
|
||||
writel(b, dev->base + offset);
|
||||
}
|
||||
|
||||
static int isp_i2c_wait_bus_not_busy(struct isp_i2c_dev_t *dev)
|
||||
{
|
||||
unsigned int timeout = 20;/* ms*/
|
||||
|
||||
while (isp_i2c_reg_read(dev, I2C_STATUS) & I2C_STATUS_ACTIVITY) {
|
||||
if (timeout <= 0) {
|
||||
ISP_ERR("timeout waiting for bus ready\n");
|
||||
return -1;
|
||||
}
|
||||
timeout--;
|
||||
mdelay(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int isp_i2c_read_clear_intrbits(struct isp_i2c_dev_t *dev)
|
||||
{
|
||||
unsigned int stat;
|
||||
|
||||
stat = isp_i2c_reg_read(dev, I2C_INTR_STAT);
|
||||
|
||||
if (stat & I2C_INTR_RX_UNDER)
|
||||
isp_i2c_reg_read(dev, I2C_CLR_RX_UNDER);
|
||||
if (stat & I2C_INTR_RX_OVER)
|
||||
isp_i2c_reg_read(dev, I2C_CLR_RX_OVER);
|
||||
if (stat & I2C_INTR_TX_OVER)
|
||||
isp_i2c_reg_read(dev, I2C_CLR_TX_OVER);
|
||||
if (stat & I2C_INTR_RD_REQ)
|
||||
isp_i2c_reg_read(dev, I2C_CLR_RD_REQ);
|
||||
if (stat & I2C_INTR_TX_ABRT) {
|
||||
ISP_ERR("ABRT_SOURCE 0x%x\n",
|
||||
isp_i2c_reg_read(dev, I2C_TX_ABRT_SOURCE));
|
||||
isp_i2c_reg_read(dev, I2C_TX_ABRT_SOURCE);
|
||||
isp_i2c_reg_read(dev, I2C_CLR_TX_ABRT);
|
||||
}
|
||||
if (stat & I2C_INTR_RX_DONE)
|
||||
isp_i2c_reg_read(dev, I2C_CLR_RX_DONE);
|
||||
if (stat & I2C_INTR_ACTIVITY)
|
||||
isp_i2c_reg_read(dev, I2C_CLR_ACTIVITY);
|
||||
if (stat & I2C_INTR_STOP_DET)
|
||||
isp_i2c_reg_read(dev, I2C_CLR_STOP_DET);
|
||||
if (stat & I2C_INTR_START_DET)
|
||||
isp_i2c_reg_read(dev, I2C_CLR_START_DET);
|
||||
if (stat & I2C_INTR_GEN_CALL)
|
||||
isp_i2c_reg_read(dev, I2C_CLR_GEN_CALL);
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
static void isp_i2c_read(struct isp_i2c_dev_t *dev)
|
||||
{
|
||||
struct isp_i2c_msg_t *msgs = dev->msgs;
|
||||
int rx_valid;
|
||||
|
||||
for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) {
|
||||
unsigned int len;
|
||||
unsigned char *buf;
|
||||
|
||||
if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD))
|
||||
continue;
|
||||
|
||||
if (!(dev->status & STATUS_READ_IN_PROGRESS)) {
|
||||
len = msgs[dev->msg_read_idx].len;
|
||||
buf = msgs[dev->msg_read_idx].buf;
|
||||
} else {
|
||||
len = dev->rx_buf_len;
|
||||
buf = dev->rx_buf;
|
||||
}
|
||||
|
||||
rx_valid = isp_i2c_reg_read(dev, I2C_RXFLR);
|
||||
|
||||
for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
|
||||
*buf++ = isp_i2c_reg_read(dev, I2C_DATA_CMD);
|
||||
dev->rx_outstanding--;
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
dev->status |= STATUS_READ_IN_PROGRESS;
|
||||
dev->rx_buf_len = len;
|
||||
dev->rx_buf = buf;
|
||||
return;
|
||||
}
|
||||
dev->status &= ~STATUS_READ_IN_PROGRESS;
|
||||
}
|
||||
}
|
||||
|
||||
static void isp_i2c_xfer_msg_loop(struct isp_i2c_dev_t *dev,
|
||||
struct isp_i2c_msg_t *msgs,
|
||||
int tx_limit, int rx_limit)
|
||||
{
|
||||
while (dev->tx_buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
|
||||
unsigned int cmd = 0;
|
||||
|
||||
if (dev->msg_write_idx == dev->msgs_num - 1 &&
|
||||
dev->tx_buf_len == 1)
|
||||
cmd |= (0x1 << 9);
|
||||
|
||||
if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
|
||||
/* avoid rx buffer overrun */
|
||||
if (rx_limit - dev->rx_outstanding <= 0)
|
||||
break;
|
||||
|
||||
isp_i2c_reg_write(dev, I2C_DATA_CMD, cmd | 0x100);
|
||||
rx_limit--;
|
||||
dev->rx_outstanding++;
|
||||
} else {
|
||||
isp_i2c_reg_write(dev,
|
||||
I2C_DATA_CMD, cmd | *(dev->tx_buf)++);
|
||||
}
|
||||
|
||||
tx_limit--;
|
||||
dev->tx_buf_len--;
|
||||
}
|
||||
}
|
||||
|
||||
static int isp_i2c_xfer_msg(struct isp_i2c_dev_t *dev)
|
||||
{
|
||||
int tx_limit;
|
||||
int rx_limit;
|
||||
unsigned int intr_mask;
|
||||
|
||||
struct isp_i2c_msg_t *msgs = dev->msgs;
|
||||
unsigned int addr = msgs[dev->msg_write_idx].addr;
|
||||
|
||||
intr_mask = I2C_INTR_DEFAULT_MASK;
|
||||
|
||||
for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
|
||||
if (msgs[dev->msg_write_idx].addr != addr) {
|
||||
ISP_ERR(" invalid target address\n");
|
||||
dev->msg_err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (msgs[dev->msg_write_idx].len == 0) {
|
||||
ISP_ERR(" invalid message length\n");
|
||||
dev->msg_err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
|
||||
/* new isp_i2c_msg_t */
|
||||
dev->tx_buf = msgs[dev->msg_write_idx].buf;
|
||||
dev->tx_buf_len = msgs[dev->msg_write_idx].len;
|
||||
}
|
||||
|
||||
tx_limit = dev->tx_fifo_depth
|
||||
- isp_i2c_reg_read(dev, I2C_TXFLR);
|
||||
rx_limit = dev->rx_fifo_depth
|
||||
- isp_i2c_reg_read(dev, I2C_RXFLR);
|
||||
|
||||
isp_i2c_xfer_msg_loop(dev, msgs, tx_limit, rx_limit);
|
||||
|
||||
if (dev->tx_buf_len > 0) {
|
||||
/* more bytes to be written */
|
||||
dev->status |= STATUS_WRITE_IN_PROGRESS;
|
||||
break;
|
||||
}
|
||||
dev->status &= ~STATUS_WRITE_IN_PROGRESS;
|
||||
}
|
||||
|
||||
if (dev->msg_write_idx == dev->msgs_num)
|
||||
intr_mask &= ~I2C_INTR_TX_EMPTY;
|
||||
if (dev->msg_err)
|
||||
intr_mask = 0;
|
||||
|
||||
isp_i2c_reg_write(dev, I2C_INTR_MASK, intr_mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isp_i2c_polling(struct isp_i2c_dev_t *dev)
|
||||
{
|
||||
int stat;
|
||||
|
||||
stat = isp_i2c_read_clear_intrbits(dev);
|
||||
|
||||
if (stat & I2C_INTR_TX_ABRT) {
|
||||
dev->cmd_err |= I2C_ERR_TX_ABRT;
|
||||
dev->status = STATUS_IDLE;
|
||||
isp_i2c_reg_write(dev, I2C_INTR_MASK, 0);
|
||||
goto i2c_isr_err1;
|
||||
}
|
||||
|
||||
if (stat & I2C_INTR_RX_FULL)
|
||||
isp_i2c_read(dev);
|
||||
|
||||
if (stat & I2C_INTR_TX_EMPTY)
|
||||
isp_i2c_xfer_msg(dev);
|
||||
|
||||
i2c_isr_err1:
|
||||
if ((stat & (I2C_INTR_TX_ABRT | I2C_INTR_STOP_DET)) || dev->msg_err)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void isp_i2c_enable(struct isp_i2c_dev_t *dev)
|
||||
{
|
||||
int timeout = 100;
|
||||
|
||||
do {
|
||||
isp_i2c_reg_write(dev, I2C_ENABLE, 1);
|
||||
if ((isp_i2c_reg_read(dev, I2C_ENABLE_STATUS) & 1) == 1)
|
||||
return;
|
||||
|
||||
mdelay(1);
|
||||
} while (timeout--);
|
||||
|
||||
ISP_WARNING("i2c dev enable timeout\n");
|
||||
}
|
||||
|
||||
static void isp_i2c_disable(struct isp_i2c_dev_t *dev)
|
||||
{
|
||||
int timeout = 100;
|
||||
|
||||
do {
|
||||
isp_i2c_reg_write(dev, I2C_ENABLE, 0);
|
||||
if ((isp_i2c_reg_read(dev, I2C_ENABLE_STATUS) & 1) == 0)
|
||||
return;
|
||||
|
||||
mdelay(1);
|
||||
} while (timeout--);
|
||||
|
||||
ISP_WARNING("i2c dev disable timeout\n");
|
||||
}
|
||||
|
||||
static void isp_i2c_clear_int(struct isp_i2c_dev_t *dev)
|
||||
{
|
||||
isp_i2c_reg_read(dev, I2C_CLR_INTR);
|
||||
}
|
||||
|
||||
static unsigned int isp_i2c_scl_hcnt(unsigned int ic_clk, unsigned int tSYMBOL,
|
||||
unsigned int tf, int cond, int offset)
|
||||
{
|
||||
if (cond)
|
||||
return (ic_clk * tSYMBOL + 5000) / 10000 - 8 + offset;
|
||||
else
|
||||
return (ic_clk * (tSYMBOL + tf) + 5000) / 10000 - 3 + offset;
|
||||
}
|
||||
|
||||
static unsigned int isp_i2c_scl_lcnt(unsigned int ic_clk, unsigned int tLOW,
|
||||
unsigned int tf, int offset)
|
||||
{
|
||||
return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset;
|
||||
}
|
||||
|
||||
static void isp_i2c_xfer_init(struct isp_i2c_dev_t *dev,
|
||||
enum isp_i2c_speed_e speed_cfg)
|
||||
{
|
||||
struct isp_i2c_msg_t *msgs = dev->msgs;
|
||||
unsigned int retry_num = 100;
|
||||
unsigned int ic_con = 0;
|
||||
unsigned int hcnt;
|
||||
unsigned int lcnt;
|
||||
|
||||
isp_i2c_reg_write(dev, I2C_ENABLE, 0);
|
||||
|
||||
while ((--retry_num != 0) &&
|
||||
(isp_i2c_reg_read(dev, I2C_ENABLE_STATUS) & I2C_IC_EN))
|
||||
mdelay(1);
|
||||
|
||||
if (retry_num <= 0)
|
||||
ISP_ERR(" disable i2c controller error.\n");
|
||||
|
||||
/* set the slave (target) address */
|
||||
isp_i2c_reg_write(dev, I2C_TAR, msgs[dev->msg_write_idx].addr);
|
||||
|
||||
/* configure the i2c master speed */
|
||||
if (speed_cfg > dev->speed_cfg)
|
||||
ISP_ERR("i2c drv error: %d is beyond speed_cfg\n", speed_cfg);
|
||||
|
||||
switch (speed_cfg) {
|
||||
case I2C_SPEED_STD:
|
||||
ic_con = I2C_CON_SPEED_STD;
|
||||
break;
|
||||
case I2C_SPEED_FAST:
|
||||
ic_con = I2C_CON_SPEED_FAST;
|
||||
hcnt = isp_i2c_scl_hcnt(dev->ic_clk,
|
||||
6, /* tHD;STA = tHIGH = 0.6 us */
|
||||
3, /* tf = 0.3 us */
|
||||
0, /* 0: default, 1: Ideal */
|
||||
0); /* No offset */
|
||||
lcnt = isp_i2c_scl_lcnt(dev->ic_clk,
|
||||
13, /* tLOW = 1.3 us */
|
||||
3, /* tf = 0.3 us */
|
||||
0); /* No offset */
|
||||
isp_i2c_reg_write(dev, I2C_FS_SCL_HCNT, hcnt);
|
||||
isp_i2c_reg_write(dev, I2C_FS_SCL_LCNT, lcnt);
|
||||
break;
|
||||
case I2C_SPEED_FAST_PLUS:
|
||||
ic_con = I2C_CON_SPEED_FAST;
|
||||
hcnt = isp_i2c_scl_hcnt(dev->ic_clk,
|
||||
2, /* tHD;STA = tHIGH = 0.26 us */
|
||||
1, /* tf = 0.12 us */
|
||||
0, /* 0: default, 1: Ideal */
|
||||
0); /* No offset */
|
||||
lcnt = isp_i2c_scl_lcnt(dev->ic_clk,
|
||||
5, /* tLOW = 0.5 us */
|
||||
1, /* tf = 0.12 us */
|
||||
0); /* No offset */
|
||||
isp_i2c_reg_write(dev, I2C_FS_SCL_HCNT, hcnt);
|
||||
isp_i2c_reg_write(dev, I2C_FS_SCL_LCNT, lcnt);
|
||||
break;
|
||||
case I2C_SPEED_HIGH:
|
||||
ic_con = I2C_CON_SPEED_HIGH;
|
||||
break;
|
||||
}
|
||||
|
||||
isp_i2c_reg_write(dev, I2C_CON, dev->master_cfg | ic_con);
|
||||
/* if the slave address is ten bit address, enable 10BITADDR */
|
||||
ic_con = isp_i2c_reg_read(dev, I2C_CON);
|
||||
if (msgs[dev->msg_write_idx].flags & I2C_ADDR_10BIT)
|
||||
ic_con |= I2C_CON_10BITADDR_MASTER;
|
||||
else
|
||||
ic_con &= ~I2C_CON_10BITADDR_MASTER;
|
||||
|
||||
isp_i2c_reg_write(dev, I2C_CON, ic_con);
|
||||
|
||||
isp_i2c_enable(dev);
|
||||
isp_i2c_clear_int(dev);
|
||||
/* Enable interrupts */
|
||||
isp_i2c_reg_write(dev, I2C_INTR_MASK, I2C_INTR_DEFAULT_MASK);
|
||||
}
|
||||
|
||||
int isp_i2c_xfer(struct isp_i2c_dev_t *dev,
|
||||
struct isp_i2c_msg_t msgs[],
|
||||
int num, int burst_flag,
|
||||
enum isp_i2c_speed_e speed_cfg)
|
||||
{
|
||||
int totallen;
|
||||
int i;
|
||||
int ret;
|
||||
unsigned int timeout = 100;
|
||||
|
||||
dev->msgs = msgs;
|
||||
dev->msgs_num = num;
|
||||
dev->cmd_err = 0;
|
||||
dev->msg_write_idx = 0;
|
||||
dev->msg_read_idx = 0;
|
||||
dev->msg_err = 0;
|
||||
dev->status = STATUS_IDLE;
|
||||
dev->abort_source = 0;
|
||||
dev->rx_outstanding = 0;
|
||||
|
||||
ret = isp_i2c_wait_bus_not_busy(dev);
|
||||
if (ret < 0)
|
||||
return -EBUSY;
|
||||
/* start the transfers */
|
||||
isp_i2c_xfer_init(dev, speed_cfg);
|
||||
|
||||
/* calculate total length */
|
||||
totallen = 0;
|
||||
for (i = 0; i < num; i++)
|
||||
totallen += msgs[i].len;
|
||||
|
||||
/* wait for tx to complete */
|
||||
while (true) {
|
||||
if (timeout <= 0) {
|
||||
ISP_ERR("i2c timeout\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (isp_i2c_polling(dev) == 0)
|
||||
break;
|
||||
|
||||
mdelay(1);
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (dev->msg_err) {
|
||||
ISP_ERR("I2C msg_err\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (dev->cmd_err == I2C_ERR_TX_ABRT) {
|
||||
ISP_ERR("I2C abort\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
isp_i2c_disable(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isp_i2c_read_reg(struct isp_i2c_client_t *client,
|
||||
unsigned short reg,
|
||||
unsigned char *val)
|
||||
{
|
||||
struct isp_i2c_msg_t msg[2];
|
||||
int ret;
|
||||
unsigned char addr[2];
|
||||
unsigned char data;
|
||||
|
||||
if ((client == NULL) || (client->i2c_dev == NULL)) {
|
||||
ISP_ERR("device is null\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr[0] = (reg>>8) & 0xff;
|
||||
addr[1] = reg & 0xff;
|
||||
|
||||
msg[0].addr = client->addr;
|
||||
msg[0].len = 2;
|
||||
msg[0].buf = addr;
|
||||
msg[0].flags = client->flag & I2C_ADDR_10BIT;
|
||||
|
||||
msg[1].addr = client->addr;
|
||||
msg[1].len = 1;
|
||||
msg[1].buf = &data;
|
||||
msg[1].flags = client->flag & I2C_ADDR_10BIT;
|
||||
msg[1].flags |= I2C_M_RD;
|
||||
|
||||
ISP_ERR("read[0x%x]\n", reg);
|
||||
|
||||
ret = isp_i2c_xfer(client->i2c_dev, msg, 2, 0, client->speed_cfg);
|
||||
if (ret != 0) {
|
||||
ISP_ERR("read reg fail");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ISP_ERR("read[0x%x] = 0x%x\n", reg, data);
|
||||
|
||||
*val = data;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int isp_i2c_write_reg(struct isp_i2c_client_t *client,
|
||||
unsigned short reg,
|
||||
unsigned char val)
|
||||
{
|
||||
struct isp_i2c_msg_t msg[1];
|
||||
int ret;
|
||||
unsigned char data[3];
|
||||
|
||||
if ((client == NULL) || (client->i2c_dev == NULL)) {
|
||||
ISP_ERR("device is null\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
data[0] = (reg>>8) & 0xff;
|
||||
data[1] = reg & 0xff;
|
||||
data[2] = val;
|
||||
|
||||
msg[0].addr = client->addr;
|
||||
msg[0].len = 3;
|
||||
msg[0].buf = data;
|
||||
msg[0].flags = client->flag & I2C_ADDR_10BIT;
|
||||
|
||||
ret = isp_i2c_xfer(client->i2c_dev, msg, 1, 0, client->speed_cfg);
|
||||
if (ret != 0) {
|
||||
ISP_ERR("write reg fail\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void isp_i2c_ispss_reset(struct isp_i2c_dev_t *dev)
|
||||
{
|
||||
int offset;
|
||||
|
||||
switch (dev->base - dev->isp_base) {
|
||||
case ISP_BASE_ADDR_I2C_1:
|
||||
offset = 11;
|
||||
break;
|
||||
case ISP_BASE_ADDR_I2C_2:
|
||||
offset = 10;
|
||||
break;
|
||||
case ISP_BASE_ADDR_I2C_3:
|
||||
offset = 12;
|
||||
break;
|
||||
default:
|
||||
ISP_ERR("invalid i2c device\n");
|
||||
return;
|
||||
}
|
||||
|
||||
REG_SET(dev->isp_base + ISP_BASE_ADDR_ISPSS_CTRL +
|
||||
ISPSS_CTRL_MODULE_RESET_TOP_REG, 1 << offset);
|
||||
mdelay(1);
|
||||
REG_SET(dev->isp_base + ISP_BASE_ADDR_ISPSS_CTRL +
|
||||
ISPSS_CTRL_MODULE_RESET_TOP_REG, 0x00000000);
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
static int isp_i2c_init(struct isp_i2c_dev_t *dev)
|
||||
{
|
||||
unsigned int hcnt;
|
||||
unsigned int lcnt;
|
||||
unsigned int sda_delay_count;
|
||||
|
||||
/* I2C internal clock */
|
||||
dev->ic_clk = 480000;
|
||||
|
||||
/* workaround: reset for a poweron sequence */
|
||||
isp_i2c_ispss_reset(dev);
|
||||
|
||||
isp_i2c_disable(dev);
|
||||
|
||||
/* Standard-mode */
|
||||
hcnt = isp_i2c_scl_hcnt(dev->ic_clk,
|
||||
40, /* tHD;STA = tHIGH = 4.0 us */
|
||||
3, /* tf = 0.3 us */
|
||||
0, /* 0: default, 1: Ideal */
|
||||
0); /* No offset */
|
||||
|
||||
lcnt = isp_i2c_scl_lcnt(dev->ic_clk,
|
||||
47, /* tLOW = 4.7 us */
|
||||
3, /* tf = 0.3 us */
|
||||
0); /* No offset */
|
||||
|
||||
isp_i2c_reg_write(dev, I2C_SS_SCL_HCNT, hcnt);
|
||||
isp_i2c_reg_write(dev, I2C_SS_SCL_LCNT, lcnt);
|
||||
|
||||
/* Fast-mode */
|
||||
hcnt = isp_i2c_scl_hcnt(dev->ic_clk,
|
||||
6, /* tHD;STA = tHIGH = 0.6 us */
|
||||
3, /* tf = 0.3 us */
|
||||
0, /* 0: default, 1: Ideal */
|
||||
0); /* No offset */
|
||||
|
||||
lcnt = isp_i2c_scl_lcnt(dev->ic_clk,
|
||||
13, /* tLOW = 1.3 us */
|
||||
3, /* tf = 0.3 us */
|
||||
0); /* No offset */
|
||||
|
||||
isp_i2c_reg_write(dev, I2C_FS_SCL_HCNT, hcnt);
|
||||
isp_i2c_reg_write(dev, I2C_FS_SCL_LCNT, lcnt);
|
||||
|
||||
/* High-mode */
|
||||
hcnt = isp_i2c_scl_hcnt(dev->ic_clk,
|
||||
1, /* tHD;STA = tHIGH = 0.1 us */
|
||||
3, /* tf = 0.3 us */
|
||||
0, /* 0: default, 1: Ideal */
|
||||
0); /* No offset */
|
||||
|
||||
lcnt = isp_i2c_scl_lcnt(dev->ic_clk,
|
||||
2, /* tLOW = 0.2 us */
|
||||
3, /* tf = 0.3 us */
|
||||
0); /* No offset */
|
||||
|
||||
isp_i2c_reg_write(dev, I2C_HS_SCL_HCNT, hcnt);
|
||||
isp_i2c_reg_write(dev, I2C_HS_SCL_LCNT, lcnt);
|
||||
|
||||
/* Spike Suppression (FS 50ns or HS 10ns) */
|
||||
isp_i2c_reg_write(dev, I2C_FS_SPKLEN, (dev->ic_clk * 50) / 1000000);
|
||||
isp_i2c_reg_write(dev, I2C_HS_SPKLEN, (dev->ic_clk * 10) / 1000000);
|
||||
|
||||
/* SDA HOLD TIME (300ns or 70ns)*/
|
||||
sda_delay_count = (dev->ic_clk * 300) / 1000000;
|
||||
isp_i2c_reg_write(dev, I2C_SDA_HOLD, sda_delay_count);
|
||||
|
||||
/* Configure Tx/Rx FIFO threshold levels */
|
||||
isp_i2c_reg_write(dev, I2C_TX_TL, dev->tx_fifo_depth / 2);
|
||||
isp_i2c_reg_write(dev, I2C_RX_TL, 0);
|
||||
|
||||
/* configure the i2c master */
|
||||
isp_i2c_reg_write(dev, I2C_CON, dev->master_cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void isp_i2c_disable_int(struct isp_i2c_dev_t *dev)
|
||||
{
|
||||
isp_i2c_reg_write(dev, I2C_INTR_MASK, 0);
|
||||
}
|
||||
|
||||
int isp_i2c_open(struct isp_i2c_client_t *client)
|
||||
{
|
||||
struct isp_i2c_dev_t *i2c_dev = client->i2c_dev;
|
||||
int param;
|
||||
int ret;
|
||||
|
||||
i2c_dev->master_cfg = I2C_CON_MASTER |
|
||||
I2C_CON_SLAVE_DISABLE |
|
||||
I2C_CON_RESTART_EN;
|
||||
|
||||
param = isp_i2c_reg_read(i2c_dev, I2C_COMP_PARAM_1);
|
||||
i2c_dev->tx_fifo_depth = ((param >> 16) & 0xff) + 1;
|
||||
i2c_dev->rx_fifo_depth = ((param >> 8) & 0xff) + 1;
|
||||
|
||||
ret = isp_i2c_init(i2c_dev);
|
||||
if (ret != 0) {
|
||||
ISP_ERR(" i2c init failed :%x\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
isp_i2c_disable_int(i2c_dev);
|
||||
|
||||
i2c_dev->speed_cfg = I2C_SPEED_HIGH;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isp_i2c_close(struct isp_i2c_client_t *client)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct isp_i2c_dev_ops i2c_dops = {
|
||||
.open = isp_i2c_open,
|
||||
.close = isp_i2c_close,
|
||||
.read = isp_i2c_read_reg,
|
||||
.write = isp_i2c_write_reg,
|
||||
};
|
||||
|
||||
int isp_i2c_get_offset(int csi_index)
|
||||
{
|
||||
switch (csi_index) {
|
||||
case 0:
|
||||
return ISP_BASE_ADDR_I2C_1;
|
||||
case 1:
|
||||
return ISP_BASE_ADDR_I2C_2;
|
||||
case 2:
|
||||
return ISP_BASE_ADDR_I2C_3;
|
||||
default:
|
||||
ISP_ERR("csi_index=%d error\n", csi_index);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
struct isp_i2c_client_t *create_isp_i2c_client(struct isp_device *isp_dev)
|
||||
{
|
||||
struct isp_i2c_client_t *client = NULL;
|
||||
|
||||
client = kzalloc(sizeof(struct isp_i2c_client_t), GFP_KERNEL);
|
||||
|
||||
if (client) {
|
||||
client->i2c_dev =
|
||||
kzalloc(sizeof(struct isp_i2c_dev_t), GFP_KERNEL);
|
||||
if (client->i2c_dev) {
|
||||
client->i2c_dev->base = isp_dev->base +
|
||||
isp_i2c_get_offset(isp_dev->csi_index);
|
||||
client->i2c_dev->isp_base = isp_dev->base;
|
||||
client->csi_index = isp_dev->csi_index;
|
||||
client->addr = isp_dev->addr >> 1;
|
||||
client->flag = isp_dev->flag;
|
||||
client->speed_cfg = isp_dev->speed_cfg;
|
||||
client->ops = &i2c_dops;
|
||||
client->isp_dev = isp_dev;
|
||||
} else {
|
||||
kfree(client);
|
||||
client = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
EXPORT_SYMBOL(create_isp_i2c_client);
|
||||
|
||||
void destroy_isp_i2c_client(struct isp_i2c_client_t *client)
|
||||
{
|
||||
kfree(client->i2c_dev);
|
||||
kfree(client);
|
||||
}
|
||||
EXPORT_SYMBOL(destroy_isp_i2c_client);
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef HISI_ISP_I2C_H
|
||||
#define HISI_ISP_I2C_H
|
||||
|
||||
#include "hisi_isp_core.h"
|
||||
|
||||
enum isp_i2c_addr_e {
|
||||
I2C_ADDR_7BIT = 0x0,
|
||||
I2C_ADDR_10BIT = 0x10,
|
||||
};
|
||||
|
||||
enum isp_i2c_speed_e {
|
||||
I2C_SPEED_STD = 0x1,
|
||||
I2C_SPEED_FAST = 0x2,
|
||||
I2C_SPEED_FAST_PLUS = 0x3,
|
||||
I2C_SPEED_HIGH = 0x4,
|
||||
};
|
||||
|
||||
enum state_e {
|
||||
OFF,
|
||||
ON,
|
||||
STATE_END,
|
||||
};
|
||||
|
||||
struct isp_i2c_msg_t {
|
||||
unsigned short addr;
|
||||
unsigned short flags;
|
||||
unsigned short len;
|
||||
unsigned char *buf;
|
||||
};
|
||||
|
||||
struct isp_i2c_dev_t {
|
||||
char __iomem *isp_base;
|
||||
char __iomem *base;
|
||||
enum isp_i2c_speed_e speed_cfg;
|
||||
unsigned int irq;
|
||||
unsigned int ic_clk;
|
||||
unsigned int master_cfg;
|
||||
unsigned int cmd_err;
|
||||
struct isp_i2c_msg_t *msgs;
|
||||
int msgs_num;
|
||||
int msg_write_idx;
|
||||
int msg_read_idx;
|
||||
unsigned int tx_buf_len;
|
||||
unsigned int rx_buf_len;
|
||||
unsigned char *tx_buf;
|
||||
unsigned char *rx_buf;
|
||||
int msg_err;
|
||||
unsigned int status;
|
||||
unsigned int abort_source;
|
||||
unsigned int tx_fifo_depth;
|
||||
unsigned int rx_fifo_depth;
|
||||
int rx_outstanding;
|
||||
};
|
||||
|
||||
struct isp_i2c_client_t {
|
||||
struct isp_device *isp_dev;
|
||||
struct isp_i2c_dev_t *i2c_dev;
|
||||
struct isp_i2c_dev_ops *ops;
|
||||
int csi_index;
|
||||
unsigned short addr;
|
||||
unsigned int flag;
|
||||
enum isp_i2c_speed_e speed_cfg;
|
||||
int mode;
|
||||
};
|
||||
|
||||
struct isp_i2c_dev_ops {
|
||||
int (*open)(struct isp_i2c_client_t *client);
|
||||
int (*close)(struct isp_i2c_client_t *client);
|
||||
int (*read)(struct isp_i2c_client_t *client,
|
||||
unsigned short reg, unsigned char *val);
|
||||
int (*write)(struct isp_i2c_client_t *client,
|
||||
unsigned short reg, unsigned char val);
|
||||
};
|
||||
|
||||
struct isp_i2c_client_t *create_isp_i2c_client(struct isp_device *isp_dev);
|
||||
void destroy_isp_i2c_client(struct isp_i2c_client_t *client);
|
||||
|
||||
#endif /* HISI_ISP_I2C_H */
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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 "hisi_isp_isr.h"
|
||||
#include "hisi_isp_common.h"
|
||||
#include "hisi_isp_cvdr.h"
|
||||
#include "hisi_isp_sr.h"
|
||||
|
||||
static unsigned int
|
||||
isp_clear_irq(struct isp_device *d, enum IRQ_MERGER_TYPE irq)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
val = REG_GET(d->base +
|
||||
ISP_BASE_ADDR_IRQ_MERGER2+irq+IRQ_MERGER_FUNC_RIS);
|
||||
REG_SET(d->base +
|
||||
ISP_BASE_ADDR_IRQ_MERGER2+irq+IRQ_MERGER_FUNC_ICR, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void isp_enable_irq(struct isp_device *dev)
|
||||
{
|
||||
REG_SET(dev->base + IRQ_MERGER_IMSC_DEBUG1, 0xFFFFFFFF);
|
||||
REG_SET(dev->base + IRQ_MERGER_IMSC_FRPROC0, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void isp_clear_irq_state(struct isp_device *dev)
|
||||
{
|
||||
REG_SET(dev->base + IRQ_MERGER_ICR_DEBUG0, 0xFFFFFFFF);
|
||||
REG_SET(dev->base + IRQ_MERGER_ICR_DEBUG1, 0xFFFFFFFF);
|
||||
REG_SET(dev->base + IRQ_MERGER_ICR_DEBUG2, 0xFFFFFFFF);
|
||||
REG_SET(dev->base + IRQ_MERGER_ICR_DEBUG3, 0xFFFFFFFF);
|
||||
REG_SET(dev->base + IRQ_MERGER_ICR_ERROR0, 0xFFFFFFFF);
|
||||
REG_SET(dev->base + IRQ_MERGER_ICR_ERROR1, 0xFFFFFFFF);
|
||||
REG_SET(dev->base + IRQ_MERGER_ICR_FRPROC0, 0xFFFFFFFF);
|
||||
REG_SET(dev->base + IRQ_MERGER_ICR_FRPROC1, 0xFFFFFFFF);
|
||||
REG_SET(dev->base + IRQ_MERGER_ICR_FRPROC2, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
irqreturn_t isp_vic1_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct isp_device *d = (struct isp_device *)dev_id;
|
||||
|
||||
unsigned int val = isp_clear_irq(d, IRQ_MERGER_DEBUG_1);
|
||||
|
||||
if (val & (1 << IRQ_MERGER_SR_4_CVDR_RT_SOF_VPWR_23_OFFSET)) {
|
||||
isp_cvdr_config(d,
|
||||
d->hw_addr + frame_num2Offset(d, d->isp_frame_num + 1));
|
||||
|
||||
d->cur_frame_num++;
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
irqreturn_t isp_frproc0_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct isp_device *d = (struct isp_device *)dev_id;
|
||||
|
||||
unsigned int val = isp_clear_irq(d, IRQ_MERGER_FRPROC_0);
|
||||
|
||||
if (val & (1 << IRQ_MERGER_SR_4_CVDR_RT_EOF_VPWR_23_OFFSET)) {
|
||||
isp_sr_go(d, (1 << (4*d->csi_index)));
|
||||
if (d->cur_frame_num == SKIP_FRAME_NUM)
|
||||
memset(d->virt_addr, 0, d->pool_size);
|
||||
if (d->cur_frame_num > SKIP_FRAME_NUM) {
|
||||
d->isp_frame_num++;
|
||||
complete_all(&d->frame_comp);
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef HISI_ISP_ISR_DEF_H
|
||||
#define HISI_ISP_ISR_DEF_H
|
||||
|
||||
#include "hisi_isp_core.h"
|
||||
|
||||
#define SKIP_FRAME_NUM (4)
|
||||
#define ISP_BASE_ADDR_IRQ_MERGER (0x00025000)
|
||||
#define ISP_BASE_ADDR_IRQ_MERGER2 (0x0002C000)
|
||||
|
||||
enum IRQ_MERGER_TYPE {
|
||||
IRQ_MERGER_DEBUG_0 = 0x0,
|
||||
IRQ_MERGER_DEBUG_1 = 0x20,
|
||||
IRQ_MERGER_DEBUG_2 = 0x40,
|
||||
IRQ_MERGER_DEBUG_3 = 0x60,
|
||||
IRQ_MERGER_DEBUG_4 = 0x80,
|
||||
IRQ_MERGER_ERROR_0 = 0xE0,
|
||||
IRQ_MERGER_ERROR_1 = 0x100,
|
||||
IRQ_MERGER_FRPROC_0 = 0x120,
|
||||
IRQ_MERGER_FRPROC_1 = 0x140,
|
||||
IRQ_MERGER_FRPROC_2 = 0x160,
|
||||
IRQ_MERGER_COMBINED = 0x1A0,
|
||||
IRQ_MERGER_IRQ_MAX = 0xFF,
|
||||
};
|
||||
|
||||
enum IRQ_MERGER_FUNC_TYPE {
|
||||
IRQ_MERGER_FUNC_IMS = 0x0,
|
||||
IRQ_MERGER_FUNC_RIS = 0x4,
|
||||
IRQ_MERGER_FUNC_MIS = 0x8,
|
||||
IRQ_MERGER_FUNC_ICR = 0xC,
|
||||
IRQ_MERGER_FUNC_ISR = 0x10,
|
||||
IRQ_MERGER_FUNC_NO = 0x1F,
|
||||
};
|
||||
|
||||
#define IRQ_MERGER_IMSC_DEBUG0 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_DEBUG_0)
|
||||
#define IRQ_MERGER_IMSC_DEBUG1 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_DEBUG_1)
|
||||
#define IRQ_MERGER_IMSC_DEBUG2 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_DEBUG_2)
|
||||
#define IRQ_MERGER_IMSC_DEBUG3 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_DEBUG_3)
|
||||
#define IRQ_MERGER_IMSC_ERROR0 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_ERROR_0)
|
||||
#define IRQ_MERGER_IMSC_ERROR1 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_ERROR_1)
|
||||
#define IRQ_MERGER_IMSC_FRPROC0 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_FRPROC_0)
|
||||
#define IRQ_MERGER_IMSC_FRPROC1 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_FRPROC_1)
|
||||
#define IRQ_MERGER_IMSC_FRPROC2 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_FRPROC_2)
|
||||
|
||||
#define IRQ_MERGER_ICR_DEBUG0 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_DEBUG_0 + IRQ_MERGER_FUNC_ICR)
|
||||
#define IRQ_MERGER_ICR_DEBUG1 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_DEBUG_1 + IRQ_MERGER_FUNC_ICR)
|
||||
#define IRQ_MERGER_ICR_DEBUG2 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_DEBUG_2 + IRQ_MERGER_FUNC_ICR)
|
||||
#define IRQ_MERGER_ICR_DEBUG3 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_DEBUG_3 + IRQ_MERGER_FUNC_ICR)
|
||||
#define IRQ_MERGER_ICR_ERROR0 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_ERROR_0 + IRQ_MERGER_FUNC_ICR)
|
||||
#define IRQ_MERGER_ICR_ERROR1 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_ERROR_1 + IRQ_MERGER_FUNC_ICR)
|
||||
#define IRQ_MERGER_ICR_FRPROC0 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_FRPROC_0 + IRQ_MERGER_FUNC_ICR)
|
||||
#define IRQ_MERGER_ICR_FRPROC1 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_FRPROC_1 + IRQ_MERGER_FUNC_ICR)
|
||||
#define IRQ_MERGER_ICR_FRPROC2 \
|
||||
(ISP_BASE_ADDR_IRQ_MERGER2 + IRQ_MERGER_FRPROC_2 + IRQ_MERGER_FUNC_ICR)
|
||||
|
||||
#define IRQ_MERGER_SR_4_CVDR_RT_SOF_VPWR_23_OFFSET 17
|
||||
#define IRQ_MERGER_SR_4_CVDR_RT_EOF_VPWR_23_OFFSET 21
|
||||
|
||||
void isp_enable_irq(struct isp_device *dev);
|
||||
void isp_clear_irq_state(struct isp_device *dev);
|
||||
|
||||
irqreturn_t isp_vic1_handler(int irq, void *dev_id);
|
||||
irqreturn_t isp_frproc0_handler(int irq, void *dev_id);
|
||||
|
||||
#endif /* HISI_ISP_ISR_DEF_H */
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef HISI_ISP_REG_OFFSET_DEF_H
|
||||
#define HISI_ISP_REG_OFFSET_DEF_H
|
||||
|
||||
#define ISP_BASE_ADDR_CSI2IF_A (0x00002000)
|
||||
#define ISP_BASE_ADDR_CSI2IF_B (0x00003000)
|
||||
#define ISP_BASE_ADDR_CSI2IF_C (0x00004000)
|
||||
|
||||
#define ISP_BASE_ADDR_I2C_1 (0x00000000)
|
||||
#define ISP_BASE_ADDR_I2C_2 (0x00001000)
|
||||
#define ISP_BASE_ADDR_I2C_3 (0x00008000)
|
||||
|
||||
#define ISP_BASE_ADDR_SMMU (0x00006000)
|
||||
|
||||
#define ISP_BASE_ADDR_ISPSS_CTRL (0x00020000)
|
||||
|
||||
#define ISP_BASE_ADDR_STREAM_ROUTER (0x00021000)
|
||||
|
||||
#define ISP_BASE_ADDR_CVDR_RT (0x00022000)
|
||||
#define ISP_BASE_ADDR_CVDR_SRT (0x0002E000)
|
||||
|
||||
#define SUB_CTRL_BASE_ADDR (0x00183000)
|
||||
|
||||
#endif /* HISI_ISP_REG_OFFSET_DEF_H */
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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 "hisi_isp_sr.h"
|
||||
#include "hisi_isp_common.h"
|
||||
#include "hisi_isp_sr_reg_offset.h"
|
||||
|
||||
/* Define the union U_ID_ROUTER_1 */
|
||||
union U_ID_ROUTER_1 {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int reserved_0 : 16 ; /* [15..0] */
|
||||
unsigned int idr_input_stream_6 : 4 ; /* [19..16] */
|
||||
unsigned int idr_enable_6 : 1 ; /* [20] */
|
||||
unsigned int reserved_1 : 3 ; /* [23..21] */
|
||||
unsigned int idr_input_stream_7 : 4 ; /* [27..24] */
|
||||
unsigned int idr_enable_7 : 1 ; /* [28] */
|
||||
unsigned int reserved_2 : 3 ; /* [31..29] */
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
|
||||
};
|
||||
|
||||
/* Define the union U_REFORMAT */
|
||||
union U_REFORMAT {
|
||||
/* Define the struct bits */
|
||||
struct {
|
||||
unsigned int reformat_num_lines : 13 ; /* [12..0] */
|
||||
unsigned int reformat_pixel_reorder : 3 ; /* [15..13] */
|
||||
unsigned int reformat_num_pixels : 13 ; /* [28..16] */
|
||||
unsigned int reserved_0 : 2 ; /* [30..29] */
|
||||
unsigned int reformat_enable : 1 ; /* [31] */
|
||||
} bits;
|
||||
|
||||
/* Define an unsigned member */
|
||||
unsigned int u32;
|
||||
};
|
||||
|
||||
#define STREAM_ROUTER_REFORMAT_MINSPACE_REG(x) \
|
||||
(STREAM_ROUTER_REFORMAT_MINSPACE_0_REG +\
|
||||
(x)*(STREAM_ROUTER_REFORMAT_MINSPACE_1_REG -\
|
||||
STREAM_ROUTER_REFORMAT_MINSPACE_0_REG))
|
||||
|
||||
#define STREAM_ROUTER_REFORMAT_REG(x) \
|
||||
(STREAM_ROUTER_REFORMAT_0_REG +\
|
||||
(x)*(STREAM_ROUTER_REFORMAT_1_REG -\
|
||||
STREAM_ROUTER_REFORMAT_0_REG))
|
||||
|
||||
int isp_sr_config(struct isp_device *dev)
|
||||
{
|
||||
int data_type = 1;
|
||||
union U_ID_ROUTER_1 reg1;
|
||||
union U_REFORMAT reg;
|
||||
char __iomem *reg_addr;
|
||||
|
||||
reg_addr = dev->base + ISP_BASE_ADDR_STREAM_ROUTER +
|
||||
STREAM_ROUTER_CSIFILTER_A_REG +
|
||||
0x04 * dev->csi_index;
|
||||
REG_SET(reg_addr, (0 << 6) | (dev->dt << 0));
|
||||
|
||||
reg_addr = dev->base + ISP_BASE_ADDR_STREAM_ROUTER +
|
||||
STREAM_ROUTER_ID_ROUTER_1_REG;
|
||||
reg1.u32 = REG_GET(reg_addr);
|
||||
reg1.bits.idr_enable_6 = 1;
|
||||
reg1.bits.idr_input_stream_6 = (dev->csi_index << 2) | (0 << 0);
|
||||
REG_SET(reg_addr, reg1.u32);
|
||||
|
||||
reg.u32 = 0;
|
||||
reg.bits.reformat_enable = 1;
|
||||
reg.bits.reformat_num_pixels = dev->w * 2 - 1;
|
||||
reg.bits.reformat_num_lines = dev->h - 1;
|
||||
reg.bits.reformat_pixel_reorder = data_type;
|
||||
reg_addr = dev->base + ISP_BASE_ADDR_STREAM_ROUTER +
|
||||
STREAM_ROUTER_REFORMAT_REG(6);
|
||||
REG_SET(reg_addr, reg.u32);
|
||||
|
||||
reg_addr = dev->base + ISP_BASE_ADDR_STREAM_ROUTER +
|
||||
STREAM_ROUTER_REFORMAT_MINSPACE_REG(6);
|
||||
REG_SET(reg_addr, (0x1F << 0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void isp_sr_go(struct isp_device *dev, unsigned int go_bit)
|
||||
{
|
||||
char __iomem *reg_addr;
|
||||
|
||||
reg_addr = dev->base + ISP_BASE_ADDR_STREAM_ROUTER +
|
||||
STREAM_ROUTER_CSIFILTER_GO_REG;
|
||||
REG_SET(reg_addr, go_bit);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef HISI_ISP_SR_DEF_H
|
||||
#define HISI_ISP_SR_DEF_H
|
||||
|
||||
#include "hisi_isp_core.h"
|
||||
|
||||
int isp_sr_config(struct isp_device *dev);
|
||||
void isp_sr_go(struct isp_device *dev, unsigned int go_bit);
|
||||
#endif /* HISI_ISP_SR_DEF_H */
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef __STREAM_ROUTER_REG_OFFSET_H__
|
||||
#define __STREAM_ROUTER_REG_OFFSET_H__
|
||||
|
||||
#define STREAM_ROUTER_CSIFILTER_A_REG 0x0
|
||||
#define STREAM_ROUTER_CSIFILTER_B_REG 0x4
|
||||
#define STREAM_ROUTER_CSIFILTER_C_REG 0x8
|
||||
#define STREAM_ROUTER_CSIFILTER_GO_REG 0xC
|
||||
#define STREAM_ROUTER_PRESSURE_START_REG 0x10
|
||||
#define STREAM_ROUTER_PRESSURE_STOP_REG 0x14
|
||||
#define STREAM_ROUTER_ID_ROUTER_0_REG 0x18
|
||||
#define STREAM_ROUTER_ID_ROUTER_1_REG 0x1C
|
||||
#define STREAM_ROUTER_REFORMAT_0_REG 0x20
|
||||
#define STREAM_ROUTER_REFORMAT_1_REG 0x28
|
||||
#define STREAM_ROUTER_REFORMAT_2_REG 0x30
|
||||
#define STREAM_ROUTER_REFORMAT_3_REG 0x38
|
||||
#define STREAM_ROUTER_REFORMAT_4_REG 0x40
|
||||
#define STREAM_ROUTER_REFORMAT_5_REG 0x48
|
||||
#define STREAM_ROUTER_REFORMAT_6_REG 0x50
|
||||
#define STREAM_ROUTER_REFORMAT_7_REG 0x58
|
||||
#define STREAM_ROUTER_REFORMAT_MINSPACE_0_REG 0x24
|
||||
#define STREAM_ROUTER_REFORMAT_MINSPACE_1_REG 0x2C
|
||||
#define STREAM_ROUTER_REFORMAT_MINSPACE_2_REG 0x34
|
||||
#define STREAM_ROUTER_REFORMAT_MINSPACE_3_REG 0x3C
|
||||
#define STREAM_ROUTER_REFORMAT_MINSPACE_4_REG 0x44
|
||||
#define STREAM_ROUTER_REFORMAT_MINSPACE_5_REG 0x4C
|
||||
#define STREAM_ROUTER_REFORMAT_MINSPACE_6_REG 0x54
|
||||
#define STREAM_ROUTER_REFORMAT_MINSPACE_7_REG 0x5C
|
||||
#define STREAM_ROUTER_EOL_CNT_REG 0x60
|
||||
#define STREAM_ROUTER_DPCM_0_REG 0x78
|
||||
#define STREAM_ROUTER_DPCM_1_REG 0x7C
|
||||
#define STREAM_ROUTER_DPCM_2_REG 0x80
|
||||
#define STREAM_ROUTER_VP_ROUTER_0_REG 0x90
|
||||
#define STREAM_ROUTER_VP_ROUTER_1_REG 0x94
|
||||
#define STREAM_ROUTER_VP_ROUTER_2_REG 0x98
|
||||
#define STREAM_ROUTER_VP_ROUTER_3_REG 0x9C
|
||||
#define STREAM_ROUTER_PIXFRAG_CONVERT_REG 0xA0
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,753 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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 "ov5640_main.h"
|
||||
|
||||
#define OV5640_MAIN_VOLTAGE_ANALOG 2800000
|
||||
#define OV5640_MAIN_VOLTAGE_DIGITAL_CORE 1500000
|
||||
#define OV5640_MAIN_VOLTAGE_DIGITAL_IO 1800000
|
||||
|
||||
#define OV5640_MAIN_SYSTEM_CTRL0 0x3008
|
||||
#define OV5640_MAIN_SYSTEM_CTRL0_START 0x02
|
||||
#define OV5640_MAIN_SYSTEM_CTRL0_STOP 0x42
|
||||
#define OV5640_MAIN_CHIP_ID_HIGH_REG 0x300a
|
||||
#define OV5640_MAIN_CHIP_ID_HIGH 0x56
|
||||
#define OV5640_MAIN_CHIP_ID_LOW_REG 0x300b
|
||||
#define OV5640_MAIN_CHIP_ID_LOW 0x40
|
||||
#define OV5640_MAIN_AWB_MANUAL_CONTROL 0x3406
|
||||
#define OV5640_MAIN_AWB_MANUAL_ENABLE BIT(0)
|
||||
#define OV5640_MAIN_AEC_PK_MANUAL 0x3503
|
||||
#define OV5640_MAIN_AEC_MANUAL_ENABLE BIT(0)
|
||||
#define OV5640_MAIN_AGC_MANUAL_ENABLE BIT(1)
|
||||
#define OV5640_MAIN_TIMING_TC_REG20 0x3820
|
||||
#define OV5640_MAIN_SENSOR_VFLIP BIT(1)
|
||||
#define OV5640_MAIN_ISP_VFLIP BIT(2)
|
||||
#define OV5640_MAIN_TIMING_TC_REG21 0x3821
|
||||
#define OV5640_MAIN_ISP_MIRROR BIT(2)
|
||||
#define OV5640_MAIN_SENSOR_MIRROR BIT(1)
|
||||
#define OV5640_MAIN_PRE_ISP_TEST_SETTING_1 0x503d
|
||||
#define OV5640_MAIN_SDE_SAT_U 0x5583
|
||||
#define OV5640_MAIN_SDE_SAT_V 0x5584
|
||||
|
||||
enum ov5640_main_mode {
|
||||
ov5640_main_mode_min = 0,
|
||||
ov5640_main_mode_1080p_1920_1080 = 0,
|
||||
ov5640_main_mode_full_2592_1944 = 1,
|
||||
ov5640_main_mode_max = 1,
|
||||
};
|
||||
|
||||
struct reg_value {
|
||||
u16 reg;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
struct ov5640_main_mode_info {
|
||||
enum ov5640_main_mode mode;
|
||||
u32 width;
|
||||
u32 height;
|
||||
struct reg_value *init_data_ptr;
|
||||
u32 init_data_size;
|
||||
};
|
||||
|
||||
static struct reg_value ov5640_main_global_init_setting[] = {
|
||||
{ 0x3103, 0x11 },
|
||||
{ 0x3008, 0x82 },
|
||||
{ 0x3008, 0x42 },
|
||||
{ 0x3103, 0x03 },
|
||||
{ 0x3017, 0x00 },
|
||||
{ 0x3018, 0x00 },
|
||||
{ 0x3034, 0x18 },
|
||||
{ 0x3035, 0x11 },
|
||||
{ 0x3036, 0x54 },
|
||||
{ 0x3037, 0x13 },
|
||||
{ 0x3108, 0x01 },
|
||||
{ 0x3630, 0x36 },
|
||||
{ 0x3631, 0x0e },
|
||||
{ 0x3632, 0xe2 },
|
||||
{ 0x3633, 0x12 },
|
||||
{ 0x3621, 0xe0 },
|
||||
{ 0x3704, 0xa0 },
|
||||
{ 0x3703, 0x5a },
|
||||
{ 0x3715, 0x78 },
|
||||
{ 0x3717, 0x01 },
|
||||
{ 0x370b, 0x60 },
|
||||
{ 0x3705, 0x1a },
|
||||
{ 0x3905, 0x02 },
|
||||
{ 0x3906, 0x10 },
|
||||
{ 0x3901, 0x0a },
|
||||
{ 0x3731, 0x12 },
|
||||
{ 0x3600, 0x08 },
|
||||
{ 0x3601, 0x33 },
|
||||
{ 0x302d, 0x60 },
|
||||
{ 0x3620, 0x52 },
|
||||
{ 0x371b, 0x20 },
|
||||
{ 0x471c, 0x50 },
|
||||
{ 0x3a13, 0x43 },
|
||||
{ 0x3a18, 0x00 },
|
||||
{ 0x3a19, 0xf8 },
|
||||
{ 0x3635, 0x13 },
|
||||
{ 0x3636, 0x03 },
|
||||
{ 0x3634, 0x40 },
|
||||
{ 0x3622, 0x01 },
|
||||
{ 0x3c01, 0x34 },
|
||||
{ 0x3c04, 0x28 },
|
||||
{ 0x3c05, 0x98 },
|
||||
{ 0x3c06, 0x00 },
|
||||
{ 0x3c07, 0x07 },
|
||||
{ 0x3c08, 0x00 },
|
||||
{ 0x3c09, 0x1c },
|
||||
{ 0x3c0a, 0x9c },
|
||||
{ 0x3c0b, 0x40 },
|
||||
{ 0x3820, 0x40 },
|
||||
{ 0x3821, 0x06 },
|
||||
{ 0x3814, 0x11 },
|
||||
{ 0x3815, 0x11 },
|
||||
{ 0x3810, 0x00 },
|
||||
{ 0x3811, 0x10 },
|
||||
{ 0x3812, 0x00 },
|
||||
{ 0x3813, 0x04 },
|
||||
{ 0x3618, 0x04 },
|
||||
{ 0x3612, 0x2b },
|
||||
{ 0x3708, 0x63 },
|
||||
{ 0x3709, 0x12 },
|
||||
{ 0x370c, 0x00 },
|
||||
{ 0x4001, 0x02 },
|
||||
{ 0x4004, 0x06 },
|
||||
{ 0x4050, 0x6e },
|
||||
{ 0x4051, 0x8f },
|
||||
{ 0x3000, 0x00 },
|
||||
{ 0x3002, 0x1c },
|
||||
{ 0x3004, 0xff },
|
||||
{ 0x3006, 0xc3 },
|
||||
{ 0x300e, 0x45 },
|
||||
{ 0x302e, 0x08 },
|
||||
{ 0x4300, 0x32 },
|
||||
{ 0x4837, 0x0a },
|
||||
{ 0x501f, 0x00 },
|
||||
{ 0x4713, 0x02 },
|
||||
{ 0x4407, 0x04 },
|
||||
{ 0x440e, 0x00 },
|
||||
{ 0x460b, 0x37 },
|
||||
{ 0x460c, 0x20 },
|
||||
{ 0x5000, 0xa7 },
|
||||
{ 0x5001, 0x83 },
|
||||
{ 0x5180, 0xff },
|
||||
{ 0x5181, 0xf2 },
|
||||
{ 0x5182, 0x00 },
|
||||
{ 0x5183, 0x14 },
|
||||
{ 0x5184, 0x25 },
|
||||
{ 0x5185, 0x24 },
|
||||
{ 0x5186, 0x09 },
|
||||
{ 0x5187, 0x09 },
|
||||
{ 0x5188, 0x09 },
|
||||
{ 0x5189, 0x75 },
|
||||
{ 0x518a, 0x54 },
|
||||
{ 0x518b, 0xe0 },
|
||||
{ 0x518c, 0xb2 },
|
||||
{ 0x518d, 0x42 },
|
||||
{ 0x518e, 0x3d },
|
||||
{ 0x518f, 0x56 },
|
||||
{ 0x5190, 0x46 },
|
||||
{ 0x5191, 0xf8 },
|
||||
{ 0x5192, 0x04 },
|
||||
{ 0x5193, 0x70 },
|
||||
{ 0x5194, 0xf0 },
|
||||
{ 0x5195, 0xf0 },
|
||||
{ 0x5196, 0x03 },
|
||||
{ 0x5197, 0x01 },
|
||||
{ 0x5198, 0x04 },
|
||||
{ 0x5199, 0x12 },
|
||||
{ 0x519a, 0x04 },
|
||||
{ 0x519b, 0x00 },
|
||||
{ 0x519c, 0x06 },
|
||||
{ 0x519d, 0x82 },
|
||||
{ 0x519e, 0x38 },
|
||||
{ 0x5381, 0x1e },
|
||||
{ 0x5382, 0x5b },
|
||||
{ 0x5383, 0x08 },
|
||||
{ 0x5384, 0x0a },
|
||||
{ 0x5385, 0x7e },
|
||||
{ 0x5386, 0x88 },
|
||||
{ 0x5387, 0x7c },
|
||||
{ 0x5388, 0x6c },
|
||||
{ 0x5389, 0x10 },
|
||||
{ 0x538a, 0x01 },
|
||||
{ 0x538b, 0x98 },
|
||||
{ 0x5300, 0x08 },
|
||||
{ 0x5301, 0x30 },
|
||||
{ 0x5302, 0x10 },
|
||||
{ 0x5303, 0x00 },
|
||||
{ 0x5304, 0x08 },
|
||||
{ 0x5305, 0x30 },
|
||||
{ 0x5306, 0x08 },
|
||||
{ 0x5307, 0x16 },
|
||||
{ 0x5309, 0x08 },
|
||||
{ 0x530a, 0x30 },
|
||||
{ 0x530b, 0x04 },
|
||||
{ 0x530c, 0x06 },
|
||||
{ 0x5480, 0x01 },
|
||||
{ 0x5481, 0x08 },
|
||||
{ 0x5482, 0x14 },
|
||||
{ 0x5483, 0x28 },
|
||||
{ 0x5484, 0x51 },
|
||||
{ 0x5485, 0x65 },
|
||||
{ 0x5486, 0x71 },
|
||||
{ 0x5487, 0x7d },
|
||||
{ 0x5488, 0x87 },
|
||||
{ 0x5489, 0x91 },
|
||||
{ 0x548a, 0x9a },
|
||||
{ 0x548b, 0xaa },
|
||||
{ 0x548c, 0xb8 },
|
||||
{ 0x548d, 0xcd },
|
||||
{ 0x548e, 0xdd },
|
||||
{ 0x548f, 0xea },
|
||||
{ 0x5490, 0x1d },
|
||||
{ 0x5580, 0x02 },
|
||||
{ 0x5583, 0x40 },
|
||||
{ 0x5584, 0x10 },
|
||||
{ 0x5589, 0x10 },
|
||||
{ 0x558a, 0x00 },
|
||||
{ 0x558b, 0xf8 },
|
||||
{ 0x5800, 0x23 },
|
||||
{ 0x5801, 0x14 },
|
||||
{ 0x5802, 0x0f },
|
||||
{ 0x5803, 0x0f },
|
||||
{ 0x5804, 0x12 },
|
||||
{ 0x5805, 0x26 },
|
||||
{ 0x5806, 0x0c },
|
||||
{ 0x5807, 0x08 },
|
||||
{ 0x5808, 0x05 },
|
||||
{ 0x5809, 0x05 },
|
||||
{ 0x580a, 0x08 },
|
||||
{ 0x580b, 0x0d },
|
||||
{ 0x580c, 0x08 },
|
||||
{ 0x580d, 0x03 },
|
||||
{ 0x580e, 0x00 },
|
||||
{ 0x580f, 0x00 },
|
||||
{ 0x5810, 0x03 },
|
||||
{ 0x5811, 0x09 },
|
||||
{ 0x5812, 0x07 },
|
||||
{ 0x5813, 0x03 },
|
||||
{ 0x5814, 0x00 },
|
||||
{ 0x5815, 0x01 },
|
||||
{ 0x5816, 0x03 },
|
||||
{ 0x5817, 0x08 },
|
||||
{ 0x5818, 0x0d },
|
||||
{ 0x5819, 0x08 },
|
||||
{ 0x581a, 0x05 },
|
||||
{ 0x581b, 0x06 },
|
||||
{ 0x581c, 0x08 },
|
||||
{ 0x581d, 0x0e },
|
||||
{ 0x581e, 0x29 },
|
||||
{ 0x581f, 0x17 },
|
||||
{ 0x5820, 0x11 },
|
||||
{ 0x5821, 0x11 },
|
||||
{ 0x5822, 0x15 },
|
||||
{ 0x5823, 0x28 },
|
||||
{ 0x5824, 0x46 },
|
||||
{ 0x5825, 0x26 },
|
||||
{ 0x5826, 0x08 },
|
||||
{ 0x5827, 0x26 },
|
||||
{ 0x5828, 0x64 },
|
||||
{ 0x5829, 0x26 },
|
||||
{ 0x582a, 0x24 },
|
||||
{ 0x582b, 0x22 },
|
||||
{ 0x582c, 0x24 },
|
||||
{ 0x582d, 0x24 },
|
||||
{ 0x582e, 0x06 },
|
||||
{ 0x582f, 0x22 },
|
||||
{ 0x5830, 0x40 },
|
||||
{ 0x5831, 0x42 },
|
||||
{ 0x5832, 0x24 },
|
||||
{ 0x5833, 0x26 },
|
||||
{ 0x5834, 0x24 },
|
||||
{ 0x5835, 0x22 },
|
||||
{ 0x5836, 0x22 },
|
||||
{ 0x5837, 0x26 },
|
||||
{ 0x5838, 0x44 },
|
||||
{ 0x5839, 0x24 },
|
||||
{ 0x583a, 0x26 },
|
||||
{ 0x583b, 0x28 },
|
||||
{ 0x583c, 0x42 },
|
||||
{ 0x583d, 0xce },
|
||||
{ 0x5025, 0x00 },
|
||||
{ 0x3a0f, 0x30 },
|
||||
{ 0x3a10, 0x28 },
|
||||
{ 0x3a1b, 0x30 },
|
||||
{ 0x3a1e, 0x26 },
|
||||
{ 0x3a11, 0x60 },
|
||||
{ 0x3a1f, 0x14 },
|
||||
};
|
||||
|
||||
static struct reg_value ov5640_main_setting_1080P[] = {
|
||||
{ 0x3800, 0x01 },
|
||||
{ 0x3801, 0x50 },
|
||||
{ 0x3802, 0x01 },
|
||||
{ 0x3803, 0xb2 },
|
||||
{ 0x3804, 0x08 },
|
||||
{ 0x3805, 0xef },
|
||||
{ 0x3806, 0x05 },
|
||||
{ 0x3807, 0xf1 },
|
||||
{ 0x3808, 0x07 },
|
||||
{ 0x3809, 0x80 },
|
||||
{ 0x380a, 0x04 },
|
||||
{ 0x380b, 0x38 },
|
||||
{ 0x380c, 0x09 },
|
||||
{ 0x380d, 0xc4 },
|
||||
{ 0x380e, 0x04 },
|
||||
{ 0x380f, 0x60 },
|
||||
{ 0x3a02, 0x04 },
|
||||
{ 0x3a03, 0x60 },
|
||||
{ 0x3a08, 0x01 },
|
||||
{ 0x3a09, 0x50 },
|
||||
{ 0x3a0a, 0x01 },
|
||||
{ 0x3a0b, 0x18 },
|
||||
{ 0x3a0e, 0x03 },
|
||||
{ 0x3a0d, 0x04 },
|
||||
{ 0x3a14, 0x04 },
|
||||
{ 0x3a15, 0x60 },
|
||||
{ 0x5684, 0x07 },
|
||||
{ 0x5685, 0xa0 },
|
||||
{ 0x5686, 0x04 },
|
||||
{ 0x5687, 0x40 },
|
||||
{ 0x3824, 0x04 },
|
||||
};
|
||||
|
||||
static struct reg_value ov5640_main_setting_full[] = {
|
||||
{ 0x3800, 0x00 },
|
||||
{ 0x3801, 0x00 },
|
||||
{ 0x3802, 0x00 },
|
||||
{ 0x3803, 0x00 },
|
||||
{ 0x3804, 0x0a },
|
||||
{ 0x3805, 0x3f },
|
||||
{ 0x3806, 0x07 },
|
||||
{ 0x3807, 0x96 },
|
||||
{ 0x3808, 0x0a },
|
||||
{ 0x3809, 0x20 },
|
||||
{ 0x380a, 0x07 },
|
||||
{ 0x380b, 0x98 },
|
||||
{ 0x380c, 0x0b },
|
||||
{ 0x380d, 0x1c },
|
||||
{ 0x380e, 0x07 },
|
||||
{ 0x380f, 0xb0 },
|
||||
{ 0x3a02, 0x07 },
|
||||
{ 0x3a03, 0xb0 },
|
||||
{ 0x3a08, 0x01 },
|
||||
{ 0x3a09, 0x27 },
|
||||
{ 0x3a0a, 0x00 },
|
||||
{ 0x3a0b, 0xf6 },
|
||||
{ 0x3a0e, 0x06 },
|
||||
{ 0x3a0d, 0x08 },
|
||||
{ 0x3a14, 0x07 },
|
||||
{ 0x3a15, 0xb0 },
|
||||
{ 0x5684, 0x0a },
|
||||
{ 0x5685, 0x20 },
|
||||
{ 0x5686, 0x07 },
|
||||
{ 0x5687, 0x98 },
|
||||
{ 0x3824, 0x01 },
|
||||
};
|
||||
|
||||
static struct ov5640_main_mode_info
|
||||
ov5640_main_mode_info_data[ov5640_main_mode_max + 1] = {
|
||||
{ov5640_main_mode_1080p_1920_1080, 1920, 1080,
|
||||
ov5640_main_setting_1080P,
|
||||
ARRAY_SIZE(ov5640_main_setting_1080P)},
|
||||
{ov5640_main_mode_full_2592_1944, 2592, 1944,
|
||||
ov5640_main_setting_full,
|
||||
ARRAY_SIZE(ov5640_main_setting_full)},
|
||||
};
|
||||
|
||||
static int ov5640_main_regulators_enable(struct isp_device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (dev->io_regulator) {
|
||||
ret = regulator_enable(dev->io_regulator);
|
||||
if (ret < 0) {
|
||||
ISP_ERR("set io voltage failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ov5640_main_regulators_disable(struct isp_device *dev)
|
||||
{
|
||||
if (dev->io_regulator)
|
||||
regulator_disable(dev->io_regulator);
|
||||
}
|
||||
|
||||
void __ov5640_main_set_power(struct isp_device *dev, bool on)
|
||||
{
|
||||
if (on) {
|
||||
ov5640_main_regulators_enable(dev);
|
||||
clk_prepare_enable(dev->xclk);
|
||||
usleep_range(5000, 15000);
|
||||
if (dev->pwdn_gpio)
|
||||
gpio_set_value(dev->pwdn_gpio, 0);
|
||||
usleep_range(1000, 2000);
|
||||
if (dev->rst_gpio)
|
||||
gpio_set_value(dev->rst_gpio, 1);
|
||||
msleep(20);
|
||||
} else {
|
||||
if (dev->rst_gpio)
|
||||
gpio_set_value(dev->rst_gpio, 0);
|
||||
if (dev->pwdn_gpio)
|
||||
gpio_set_value(dev->pwdn_gpio, 1);
|
||||
ov5640_main_regulators_disable(dev);
|
||||
clk_disable_unprepare(dev->xclk);
|
||||
}
|
||||
}
|
||||
|
||||
static enum ov5640_main_mode
|
||||
ov5640_main_find_nearest_mode(int width, int height)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = ov5640_main_mode_max; i >= 0; i--) {
|
||||
if (ov5640_main_mode_info_data[i].width <= width &&
|
||||
ov5640_main_mode_info_data[i].height <= height)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < 0)
|
||||
i = 0;
|
||||
|
||||
return (enum ov5640_main_mode)i;
|
||||
}
|
||||
|
||||
static int ov5640_main_set_register_array(struct isp_i2c_client_t *client,
|
||||
struct reg_value *settings,
|
||||
s32 num_settings)
|
||||
{
|
||||
register u16 reg = 0;
|
||||
register u8 val = 0;
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < num_settings; ++i, ++settings) {
|
||||
reg = settings->reg;
|
||||
val = settings->val;
|
||||
|
||||
ret = client->ops->write(client, reg, val);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov5640_main_init(struct isp_i2c_client_t *client)
|
||||
{
|
||||
struct reg_value *settings = NULL;
|
||||
int num_settings = 0;
|
||||
int ret;
|
||||
|
||||
settings = ov5640_main_global_init_setting;
|
||||
num_settings = ARRAY_SIZE(ov5640_main_global_init_setting);
|
||||
ret = ov5640_main_set_register_array(client, settings, num_settings);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov5640_main_change_mode(struct isp_i2c_client_t *client,
|
||||
enum ov5640_main_mode mode)
|
||||
{
|
||||
struct reg_value *settings = NULL;
|
||||
s32 num_settings = 0;
|
||||
int ret = 0;
|
||||
|
||||
settings = ov5640_main_mode_info_data[mode].init_data_ptr;
|
||||
num_settings = ov5640_main_mode_info_data[mode].init_data_size;
|
||||
ret = ov5640_main_set_register_array(client, settings, num_settings);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov5640_main_set_aec_mode(struct isp_i2c_client_t *client,
|
||||
int auto_mode)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
client->ops->read(client, OV5640_MAIN_AEC_PK_MANUAL, &val);
|
||||
if (auto_mode) {
|
||||
val |= OV5640_MAIN_AEC_MANUAL_ENABLE;
|
||||
} else { /* V4L2_EXPOSURE_MANUAL */
|
||||
val &= ~OV5640_MAIN_AEC_MANUAL_ENABLE;
|
||||
}
|
||||
|
||||
return client->ops->write(client, OV5640_MAIN_AEC_PK_MANUAL, val);
|
||||
}
|
||||
|
||||
static int ov5640_main_set_awb(struct isp_i2c_client_t *client, s32 enable_auto)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
client->ops->read(client, OV5640_MAIN_AWB_MANUAL_CONTROL, &val);
|
||||
if (enable_auto)
|
||||
val &= ~OV5640_MAIN_AWB_MANUAL_ENABLE;
|
||||
else
|
||||
val |= OV5640_MAIN_AWB_MANUAL_ENABLE;
|
||||
|
||||
return client->ops->write(client, OV5640_MAIN_AWB_MANUAL_CONTROL, val);
|
||||
}
|
||||
|
||||
int ov5640_main_set_fmt(struct isp_i2c_client_t *client,
|
||||
unsigned int w, unsigned int h)
|
||||
{
|
||||
enum ov5640_main_mode new_mode;
|
||||
|
||||
new_mode = ov5640_main_find_nearest_mode(w, h);
|
||||
|
||||
client->mode = new_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ov5640_main_get_chip_id(struct isp_i2c_client_t *client,
|
||||
unsigned int *chip_id)
|
||||
{
|
||||
int ret;
|
||||
unsigned char chip_id_high, chip_id_low;
|
||||
|
||||
ret = client->ops->read(client,
|
||||
OV5640_MAIN_CHIP_ID_HIGH_REG, &chip_id_high);
|
||||
if (ret || chip_id_high != OV5640_MAIN_CHIP_ID_HIGH) {
|
||||
ISP_ERR("get chip id high[%d] fail\n", chip_id_high);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = client->ops->read(client,
|
||||
OV5640_MAIN_CHIP_ID_LOW_REG, &chip_id_low);
|
||||
if (ret || chip_id_low != OV5640_MAIN_CHIP_ID_LOW) {
|
||||
ISP_ERR("get chip id low[%d] fail\n", chip_id_low);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
*chip_id = (chip_id_high<<8) | chip_id_low;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ov5640_main_stream_on_off(struct isp_i2c_client_t *client, int enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ISP_ERR("enable = %d mode = %d\n", enable, client->mode);
|
||||
|
||||
if (enable) {
|
||||
ret = ov5640_main_change_mode(client, client->mode);
|
||||
if (ret < 0) {
|
||||
ISP_ERR("could not set mode %d\n",
|
||||
client->mode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ov5640_main_set_aec_mode(client, 0);
|
||||
ov5640_main_set_awb(client, 1);
|
||||
client->ops->write(client, OV5640_MAIN_SYSTEM_CTRL0,
|
||||
OV5640_MAIN_SYSTEM_CTRL0_START);
|
||||
} else {
|
||||
client->ops->write(client, OV5640_MAIN_SYSTEM_CTRL0,
|
||||
OV5640_MAIN_SYSTEM_CTRL0_STOP);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ov5640_main_power(struct isp_i2c_client_t *client, int on)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__ov5640_main_set_power(client->isp_dev, !!on);
|
||||
|
||||
if (on) {
|
||||
ret = ov5640_main_init(client);
|
||||
if (ret < 0) {
|
||||
ISP_ERR("could not set init registers\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
client->ops->write(client, OV5640_MAIN_SYSTEM_CTRL0,
|
||||
OV5640_MAIN_SYSTEM_CTRL0_STOP);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov5640_main_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct isp_device *idev = NULL;
|
||||
struct device *device = &pdev->dev;
|
||||
struct device_node *np = device->of_node;
|
||||
int index = 0;
|
||||
unsigned int chip_id = 0;
|
||||
struct isp_i2c_client_t *i2c_client = NULL;
|
||||
|
||||
ISP_INFO("enter!\n");
|
||||
if (pdev->dev.parent)
|
||||
idev = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
if (!idev)
|
||||
return -ENXIO;
|
||||
|
||||
ret = of_property_read_u32(np, "sensor_index", (u32 *)&index);
|
||||
if (ret < 0) {
|
||||
ISP_ERR("no sensor index available\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (idev->sensor[index].probe == true)
|
||||
return 0;
|
||||
|
||||
idev->sensor[index].rst_gpio = of_get_named_gpio(np, "reset-gpio", 0);
|
||||
if (!gpio_is_valid(idev->sensor[index].rst_gpio)) {
|
||||
ISP_ERR("no reset pin available\n");
|
||||
idev->sensor[index].rst_gpio = 0;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
idev->sensor[index].pwdn_gpio = of_get_named_gpio(np, "pwdn-gpio", 0);
|
||||
if (!gpio_is_valid(idev->sensor[index].rst_gpio)) {
|
||||
ISP_ERR("no powerdown pin available\n");
|
||||
idev->sensor[index].rst_gpio = 0;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
ret = devm_gpio_request_one(&pdev->dev,
|
||||
idev->sensor[index].rst_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "sensor-reset");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_gpio_request_one(&pdev->dev,
|
||||
idev->sensor[index].pwdn_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "sensor-pwdn");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
idev->sensor[index].addr = OV5640_MAIN_SLAVE_ID;
|
||||
idev->sensor[index].flag = I2C_ADDR_7BIT;
|
||||
idev->sensor[index].speed_cfg = I2C_SPEED_STD;
|
||||
idev->sensor[index].csi_index = 0;
|
||||
idev->sensor[index].dt = YUV_DT_422_8BITS;
|
||||
idev->sensor[index].pf = DF_2PF8;
|
||||
idev->sensor[index].csi_lane = 2;
|
||||
|
||||
idev->addr = idev->sensor[index].addr;
|
||||
idev->flag = idev->sensor[index].flag;
|
||||
idev->speed_cfg = idev->sensor[index].speed_cfg;
|
||||
idev->csi_index = idev->sensor[index].csi_index;
|
||||
idev->dt = idev->sensor[index].dt;
|
||||
idev->pf = idev->sensor[index].pf;
|
||||
idev->csi_lane = idev->sensor[index].csi_lane;
|
||||
idev->pwdn_gpio = idev->sensor[index].pwdn_gpio;
|
||||
idev->rst_gpio = idev->sensor[index].rst_gpio;
|
||||
|
||||
isp_ispss_enable_clock(idev);
|
||||
|
||||
mdelay(100);
|
||||
|
||||
isp_ispss_reset_all(idev);
|
||||
|
||||
mdelay(100);
|
||||
|
||||
idev->client = create_isp_i2c_client(idev);
|
||||
if (!idev->client)
|
||||
return -ENODEV;
|
||||
|
||||
i2c_client = idev->client;
|
||||
ret = i2c_client->ops->open(i2c_client);
|
||||
if (ret) {
|
||||
destroy_isp_i2c_client(i2c_client);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ov5640_main_power(i2c_client, 1);
|
||||
ov5640_main_get_chip_id(i2c_client, &chip_id);
|
||||
ov5640_main_power(i2c_client, 0);
|
||||
i2c_client->ops->close(i2c_client);
|
||||
destroy_isp_i2c_client(i2c_client);
|
||||
ISP_ERR("chip id is 0x%x\n", chip_id);
|
||||
if (chip_id != 0x5640) {
|
||||
ISP_ERR("chip id is 0x%x, probe failed\n", chip_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
idev->sensor[index].probe = true;
|
||||
idev->sensor[index].camera_sensor_power = ov5640_main_power;
|
||||
idev->sensor[index].camera_sensor_set_fmt = ov5640_main_set_fmt;
|
||||
idev->sensor[index].camera_stream_on_off = ov5640_main_stream_on_off;
|
||||
|
||||
ISP_INFO("exit!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov5640_main_remove(struct platform_device *pdev)
|
||||
{
|
||||
ISP_INFO("enter!\n");
|
||||
|
||||
|
||||
ISP_INFO("exit!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ov5640_main_match_table[] = {
|
||||
{
|
||||
.compatible = "hisilicon,ov5640_main",
|
||||
.data = NULL,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ov5640_main_match_table);
|
||||
|
||||
static struct platform_driver ov5640_main_driver = {
|
||||
.probe = ov5640_main_probe,
|
||||
.remove = ov5640_main_remove,
|
||||
.driver = {
|
||||
.name = "hisi-ov5640_main",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(ov5640_main_match_table),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ov5640_main_module_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ISP_INFO("enter!\n");
|
||||
|
||||
ret = platform_driver_register(&ov5640_main_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ISP_INFO("exit!\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ov5640_main_module_exit(void)
|
||||
{
|
||||
ISP_INFO("enter!\n");
|
||||
|
||||
platform_driver_unregister(&ov5640_main_driver);
|
||||
|
||||
ISP_INFO("exit!\n");
|
||||
}
|
||||
|
||||
late_initcall(ov5640_main_module_init);
|
||||
module_exit(ov5640_main_module_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Hisilicon Isp Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef HISI_OV5640_MAIN_H
|
||||
#define HISI_OV5640_MAIN_H
|
||||
|
||||
#include "hisi_isp_core.h"
|
||||
#include "hisi_isp_i2c.h"
|
||||
#include "hisi_isp_common.h"
|
||||
#include "hisi_isp_cvdr.h"
|
||||
|
||||
#define OV5640_MAIN_SLAVE_ID 0x78
|
||||
|
||||
#endif /* HISI_OV5640_MAIN_H */
|
||||
@@ -0,0 +1,751 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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 "ov5640_sub.h"
|
||||
|
||||
#define OV5640_SUB_VOLTAGE_ANALOG 2800000
|
||||
#define OV5640_SUB_VOLTAGE_DIGITAL_CORE 1500000
|
||||
#define OV5640_SUB_VOLTAGE_DIGITAL_IO 1800000
|
||||
|
||||
#define OV5640_SUB_SYSTEM_CTRL0 0x3008
|
||||
#define OV5640_SUB_SYSTEM_CTRL0_START 0x02
|
||||
#define OV5640_SUB_SYSTEM_CTRL0_STOP 0x42
|
||||
#define OV5640_SUB_CHIP_ID_HIGH_REG 0x300a
|
||||
#define OV5640_SUB_CHIP_ID_HIGH 0x56
|
||||
#define OV5640_SUB_CHIP_ID_LOW_REG 0x300b
|
||||
#define OV5640_SUB_CHIP_ID_LOW 0x40
|
||||
#define OV5640_SUB_AWB_MANUAL_CONTROL 0x3406
|
||||
#define OV5640_SUB_AWB_MANUAL_ENABLE BIT(0)
|
||||
#define OV5640_SUB_AEC_PK_MANUAL 0x3503
|
||||
#define OV5640_SUB_AEC_MANUAL_ENABLE BIT(0)
|
||||
#define OV5640_SUB_AGC_MANUAL_ENABLE BIT(1)
|
||||
#define OV5640_SUB_TIMING_TC_REG20 0x3820
|
||||
#define OV5640_SUB_SENSOR_VFLIP BIT(1)
|
||||
#define OV5640_SUB_ISP_VFLIP BIT(2)
|
||||
#define OV5640_SUB_TIMING_TC_REG21 0x3821
|
||||
#define OV5640_SUB_ISP_MIRROR BIT(2)
|
||||
#define OV5640_SUB_SENSOR_MIRROR BIT(1)
|
||||
#define OV5640_SUB_PRE_ISP_TEST_SETTING_1 0x503d
|
||||
#define OV5640_SUB_SDE_SAT_U 0x5583
|
||||
#define OV5640_SUB_SDE_SAT_V 0x5584
|
||||
|
||||
enum ov5640_sub_mode {
|
||||
ov5640_sub_mode_min = 0,
|
||||
ov5640_sub_mode_1080p_1920_1080 = 0,
|
||||
ov5640_sub_mode_full_2592_1944 = 1,
|
||||
ov5640_sub_mode_max = 1,
|
||||
};
|
||||
|
||||
struct reg_value {
|
||||
u16 reg;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
struct ov5640_sub_mode_info {
|
||||
enum ov5640_sub_mode mode;
|
||||
u32 width;
|
||||
u32 height;
|
||||
struct reg_value *init_data_ptr;
|
||||
u32 init_data_size;
|
||||
};
|
||||
|
||||
static struct reg_value ov5640_sub_global_init_setting[] = {
|
||||
{ 0x3103, 0x11 },
|
||||
{ 0x3008, 0x82 },
|
||||
{ 0x3008, 0x42 },
|
||||
{ 0x3103, 0x03 },
|
||||
{ 0x3017, 0x00 },
|
||||
{ 0x3018, 0x00 },
|
||||
{ 0x3034, 0x18 },
|
||||
{ 0x3035, 0x11 },
|
||||
{ 0x3036, 0x54 },
|
||||
{ 0x3037, 0x13 },
|
||||
{ 0x3108, 0x01 },
|
||||
{ 0x3630, 0x36 },
|
||||
{ 0x3631, 0x0e },
|
||||
{ 0x3632, 0xe2 },
|
||||
{ 0x3633, 0x12 },
|
||||
{ 0x3621, 0xe0 },
|
||||
{ 0x3704, 0xa0 },
|
||||
{ 0x3703, 0x5a },
|
||||
{ 0x3715, 0x78 },
|
||||
{ 0x3717, 0x01 },
|
||||
{ 0x370b, 0x60 },
|
||||
{ 0x3705, 0x1a },
|
||||
{ 0x3905, 0x02 },
|
||||
{ 0x3906, 0x10 },
|
||||
{ 0x3901, 0x0a },
|
||||
{ 0x3731, 0x12 },
|
||||
{ 0x3600, 0x08 },
|
||||
{ 0x3601, 0x33 },
|
||||
{ 0x302d, 0x60 },
|
||||
{ 0x3620, 0x52 },
|
||||
{ 0x371b, 0x20 },
|
||||
{ 0x471c, 0x50 },
|
||||
{ 0x3a13, 0x43 },
|
||||
{ 0x3a18, 0x00 },
|
||||
{ 0x3a19, 0xf8 },
|
||||
{ 0x3635, 0x13 },
|
||||
{ 0x3636, 0x03 },
|
||||
{ 0x3634, 0x40 },
|
||||
{ 0x3622, 0x01 },
|
||||
{ 0x3c01, 0x34 },
|
||||
{ 0x3c04, 0x28 },
|
||||
{ 0x3c05, 0x98 },
|
||||
{ 0x3c06, 0x00 },
|
||||
{ 0x3c07, 0x07 },
|
||||
{ 0x3c08, 0x00 },
|
||||
{ 0x3c09, 0x1c },
|
||||
{ 0x3c0a, 0x9c },
|
||||
{ 0x3c0b, 0x40 },
|
||||
{ 0x3820, 0x40 },
|
||||
{ 0x3821, 0x06 },
|
||||
{ 0x3814, 0x11 },
|
||||
{ 0x3815, 0x11 },
|
||||
{ 0x3810, 0x00 },
|
||||
{ 0x3811, 0x10 },
|
||||
{ 0x3812, 0x00 },
|
||||
{ 0x3813, 0x04 },
|
||||
{ 0x3618, 0x04 },
|
||||
{ 0x3612, 0x2b },
|
||||
{ 0x3708, 0x63 },
|
||||
{ 0x3709, 0x12 },
|
||||
{ 0x370c, 0x00 },
|
||||
{ 0x4001, 0x02 },
|
||||
{ 0x4004, 0x06 },
|
||||
{ 0x4050, 0x6e },
|
||||
{ 0x4051, 0x8f },
|
||||
{ 0x3000, 0x00 },
|
||||
{ 0x3002, 0x1c },
|
||||
{ 0x3004, 0xff },
|
||||
{ 0x3006, 0xc3 },
|
||||
{ 0x300e, 0x45 },
|
||||
{ 0x302e, 0x08 },
|
||||
{ 0x4300, 0x32 },
|
||||
{ 0x4837, 0x0a },
|
||||
{ 0x501f, 0x00 },
|
||||
{ 0x4713, 0x02 },
|
||||
{ 0x4407, 0x04 },
|
||||
{ 0x440e, 0x00 },
|
||||
{ 0x460b, 0x37 },
|
||||
{ 0x460c, 0x20 },
|
||||
{ 0x5000, 0xa7 },
|
||||
{ 0x5001, 0x83 },
|
||||
{ 0x5180, 0xff },
|
||||
{ 0x5181, 0xf2 },
|
||||
{ 0x5182, 0x00 },
|
||||
{ 0x5183, 0x14 },
|
||||
{ 0x5184, 0x25 },
|
||||
{ 0x5185, 0x24 },
|
||||
{ 0x5186, 0x09 },
|
||||
{ 0x5187, 0x09 },
|
||||
{ 0x5188, 0x09 },
|
||||
{ 0x5189, 0x75 },
|
||||
{ 0x518a, 0x54 },
|
||||
{ 0x518b, 0xe0 },
|
||||
{ 0x518c, 0xb2 },
|
||||
{ 0x518d, 0x42 },
|
||||
{ 0x518e, 0x3d },
|
||||
{ 0x518f, 0x56 },
|
||||
{ 0x5190, 0x46 },
|
||||
{ 0x5191, 0xf8 },
|
||||
{ 0x5192, 0x04 },
|
||||
{ 0x5193, 0x70 },
|
||||
{ 0x5194, 0xf0 },
|
||||
{ 0x5195, 0xf0 },
|
||||
{ 0x5196, 0x03 },
|
||||
{ 0x5197, 0x01 },
|
||||
{ 0x5198, 0x04 },
|
||||
{ 0x5199, 0x12 },
|
||||
{ 0x519a, 0x04 },
|
||||
{ 0x519b, 0x00 },
|
||||
{ 0x519c, 0x06 },
|
||||
{ 0x519d, 0x82 },
|
||||
{ 0x519e, 0x38 },
|
||||
{ 0x5381, 0x1e },
|
||||
{ 0x5382, 0x5b },
|
||||
{ 0x5383, 0x08 },
|
||||
{ 0x5384, 0x0a },
|
||||
{ 0x5385, 0x7e },
|
||||
{ 0x5386, 0x88 },
|
||||
{ 0x5387, 0x7c },
|
||||
{ 0x5388, 0x6c },
|
||||
{ 0x5389, 0x10 },
|
||||
{ 0x538a, 0x01 },
|
||||
{ 0x538b, 0x98 },
|
||||
{ 0x5300, 0x08 },
|
||||
{ 0x5301, 0x30 },
|
||||
{ 0x5302, 0x10 },
|
||||
{ 0x5303, 0x00 },
|
||||
{ 0x5304, 0x08 },
|
||||
{ 0x5305, 0x30 },
|
||||
{ 0x5306, 0x08 },
|
||||
{ 0x5307, 0x16 },
|
||||
{ 0x5309, 0x08 },
|
||||
{ 0x530a, 0x30 },
|
||||
{ 0x530b, 0x04 },
|
||||
{ 0x530c, 0x06 },
|
||||
{ 0x5480, 0x01 },
|
||||
{ 0x5481, 0x08 },
|
||||
{ 0x5482, 0x14 },
|
||||
{ 0x5483, 0x28 },
|
||||
{ 0x5484, 0x51 },
|
||||
{ 0x5485, 0x65 },
|
||||
{ 0x5486, 0x71 },
|
||||
{ 0x5487, 0x7d },
|
||||
{ 0x5488, 0x87 },
|
||||
{ 0x5489, 0x91 },
|
||||
{ 0x548a, 0x9a },
|
||||
{ 0x548b, 0xaa },
|
||||
{ 0x548c, 0xb8 },
|
||||
{ 0x548d, 0xcd },
|
||||
{ 0x548e, 0xdd },
|
||||
{ 0x548f, 0xea },
|
||||
{ 0x5490, 0x1d },
|
||||
{ 0x5580, 0x02 },
|
||||
{ 0x5583, 0x40 },
|
||||
{ 0x5584, 0x10 },
|
||||
{ 0x5589, 0x10 },
|
||||
{ 0x558a, 0x00 },
|
||||
{ 0x558b, 0xf8 },
|
||||
{ 0x5800, 0x23 },
|
||||
{ 0x5801, 0x14 },
|
||||
{ 0x5802, 0x0f },
|
||||
{ 0x5803, 0x0f },
|
||||
{ 0x5804, 0x12 },
|
||||
{ 0x5805, 0x26 },
|
||||
{ 0x5806, 0x0c },
|
||||
{ 0x5807, 0x08 },
|
||||
{ 0x5808, 0x05 },
|
||||
{ 0x5809, 0x05 },
|
||||
{ 0x580a, 0x08 },
|
||||
{ 0x580b, 0x0d },
|
||||
{ 0x580c, 0x08 },
|
||||
{ 0x580d, 0x03 },
|
||||
{ 0x580e, 0x00 },
|
||||
{ 0x580f, 0x00 },
|
||||
{ 0x5810, 0x03 },
|
||||
{ 0x5811, 0x09 },
|
||||
{ 0x5812, 0x07 },
|
||||
{ 0x5813, 0x03 },
|
||||
{ 0x5814, 0x00 },
|
||||
{ 0x5815, 0x01 },
|
||||
{ 0x5816, 0x03 },
|
||||
{ 0x5817, 0x08 },
|
||||
{ 0x5818, 0x0d },
|
||||
{ 0x5819, 0x08 },
|
||||
{ 0x581a, 0x05 },
|
||||
{ 0x581b, 0x06 },
|
||||
{ 0x581c, 0x08 },
|
||||
{ 0x581d, 0x0e },
|
||||
{ 0x581e, 0x29 },
|
||||
{ 0x581f, 0x17 },
|
||||
{ 0x5820, 0x11 },
|
||||
{ 0x5821, 0x11 },
|
||||
{ 0x5822, 0x15 },
|
||||
{ 0x5823, 0x28 },
|
||||
{ 0x5824, 0x46 },
|
||||
{ 0x5825, 0x26 },
|
||||
{ 0x5826, 0x08 },
|
||||
{ 0x5827, 0x26 },
|
||||
{ 0x5828, 0x64 },
|
||||
{ 0x5829, 0x26 },
|
||||
{ 0x582a, 0x24 },
|
||||
{ 0x582b, 0x22 },
|
||||
{ 0x582c, 0x24 },
|
||||
{ 0x582d, 0x24 },
|
||||
{ 0x582e, 0x06 },
|
||||
{ 0x582f, 0x22 },
|
||||
{ 0x5830, 0x40 },
|
||||
{ 0x5831, 0x42 },
|
||||
{ 0x5832, 0x24 },
|
||||
{ 0x5833, 0x26 },
|
||||
{ 0x5834, 0x24 },
|
||||
{ 0x5835, 0x22 },
|
||||
{ 0x5836, 0x22 },
|
||||
{ 0x5837, 0x26 },
|
||||
{ 0x5838, 0x44 },
|
||||
{ 0x5839, 0x24 },
|
||||
{ 0x583a, 0x26 },
|
||||
{ 0x583b, 0x28 },
|
||||
{ 0x583c, 0x42 },
|
||||
{ 0x583d, 0xce },
|
||||
{ 0x5025, 0x00 },
|
||||
{ 0x3a0f, 0x30 },
|
||||
{ 0x3a10, 0x28 },
|
||||
{ 0x3a1b, 0x30 },
|
||||
{ 0x3a1e, 0x26 },
|
||||
{ 0x3a11, 0x60 },
|
||||
{ 0x3a1f, 0x14 },
|
||||
};
|
||||
|
||||
static struct reg_value ov5640_sub_setting_1080P[] = {
|
||||
{ 0x3800, 0x01 },
|
||||
{ 0x3801, 0x50 },
|
||||
{ 0x3802, 0x01 },
|
||||
{ 0x3803, 0xb2 },
|
||||
{ 0x3804, 0x08 },
|
||||
{ 0x3805, 0xef },
|
||||
{ 0x3806, 0x05 },
|
||||
{ 0x3807, 0xf1 },
|
||||
{ 0x3808, 0x07 },
|
||||
{ 0x3809, 0x80 },
|
||||
{ 0x380a, 0x04 },
|
||||
{ 0x380b, 0x38 },
|
||||
{ 0x380c, 0x09 },
|
||||
{ 0x380d, 0xc4 },
|
||||
{ 0x380e, 0x04 },
|
||||
{ 0x380f, 0x60 },
|
||||
{ 0x3a02, 0x04 },
|
||||
{ 0x3a03, 0x60 },
|
||||
{ 0x3a08, 0x01 },
|
||||
{ 0x3a09, 0x50 },
|
||||
{ 0x3a0a, 0x01 },
|
||||
{ 0x3a0b, 0x18 },
|
||||
{ 0x3a0e, 0x03 },
|
||||
{ 0x3a0d, 0x04 },
|
||||
{ 0x3a14, 0x04 },
|
||||
{ 0x3a15, 0x60 },
|
||||
{ 0x5684, 0x07 },
|
||||
{ 0x5685, 0xa0 },
|
||||
{ 0x5686, 0x04 },
|
||||
{ 0x5687, 0x40 },
|
||||
{ 0x3824, 0x04 },
|
||||
};
|
||||
|
||||
static struct reg_value ov5640_sub_setting_full[] = {
|
||||
{ 0x3800, 0x00 },
|
||||
{ 0x3801, 0x00 },
|
||||
{ 0x3802, 0x00 },
|
||||
{ 0x3803, 0x00 },
|
||||
{ 0x3804, 0x0a },
|
||||
{ 0x3805, 0x3f },
|
||||
{ 0x3806, 0x07 },
|
||||
{ 0x3807, 0x96 },
|
||||
{ 0x3808, 0x0a },
|
||||
{ 0x3809, 0x20 },
|
||||
{ 0x380a, 0x07 },
|
||||
{ 0x380b, 0x98 },
|
||||
{ 0x380c, 0x0b },
|
||||
{ 0x380d, 0x1c },
|
||||
{ 0x380e, 0x07 },
|
||||
{ 0x380f, 0xb0 },
|
||||
{ 0x3a02, 0x07 },
|
||||
{ 0x3a03, 0xb0 },
|
||||
{ 0x3a08, 0x01 },
|
||||
{ 0x3a09, 0x27 },
|
||||
{ 0x3a0a, 0x00 },
|
||||
{ 0x3a0b, 0xf6 },
|
||||
{ 0x3a0e, 0x06 },
|
||||
{ 0x3a0d, 0x08 },
|
||||
{ 0x3a14, 0x07 },
|
||||
{ 0x3a15, 0xb0 },
|
||||
{ 0x5684, 0x0a },
|
||||
{ 0x5685, 0x20 },
|
||||
{ 0x5686, 0x07 },
|
||||
{ 0x5687, 0x98 },
|
||||
{ 0x3824, 0x01 },
|
||||
};
|
||||
|
||||
static struct ov5640_sub_mode_info
|
||||
ov5640_sub_mode_info_data[ov5640_sub_mode_max + 1] = {
|
||||
{ov5640_sub_mode_1080p_1920_1080, 1920, 1080,
|
||||
ov5640_sub_setting_1080P,
|
||||
ARRAY_SIZE(ov5640_sub_setting_1080P)},
|
||||
{ov5640_sub_mode_full_2592_1944, 2592, 1944,
|
||||
ov5640_sub_setting_full,
|
||||
ARRAY_SIZE(ov5640_sub_setting_full)},
|
||||
};
|
||||
|
||||
static int ov5640_sub_regulators_enable(struct isp_device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (dev->io_regulator) {
|
||||
ret = regulator_enable(dev->io_regulator);
|
||||
if (ret < 0) {
|
||||
ISP_ERR("set io voltage failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ov5640_sub_regulators_disable(struct isp_device *dev)
|
||||
{
|
||||
if (dev->io_regulator)
|
||||
regulator_disable(dev->io_regulator);
|
||||
}
|
||||
|
||||
void __ov5640_sub_set_power(struct isp_device *dev, bool on)
|
||||
{
|
||||
if (on) {
|
||||
|
||||
ov5640_sub_regulators_enable(dev);
|
||||
clk_prepare_enable(dev->xclk1);
|
||||
usleep_range(5000, 15000);
|
||||
if (dev->pwdn_gpio)
|
||||
gpio_set_value(dev->pwdn_gpio, 0);
|
||||
usleep_range(1000, 2000);
|
||||
if (dev->rst_gpio)
|
||||
gpio_set_value(dev->rst_gpio, 1);
|
||||
msleep(20);
|
||||
} else {
|
||||
if (dev->rst_gpio)
|
||||
gpio_set_value(dev->rst_gpio, 0);
|
||||
if (dev->pwdn_gpio)
|
||||
gpio_set_value(dev->pwdn_gpio, 1);
|
||||
ov5640_sub_regulators_disable(dev);
|
||||
clk_disable_unprepare(dev->xclk1);
|
||||
}
|
||||
}
|
||||
|
||||
static enum ov5640_sub_mode ov5640_sub_find_nearest_mode(int width, int height)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = ov5640_sub_mode_max; i >= 0; i--) {
|
||||
if (ov5640_sub_mode_info_data[i].width <= width &&
|
||||
ov5640_sub_mode_info_data[i].height <= height)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < 0)
|
||||
i = 0;
|
||||
|
||||
return (enum ov5640_sub_mode)i;
|
||||
}
|
||||
|
||||
static int ov5640_sub_set_register_array(struct isp_i2c_client_t *client,
|
||||
struct reg_value *settings,
|
||||
s32 num_settings)
|
||||
{
|
||||
register u16 reg = 0;
|
||||
register u8 val = 0;
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < num_settings; ++i, ++settings) {
|
||||
reg = settings->reg;
|
||||
val = settings->val;
|
||||
|
||||
ret = client->ops->write(client, reg, val);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov5640_sub_init(struct isp_i2c_client_t *client)
|
||||
{
|
||||
struct reg_value *settings = NULL;
|
||||
int num_settings = 0;
|
||||
int ret;
|
||||
|
||||
settings = ov5640_sub_global_init_setting;
|
||||
num_settings = ARRAY_SIZE(ov5640_sub_global_init_setting);
|
||||
ret = ov5640_sub_set_register_array(client, settings, num_settings);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ov5640_sub_change_mode(struct isp_i2c_client_t *client,
|
||||
enum ov5640_sub_mode mode)
|
||||
{
|
||||
struct reg_value *settings = NULL;
|
||||
s32 num_settings = 0;
|
||||
int ret = 0;
|
||||
|
||||
settings = ov5640_sub_mode_info_data[mode].init_data_ptr;
|
||||
num_settings = ov5640_sub_mode_info_data[mode].init_data_size;
|
||||
ret = ov5640_sub_set_register_array(client, settings, num_settings);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov5640_sub_set_aec_mode(struct isp_i2c_client_t *client,
|
||||
int auto_mode)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
client->ops->read(client, OV5640_SUB_AEC_PK_MANUAL, &val);
|
||||
if (auto_mode) {
|
||||
val |= OV5640_SUB_AEC_MANUAL_ENABLE;
|
||||
} else { /* V4L2_EXPOSURE_MANUAL */
|
||||
val &= ~OV5640_SUB_AEC_MANUAL_ENABLE;
|
||||
}
|
||||
|
||||
return client->ops->write(client, OV5640_SUB_AEC_PK_MANUAL, val);
|
||||
}
|
||||
|
||||
static int ov5640_sub_set_awb(struct isp_i2c_client_t *client, s32 enable_auto)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
client->ops->read(client, OV5640_SUB_AWB_MANUAL_CONTROL, &val);
|
||||
if (enable_auto)
|
||||
val &= ~OV5640_SUB_AWB_MANUAL_ENABLE;
|
||||
else
|
||||
val |= OV5640_SUB_AWB_MANUAL_ENABLE;
|
||||
|
||||
return client->ops->write(client, OV5640_SUB_AWB_MANUAL_CONTROL, val);
|
||||
}
|
||||
|
||||
int ov5640_sub_set_fmt(struct isp_i2c_client_t *client,
|
||||
unsigned int w, unsigned int h)
|
||||
{
|
||||
enum ov5640_sub_mode new_mode;
|
||||
|
||||
new_mode = ov5640_sub_find_nearest_mode(w, h);
|
||||
|
||||
client->mode = new_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ov5640_sub_get_chip_id(struct isp_i2c_client_t *client,
|
||||
unsigned int *chip_id)
|
||||
{
|
||||
int ret;
|
||||
unsigned char chip_id_high, chip_id_low;
|
||||
|
||||
ret = client->ops->read(client,
|
||||
OV5640_SUB_CHIP_ID_HIGH_REG, &chip_id_high);
|
||||
if (ret || chip_id_high != OV5640_SUB_CHIP_ID_HIGH) {
|
||||
ISP_ERR("get chip id high[%d] fail\n", chip_id_high);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = client->ops->read(client,
|
||||
OV5640_SUB_CHIP_ID_LOW_REG, &chip_id_low);
|
||||
if (ret || chip_id_low != OV5640_SUB_CHIP_ID_LOW) {
|
||||
ISP_ERR("get chip id low[%d] fail\n", chip_id_low);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
*chip_id = (chip_id_high<<8) | chip_id_low;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ov5640_sub_stream_on_off(struct isp_i2c_client_t *client, int enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ISP_ERR("enable = %d mode = %d\n", enable, client->mode);
|
||||
|
||||
if (enable) {
|
||||
ret = ov5640_sub_change_mode(client, client->mode);
|
||||
if (ret < 0) {
|
||||
ISP_ERR("could not set mode %d\n",
|
||||
client->mode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ov5640_sub_set_aec_mode(client, 0);
|
||||
ov5640_sub_set_awb(client, 1);
|
||||
client->ops->write(client, OV5640_SUB_SYSTEM_CTRL0,
|
||||
OV5640_SUB_SYSTEM_CTRL0_START);
|
||||
} else {
|
||||
client->ops->write(client, OV5640_SUB_SYSTEM_CTRL0,
|
||||
OV5640_SUB_SYSTEM_CTRL0_STOP);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ov5640_sub_power(struct isp_i2c_client_t *client, int on)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__ov5640_sub_set_power(client->isp_dev, !!on);
|
||||
|
||||
if (on) {
|
||||
ret = ov5640_sub_init(client);
|
||||
if (ret < 0) {
|
||||
ISP_ERR("could not set init registers\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
client->ops->write(client, OV5640_SUB_SYSTEM_CTRL0,
|
||||
OV5640_SUB_SYSTEM_CTRL0_STOP);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov5640_sub_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct isp_device *idev = NULL;
|
||||
struct device *device = &pdev->dev;
|
||||
struct device_node *np = device->of_node;
|
||||
int index = 0;
|
||||
unsigned int chip_id = 0;
|
||||
struct isp_i2c_client_t *i2c_client = NULL;
|
||||
|
||||
ISP_INFO("enter!\n");
|
||||
if (pdev->dev.parent)
|
||||
idev = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
ret = of_property_read_u32(np, "sensor_index", (u32 *)&index);
|
||||
if (ret < 0) {
|
||||
ISP_ERR("no sensor index available\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (idev->sensor[index].probe == true)
|
||||
return 0;
|
||||
|
||||
idev->sensor[index].rst_gpio = of_get_named_gpio(np, "reset-gpio", 0);
|
||||
if (!gpio_is_valid(idev->sensor[index].rst_gpio)) {
|
||||
ISP_ERR("no reset pin available\n");
|
||||
idev->sensor[index].rst_gpio = 0;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
idev->sensor[index].pwdn_gpio = of_get_named_gpio(np, "pwdn-gpio", 0);
|
||||
if (!gpio_is_valid(idev->sensor[index].rst_gpio)) {
|
||||
ISP_ERR("no powerdown pin available\n");
|
||||
idev->sensor[index].rst_gpio = 0;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
ret = devm_gpio_request_one(&pdev->dev,
|
||||
idev->sensor[index].pwdn_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "sensor-pwdn");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_gpio_request_one(&pdev->dev,
|
||||
idev->sensor[index].rst_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "sensor-reset");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
idev->sensor[index].addr = OV5640_SUB_SLAVE_ID;
|
||||
idev->sensor[index].flag = I2C_ADDR_7BIT;
|
||||
idev->sensor[index].speed_cfg = I2C_SPEED_STD;
|
||||
idev->sensor[index].csi_index = 1;
|
||||
idev->sensor[index].dt = YUV_DT_422_8BITS;
|
||||
idev->sensor[index].pf = DF_2PF8;
|
||||
idev->sensor[index].csi_lane = 2;
|
||||
|
||||
idev->addr = idev->sensor[index].addr;
|
||||
idev->flag = idev->sensor[index].flag;
|
||||
idev->speed_cfg = idev->sensor[index].speed_cfg;
|
||||
idev->csi_index = idev->sensor[index].csi_index;
|
||||
idev->dt = idev->sensor[index].dt;
|
||||
idev->pf = idev->sensor[index].pf;
|
||||
idev->csi_lane = idev->sensor[index].csi_lane;
|
||||
idev->pwdn_gpio = idev->sensor[index].pwdn_gpio;
|
||||
idev->rst_gpio = idev->sensor[index].rst_gpio;
|
||||
|
||||
isp_ispss_enable_clock(idev);
|
||||
|
||||
mdelay(100);
|
||||
|
||||
isp_ispss_reset_all(idev);
|
||||
|
||||
mdelay(100);
|
||||
|
||||
idev->client = create_isp_i2c_client(idev);
|
||||
if (!idev->client)
|
||||
return -ENODEV;
|
||||
|
||||
i2c_client = idev->client;
|
||||
ret = i2c_client->ops->open(i2c_client);
|
||||
if (ret) {
|
||||
destroy_isp_i2c_client(i2c_client);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ov5640_sub_power(i2c_client, 1);
|
||||
ov5640_sub_get_chip_id(i2c_client, &chip_id);
|
||||
ov5640_sub_power(i2c_client, 0);
|
||||
i2c_client->ops->close(i2c_client);
|
||||
destroy_isp_i2c_client(i2c_client);
|
||||
|
||||
if (chip_id != 0x5640) {
|
||||
ISP_ERR("chip id is 0x%x, probe failed\n", chip_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
idev->sensor[index].probe = true;
|
||||
idev->sensor[index].camera_sensor_power = ov5640_sub_power;
|
||||
idev->sensor[index].camera_sensor_set_fmt = ov5640_sub_set_fmt;
|
||||
idev->sensor[index].camera_stream_on_off = ov5640_sub_stream_on_off;
|
||||
|
||||
ISP_INFO("exit!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov5640_sub_remove(struct platform_device *pdev)
|
||||
{
|
||||
ISP_INFO("enter!\n");
|
||||
|
||||
|
||||
ISP_INFO("exit!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ov5640_sub_match_table[] = {
|
||||
{
|
||||
.compatible = "hisilicon,ov5640_sub",
|
||||
.data = NULL,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ov5640_sub_match_table);
|
||||
|
||||
static struct platform_driver ov5640_sub_driver = {
|
||||
.probe = ov5640_sub_probe,
|
||||
.remove = ov5640_sub_remove,
|
||||
.driver = {
|
||||
.name = "hisi-ov5640_sub",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(ov5640_sub_match_table),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ov5640_sub_module_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ISP_INFO("enter!\n");
|
||||
|
||||
ret = platform_driver_register(&ov5640_sub_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ISP_INFO("exit!\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ov5640_sub_module_exit(void)
|
||||
{
|
||||
ISP_INFO("enter!\n");
|
||||
|
||||
platform_driver_unregister(&ov5640_sub_driver);
|
||||
|
||||
ISP_INFO("exit!\n");
|
||||
}
|
||||
|
||||
late_initcall(ov5640_sub_module_init);
|
||||
module_exit(ov5640_sub_module_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Hisilicon Isp Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef HISI_OV5640_SUB_H
|
||||
#define HISI_OV5640_SUB_H
|
||||
|
||||
#include "hisi_isp_core.h"
|
||||
#include "hisi_isp_i2c.h"
|
||||
#include "hisi_isp_common.h"
|
||||
#include "hisi_isp_cvdr.h"
|
||||
|
||||
#define OV5640_SUB_SLAVE_ID 0x78
|
||||
|
||||
#endif /* HISI_OV5640_H */
|
||||
@@ -0,0 +1,839 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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 "ov5645.h"
|
||||
|
||||
#define OV5645_SYSTEM_CTRL0 0x3008
|
||||
#define OV5645_SYSTEM_CTRL0_START 0x02
|
||||
#define OV5645_SYSTEM_CTRL0_STOP 0x42
|
||||
#define OV5645_CHIP_ID_HIGH_REG 0x300A
|
||||
#define OV5645_CHIP_ID_HIGH 0x56
|
||||
#define OV5645_CHIP_ID_LOW_REG 0x300B
|
||||
#define OV5645_CHIP_ID_LOW 0x45
|
||||
#define OV5645_AWB_MANUAL_CONTROL 0x3406
|
||||
#define OV5645_AWB_MANUAL_ENABLE (1 << 0)
|
||||
#define OV5645_AEC_PK_MANUAL 0x3503
|
||||
#define OV5645_AEC_MANUAL_ENABLE (1 << 0)
|
||||
#define OV5645_AGC_MANUAL_ENABLE (1 << 1)
|
||||
#define OV5645_TIMING_TC_REG20 0x3820
|
||||
#define OV5645_SENSOR_VFLIP (1 << 1)
|
||||
#define OV5645_ISP_VFLIP (1 << 2)
|
||||
#define OV5645_TIMING_TC_REG21 0x3821
|
||||
#define OV5645_SENSOR_MIRROR (1 << 1)
|
||||
#define OV5645_PRE_ISP_TEST_SETTING_1 0x503d
|
||||
|
||||
#define OV5645_SDE_SAT_U 0x5583
|
||||
#define OV5645_SDE_SAT_V 0x5584
|
||||
|
||||
enum ov5645_mode {
|
||||
ov5645_mode_min = 0,
|
||||
ov5645_mode_sxga_1280_960 = 0,
|
||||
ov5645_mode_1080p_1920_1080 = 1,
|
||||
ov5645_mode_full_2592_1944 = 2,
|
||||
ov5645_mode_max = 2,
|
||||
};
|
||||
|
||||
struct reg_value {
|
||||
u16 reg;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
struct ov5645_mode_info {
|
||||
enum ov5645_mode mode;
|
||||
u32 width;
|
||||
u32 height;
|
||||
struct reg_value *init_data_ptr;
|
||||
u32 init_data_size;
|
||||
};
|
||||
|
||||
static struct reg_value ov5645_global_init_setting[] = {
|
||||
{0x3103, 0x11,},
|
||||
{0x3008, 0x82,},
|
||||
{0x3008, 0x42,},
|
||||
{0x3103, 0x03,},
|
||||
{0x3503, 0x07,},
|
||||
{0x3002, 0x1c,},
|
||||
{0x3006, 0xc3,},
|
||||
{0x300e, 0x45,},
|
||||
{0x3017, 0x00,},
|
||||
{0x3018, 0x00,},
|
||||
{0x302e, 0x0b,},
|
||||
{0x3037, 0x13,},
|
||||
{0x3108, 0x01,},
|
||||
{0x3611, 0x06,},
|
||||
{0x3500, 0x00,},
|
||||
{0x3501, 0x01,},
|
||||
{0x3502, 0x00,},
|
||||
{0x350a, 0x00,},
|
||||
{0x350b, 0x3f,},
|
||||
{0x3620, 0x33,},
|
||||
{0x3621, 0xe0,},
|
||||
{0x3622, 0x01,},
|
||||
{0x3630, 0x2e,},
|
||||
{0x3631, 0x00,},
|
||||
{0x3632, 0x32,},
|
||||
{0x3633, 0x52,},
|
||||
{0x3634, 0x70,},
|
||||
{0x3635, 0x13,},
|
||||
{0x3636, 0x03,},
|
||||
{0x3703, 0x5a,},
|
||||
{0x3704, 0xa0,},
|
||||
{0x3705, 0x1a,},
|
||||
{0x3709, 0x12,},
|
||||
{0x370b, 0x61,},
|
||||
{0x370f, 0x10,},
|
||||
{0x3715, 0x78,},
|
||||
{0x3717, 0x01,},
|
||||
{0x371b, 0x20,},
|
||||
{0x3731, 0x12,},
|
||||
{0x3901, 0x0a,},
|
||||
{0x3905, 0x02,},
|
||||
{0x3906, 0x10,},
|
||||
{0x3719, 0x86,},
|
||||
{0x3810, 0x00,},
|
||||
{0x3811, 0x10,},
|
||||
{0x3812, 0x00,},
|
||||
{0x3821, 0x01,},
|
||||
{0x3824, 0x01,},
|
||||
{0x3826, 0x03,},
|
||||
{0x3828, 0x08,},
|
||||
{0x3a19, 0xf8,},
|
||||
{0x3c01, 0x34,},
|
||||
{0x3c04, 0x28,},
|
||||
{0x3c05, 0x98,},
|
||||
{0x3c07, 0x07,},
|
||||
{0x3c09, 0xc2,},
|
||||
{0x3c0a, 0x9c,},
|
||||
{0x3c0b, 0x40,},
|
||||
{0x3c01, 0x34,},
|
||||
{0x4001, 0x02,},
|
||||
{0x4514, 0x00,},
|
||||
{0x4520, 0xb0,},
|
||||
{0x460b, 0x37,},
|
||||
{0x460c, 0x20,},
|
||||
{0x4818, 0x01,},
|
||||
{0x481d, 0xf0,},
|
||||
{0x481f, 0x50,},
|
||||
{0x4823, 0x70,},
|
||||
{0x4831, 0x14,},
|
||||
{0x5000, 0xa7,},
|
||||
{0x5001, 0x83,},
|
||||
{0x501d, 0x00,},
|
||||
{0x501f, 0x00,},
|
||||
{0x503d, 0x00,},
|
||||
{0x505c, 0x30,},
|
||||
{0x5181, 0x59,},
|
||||
{0x5183, 0x00,},
|
||||
{0x5191, 0xf0,},
|
||||
{0x5192, 0x03,},
|
||||
{0x5684, 0x10,},
|
||||
{0x5685, 0xa0,},
|
||||
{0x5686, 0x0c,},
|
||||
{0x5687, 0x78,},
|
||||
{0x5a00, 0x08,},
|
||||
{0x5a21, 0x00,},
|
||||
{0x5a24, 0x00,},
|
||||
{0x3008, 0x02,},
|
||||
{0x3503, 0x00,},
|
||||
{0x5180, 0xff,},
|
||||
{0x5181, 0xf2,},
|
||||
{0x5182, 0x00,},
|
||||
{0x5183, 0x14,},
|
||||
{0x5184, 0x25,},
|
||||
{0x5185, 0x24,},
|
||||
{0x5186, 0x09,},
|
||||
{0x5187, 0x09,},
|
||||
{0x5188, 0x0a,},
|
||||
{0x5189, 0x75,},
|
||||
{0x518a, 0x52,},
|
||||
{0x518b, 0xea,},
|
||||
{0x518c, 0xa8,},
|
||||
{0x518d, 0x42,},
|
||||
{0x518e, 0x38,},
|
||||
{0x518f, 0x56,},
|
||||
{0x5190, 0x42,},
|
||||
{0x5191, 0xf8,},
|
||||
{0x5192, 0x04,},
|
||||
{0x5193, 0x70,},
|
||||
{0x5194, 0xf0,},
|
||||
{0x5195, 0xf0,},
|
||||
{0x5196, 0x03,},
|
||||
{0x5197, 0x01,},
|
||||
{0x5198, 0x04,},
|
||||
{0x5199, 0x12,},
|
||||
{0x519a, 0x04,},
|
||||
{0x519b, 0x00,},
|
||||
{0x519c, 0x06,},
|
||||
{0x519d, 0x82,},
|
||||
{0x519e, 0x38,},
|
||||
{0x5381, 0x1e,},
|
||||
{0x5382, 0x5b,},
|
||||
{0x5383, 0x08,},
|
||||
{0x5384, 0x0a,},
|
||||
{0x5385, 0x7e,},
|
||||
{0x5386, 0x88,},
|
||||
{0x5387, 0x7c,},
|
||||
{0x5388, 0x6c,},
|
||||
{0x5389, 0x10,},
|
||||
{0x538a, 0x01,},
|
||||
{0x538b, 0x98,},
|
||||
{0x5300, 0x08,},
|
||||
{0x5301, 0x30,},
|
||||
{0x5302, 0x10,},
|
||||
{0x5303, 0x00,},
|
||||
{0x5304, 0x08,},
|
||||
{0x5305, 0x30,},
|
||||
{0x5306, 0x08,},
|
||||
{0x5307, 0x16,},
|
||||
{0x5309, 0x08,},
|
||||
{0x530a, 0x30,},
|
||||
{0x530b, 0x04,},
|
||||
{0x530c, 0x06,},
|
||||
{0x5480, 0x01,},
|
||||
{0x5481, 0x08,},
|
||||
{0x5482, 0x14,},
|
||||
{0x5483, 0x28,},
|
||||
{0x5484, 0x51,},
|
||||
{0x5485, 0x65,},
|
||||
{0x5486, 0x71,},
|
||||
{0x5487, 0x7d,},
|
||||
{0x5488, 0x87,},
|
||||
{0x5489, 0x91,},
|
||||
{0x548a, 0x9a,},
|
||||
{0x548b, 0xaa,},
|
||||
{0x548c, 0xb8,},
|
||||
{0x548d, 0xcd,},
|
||||
{0x548e, 0xdd,},
|
||||
{0x548f, 0xea,},
|
||||
{0x5490, 0x1d,},
|
||||
{0x5580, 0x02,},
|
||||
{0x5583, 0x40,},
|
||||
{0x5584, 0x10,},
|
||||
{0x5589, 0x10,},
|
||||
{0x558a, 0x00,},
|
||||
{0x558b, 0xf8,},
|
||||
{0x5800, 0x3f,},
|
||||
{0x5801, 0x16,},
|
||||
{0x5802, 0x0e,},
|
||||
{0x5803, 0x0d,},
|
||||
{0x5804, 0x17,},
|
||||
{0x5805, 0x3f,},
|
||||
{0x5806, 0x0b,},
|
||||
{0x5807, 0x06,},
|
||||
{0x5808, 0x04,},
|
||||
{0x5809, 0x04,},
|
||||
{0x580a, 0x06,},
|
||||
{0x580b, 0x0b,},
|
||||
{0x580c, 0x09,},
|
||||
{0x580d, 0x03,},
|
||||
{0x580e, 0x00,},
|
||||
{0x580f, 0x00,},
|
||||
{0x5810, 0x03,},
|
||||
{0x5811, 0x08,},
|
||||
{0x5812, 0x0a,},
|
||||
{0x5813, 0x03,},
|
||||
{0x5814, 0x00,},
|
||||
{0x5815, 0x00,},
|
||||
{0x5816, 0x04,},
|
||||
{0x5817, 0x09,},
|
||||
{0x5818, 0x0f,},
|
||||
{0x5819, 0x08,},
|
||||
{0x581a, 0x06,},
|
||||
{0x581b, 0x06,},
|
||||
{0x581c, 0x08,},
|
||||
{0x581d, 0x0c,},
|
||||
{0x581e, 0x3f,},
|
||||
{0x581f, 0x1e,},
|
||||
{0x5820, 0x12,},
|
||||
{0x5821, 0x13,},
|
||||
{0x5822, 0x21,},
|
||||
{0x5823, 0x3f,},
|
||||
{0x5824, 0x68,},
|
||||
{0x5825, 0x28,},
|
||||
{0x5826, 0x2c,},
|
||||
{0x5827, 0x28,},
|
||||
{0x5828, 0x08,},
|
||||
{0x5829, 0x48,},
|
||||
{0x582a, 0x64,},
|
||||
{0x582b, 0x62,},
|
||||
{0x582c, 0x64,},
|
||||
{0x582d, 0x28,},
|
||||
{0x582e, 0x46,},
|
||||
{0x582f, 0x62,},
|
||||
{0x5830, 0x60,},
|
||||
{0x5831, 0x62,},
|
||||
{0x5832, 0x26,},
|
||||
{0x5833, 0x48,},
|
||||
{0x5834, 0x66,},
|
||||
{0x5835, 0x44,},
|
||||
{0x5836, 0x64,},
|
||||
{0x5837, 0x28,},
|
||||
{0x5838, 0x66,},
|
||||
{0x5839, 0x48,},
|
||||
{0x583a, 0x2c,},
|
||||
{0x583b, 0x28,},
|
||||
{0x583c, 0x26,},
|
||||
{0x583d, 0xae,},
|
||||
{0x5025, 0x00,},
|
||||
{0x3a0f, 0x30,},
|
||||
{0x3a10, 0x28,},
|
||||
{0x3a1b, 0x30,},
|
||||
{0x3a1e, 0x26,},
|
||||
{0x3a11, 0x60,},
|
||||
{0x3a1f, 0x14,},
|
||||
{0x0601, 0x02,},
|
||||
{0x3008, 0x42,},
|
||||
{0x3008, 0x02},
|
||||
};
|
||||
|
||||
static struct reg_value ov5645_setting_sxga[] = {
|
||||
{0x3612, 0xa9,},
|
||||
{0x3614, 0x50,},
|
||||
{0x3618, 0x00,},
|
||||
{0x3034, 0x18,},
|
||||
{0x3035, 0x21,},
|
||||
{0x3036, 0x70,},
|
||||
{0x3600, 0x09,},
|
||||
{0x3601, 0x43,},
|
||||
{0x3708, 0x66,},
|
||||
{0x370c, 0xc3,},
|
||||
{0x3800, 0x00,},
|
||||
{0x3801, 0x00,},
|
||||
{0x3802, 0x00,},
|
||||
{0x3803, 0x06,},
|
||||
{0x3804, 0x0a,},
|
||||
{0x3805, 0x3f,},
|
||||
{0x3806, 0x07,},
|
||||
{0x3807, 0x9d,},
|
||||
{0x3808, 0x05,},
|
||||
{0x3809, 0x00,},
|
||||
{0x380a, 0x03,},
|
||||
{0x380b, 0xc0,},
|
||||
{0x380c, 0x07,},
|
||||
{0x380d, 0x68,},
|
||||
{0x380e, 0x03,},
|
||||
{0x380f, 0xd8,},
|
||||
{0x3813, 0x06,},
|
||||
{0x3814, 0x31,},
|
||||
{0x3815, 0x31,},
|
||||
{0x3820, 0x47,},
|
||||
{0x3a02, 0x03,},
|
||||
{0x3a03, 0xd8,},
|
||||
{0x3a08, 0x01,},
|
||||
{0x3a09, 0xf8,},
|
||||
{0x3a0a, 0x01,},
|
||||
{0x3a0b, 0xa4,},
|
||||
{0x3a0e, 0x02,},
|
||||
{0x3a0d, 0x02,},
|
||||
{0x3a14, 0x03,},
|
||||
{0x3a15, 0xd8,},
|
||||
{0x3a18, 0x00,},
|
||||
{0x4004, 0x02,},
|
||||
{0x4005, 0x18,},
|
||||
{0x4300, 0x32,},
|
||||
{0x4202, 0x00,},
|
||||
};
|
||||
|
||||
static struct reg_value ov5645_setting_1080P[] = {
|
||||
{0x3612, 0xab,},
|
||||
{0x3614, 0x50,},
|
||||
{0x3618, 0x04,},
|
||||
{0x3034, 0x18,},
|
||||
{0x3035, 0x11,},
|
||||
{0x3036, 0x54,},
|
||||
{0x3600, 0x08,},
|
||||
{0x3601, 0x33,},
|
||||
{0x3708, 0x63,},
|
||||
{0x370c, 0xc0,},
|
||||
{0x3800, 0x01,},
|
||||
{0x3801, 0x50,},
|
||||
{0x3802, 0x01,},
|
||||
{0x3803, 0xb2,},
|
||||
{0x3804, 0x08,},
|
||||
{0x3805, 0xef,},
|
||||
{0x3806, 0x05,},
|
||||
{0x3807, 0xf1,},
|
||||
{0x3808, 0x07,},
|
||||
{0x3809, 0x80,},
|
||||
{0x380a, 0x04,},
|
||||
{0x380b, 0x38,},
|
||||
{0x380c, 0x09,},
|
||||
{0x380d, 0xc4,},
|
||||
{0x380e, 0x04,},
|
||||
{0x380f, 0x60,},
|
||||
{0x3813, 0x04,},
|
||||
{0x3814, 0x11,},
|
||||
{0x3815, 0x11,},
|
||||
{0x3820, 0x47,},
|
||||
{0x4514, 0x88,},
|
||||
{0x3a02, 0x04,},
|
||||
{0x3a03, 0x60,},
|
||||
{0x3a08, 0x01,},
|
||||
{0x3a09, 0x50,},
|
||||
{0x3a0a, 0x01,},
|
||||
{0x3a0b, 0x18,},
|
||||
{0x3a0e, 0x03,},
|
||||
{0x3a0d, 0x04,},
|
||||
{0x3a14, 0x04,},
|
||||
{0x3a15, 0x60,},
|
||||
{0x3a18, 0x00,},
|
||||
{0x4004, 0x06,},
|
||||
{0x4005, 0x18,},
|
||||
{0x4300, 0x32,},
|
||||
{0x4202, 0x00,},
|
||||
{0x4837, 0x0b,},
|
||||
};
|
||||
|
||||
static struct reg_value ov5645_setting_full[] = {
|
||||
{0x3612, 0xab,},
|
||||
{0x3614, 0x50,},
|
||||
{0x3618, 0x04,},
|
||||
{0x3034, 0x18,},
|
||||
{0x3035, 0x11,},
|
||||
{0x3036, 0x54,},
|
||||
{0x3600, 0x08,},
|
||||
{0x3601, 0x33,},
|
||||
{0x3708, 0x63,},
|
||||
{0x370c, 0xc0,},
|
||||
{0x3800, 0x00,},
|
||||
{0x3801, 0x00,},
|
||||
{0x3802, 0x00,},
|
||||
{0x3803, 0x00,},
|
||||
{0x3804, 0x0a,},
|
||||
{0x3805, 0x3f,},
|
||||
{0x3806, 0x07,},
|
||||
{0x3807, 0x9f,},
|
||||
{0x3808, 0x0a,},
|
||||
{0x3809, 0x20,},
|
||||
{0x380a, 0x07,},
|
||||
{0x380b, 0x98,},
|
||||
{0x380c, 0x0b,},
|
||||
{0x380d, 0x1c,},
|
||||
{0x380e, 0x07,},
|
||||
{0x380f, 0xb0,},
|
||||
{0x3813, 0x06,},
|
||||
{0x3814, 0x11,},
|
||||
{0x3815, 0x11,},
|
||||
{0x3820, 0x47,},
|
||||
{0x4514, 0x88,},
|
||||
{0x3a02, 0x07,},
|
||||
{0x3a03, 0xb0,},
|
||||
{0x3a08, 0x01,},
|
||||
{0x3a09, 0x27,},
|
||||
{0x3a0a, 0x00,},
|
||||
{0x3a0b, 0xf6,},
|
||||
{0x3a0e, 0x06,},
|
||||
{0x3a0d, 0x08,},
|
||||
{0x3a14, 0x07,},
|
||||
{0x3a15, 0xb0,},
|
||||
{0x3a18, 0x01,},
|
||||
{0x4004, 0x06,},
|
||||
{0x4005, 0x18,},
|
||||
{0x4300, 0x32,},
|
||||
{0x4837, 0x0b,},
|
||||
{0x4202, 0x00,},
|
||||
};
|
||||
|
||||
static struct ov5645_mode_info ov5645_mode_info_data[ov5645_mode_max + 1] = {
|
||||
{ov5645_mode_sxga_1280_960, 1280, 960,
|
||||
ov5645_setting_sxga,
|
||||
ARRAY_SIZE(ov5645_setting_sxga)},
|
||||
{ov5645_mode_1080p_1920_1080, 1920, 1080,
|
||||
ov5645_setting_1080P,
|
||||
ARRAY_SIZE(ov5645_setting_1080P)},
|
||||
{ov5645_mode_full_2592_1944, 2592, 1944,
|
||||
ov5645_setting_full,
|
||||
ARRAY_SIZE(ov5645_setting_full)},
|
||||
};
|
||||
|
||||
static int ov5645_regulators_enable(struct isp_device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (dev->io_regulator) {
|
||||
ret = regulator_enable(dev->io_regulator);
|
||||
if (ret < 0) {
|
||||
ISP_ERR("set io voltage failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ov5645_regulators_disable(struct isp_device *dev)
|
||||
{
|
||||
if (dev->io_regulator)
|
||||
regulator_disable(dev->io_regulator);
|
||||
}
|
||||
|
||||
void __ov5645_set_power(struct isp_device *dev, bool on)
|
||||
{
|
||||
if (on) {
|
||||
clk_prepare_enable(dev->xclk);
|
||||
ov5645_regulators_enable(dev);
|
||||
usleep_range(5000, 15000);
|
||||
if (dev->pwdn_gpio)
|
||||
gpio_set_value(dev->pwdn_gpio, 1);
|
||||
usleep_range(1000, 2000);
|
||||
if (dev->rst_gpio)
|
||||
gpio_set_value(dev->rst_gpio, 1);
|
||||
msleep(20);
|
||||
ISP_ERR("enter\n");
|
||||
} else {
|
||||
if (dev->rst_gpio)
|
||||
gpio_set_value(dev->rst_gpio, 0);
|
||||
if (dev->pwdn_gpio)
|
||||
gpio_set_value(dev->pwdn_gpio, 0);
|
||||
ov5645_regulators_disable(dev);
|
||||
clk_disable_unprepare(dev->xclk);
|
||||
}
|
||||
}
|
||||
|
||||
static enum ov5645_mode ov5645_find_nearest_mode(int width, int height)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = ov5645_mode_max; i >= 0; i--) {
|
||||
if (ov5645_mode_info_data[i].width <= width &&
|
||||
ov5645_mode_info_data[i].height <= height)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < 0)
|
||||
i = 0;
|
||||
|
||||
return (enum ov5645_mode)i;
|
||||
}
|
||||
|
||||
static int ov5645_set_register_array(struct isp_i2c_client_t *client,
|
||||
struct reg_value *settings,
|
||||
s32 num_settings)
|
||||
{
|
||||
register u16 reg = 0;
|
||||
register u8 val = 0;
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < num_settings; ++i, ++settings) {
|
||||
reg = settings->reg;
|
||||
val = settings->val;
|
||||
|
||||
ret = client->ops->write(client, reg, val);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
}
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov5645_init(struct isp_i2c_client_t *client)
|
||||
{
|
||||
struct reg_value *settings = NULL;
|
||||
int num_settings = 0;
|
||||
int ret;
|
||||
|
||||
settings = ov5645_global_init_setting;
|
||||
num_settings = ARRAY_SIZE(ov5645_global_init_setting);
|
||||
ret = ov5645_set_register_array(client, settings, num_settings);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ov5645_change_mode(struct isp_i2c_client_t *client, enum ov5645_mode mode)
|
||||
{
|
||||
struct reg_value *settings = NULL;
|
||||
s32 num_settings = 0;
|
||||
int ret = 0;
|
||||
|
||||
settings = ov5645_mode_info_data[mode].init_data_ptr;
|
||||
num_settings = ov5645_mode_info_data[mode].init_data_size;
|
||||
ret = ov5645_set_register_array(client, settings, num_settings);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov5645_set_aec_mode(struct isp_i2c_client_t *client, int auto_mode)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
client->ops->read(client, OV5645_AEC_PK_MANUAL, &val);
|
||||
if (auto_mode) {
|
||||
val |= OV5645_AEC_MANUAL_ENABLE;
|
||||
} else { /* V4L2_EXPOSURE_MANUAL */
|
||||
val &= ~OV5645_AEC_MANUAL_ENABLE;
|
||||
}
|
||||
|
||||
return client->ops->write(client, OV5645_AEC_PK_MANUAL, val);
|
||||
}
|
||||
|
||||
static int ov5645_set_awb(struct isp_i2c_client_t *client, s32 enable_auto)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
client->ops->read(client, OV5645_AWB_MANUAL_CONTROL, &val);
|
||||
if (enable_auto)
|
||||
val &= ~OV5645_AWB_MANUAL_ENABLE;
|
||||
else
|
||||
val |= OV5645_AWB_MANUAL_ENABLE;
|
||||
|
||||
return client->ops->write(client, OV5645_AWB_MANUAL_CONTROL, val);
|
||||
}
|
||||
|
||||
int ov5645_set_fmt(struct isp_i2c_client_t *client,
|
||||
unsigned int w, unsigned int h)
|
||||
{
|
||||
enum ov5645_mode new_mode;
|
||||
|
||||
new_mode = ov5645_find_nearest_mode(w, h);
|
||||
|
||||
client->mode = new_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ov5645_get_chip_id(struct isp_i2c_client_t *client, unsigned int *chip_id)
|
||||
{
|
||||
int ret;
|
||||
unsigned char chip_id_high, chip_id_low;
|
||||
|
||||
ret = client->ops->read(client, OV5645_CHIP_ID_HIGH_REG, &chip_id_high);
|
||||
if (ret || chip_id_high != OV5645_CHIP_ID_HIGH) {
|
||||
ISP_ERR("get chip id high[%d] fail\n", chip_id_high);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = client->ops->read(client, OV5645_CHIP_ID_LOW_REG, &chip_id_low);
|
||||
if (ret || chip_id_low != OV5645_CHIP_ID_LOW) {
|
||||
ISP_ERR("get chip id low[%d] fail\n", chip_id_low);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
*chip_id = (chip_id_high<<8) | chip_id_low;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ov5645_stream_on_off(struct isp_i2c_client_t *client, int enable)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ISP_ERR("enable = %d mode = %d\n", enable, client->mode);
|
||||
|
||||
if (enable) {
|
||||
ret = ov5645_change_mode(client, client->mode);
|
||||
if (ret < 0) {
|
||||
ISP_ERR("could not set mode %d\n",
|
||||
client->mode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ov5645_set_aec_mode(client, 0);
|
||||
ov5645_set_awb(client, 1);
|
||||
|
||||
client->ops->write(client, OV5645_SYSTEM_CTRL0,
|
||||
OV5645_SYSTEM_CTRL0_START);
|
||||
} else {
|
||||
client->ops->write(client, OV5645_SYSTEM_CTRL0,
|
||||
OV5645_SYSTEM_CTRL0_STOP);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ov5645_power(struct isp_i2c_client_t *client, int on)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__ov5645_set_power(client->isp_dev, !!on);
|
||||
|
||||
if (on) {
|
||||
ret = ov5645_init(client);
|
||||
if (ret < 0) {
|
||||
ISP_ERR("could not set init registers\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
client->ops->write(client, OV5645_SYSTEM_CTRL0,
|
||||
OV5645_SYSTEM_CTRL0_STOP);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov5645_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct isp_device *idev = NULL;
|
||||
struct device *device = &pdev->dev;
|
||||
struct device_node *np = device->of_node;
|
||||
int index = 0;
|
||||
unsigned int chip_id = 0;
|
||||
struct isp_i2c_client_t *i2c_client = NULL;
|
||||
|
||||
ISP_INFO("enter!\n");
|
||||
if (pdev->dev.parent)
|
||||
idev = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
if (!idev)
|
||||
return -ENXIO;
|
||||
|
||||
ret = of_property_read_u32(np, "sensor_index", (u32 *)&index);
|
||||
if (ret < 0) {
|
||||
ISP_ERR("no sensor index available\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (idev->sensor[index].probe == true)
|
||||
return 0;
|
||||
|
||||
idev->sensor[index].rst_gpio = of_get_named_gpio(np, "reset-gpio", 0);
|
||||
if (!gpio_is_valid(idev->sensor[index].rst_gpio)) {
|
||||
ISP_ERR("no reset pin available\n");
|
||||
idev->sensor[index].rst_gpio = 0;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
idev->sensor[index].pwdn_gpio = of_get_named_gpio(np, "pwdn-gpio", 0);
|
||||
if (!gpio_is_valid(idev->sensor[index].rst_gpio)) {
|
||||
ISP_ERR("no powerdown pin available\n");
|
||||
idev->sensor[index].rst_gpio = 0;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
ret = devm_gpio_request_one(&pdev->dev,
|
||||
idev->sensor[index].rst_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "sensor-reset");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_gpio_request_one(&pdev->dev,
|
||||
idev->sensor[index].pwdn_gpio,
|
||||
GPIOF_OUT_INIT_LOW, "sensor-pwdn");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
idev->sensor[index].addr = OV5645_SLAVE_ID;
|
||||
idev->sensor[index].flag = I2C_ADDR_7BIT;
|
||||
idev->sensor[index].speed_cfg = I2C_SPEED_STD;
|
||||
idev->sensor[index].csi_index = 0;
|
||||
idev->sensor[index].dt = YUV_DT_422_8BITS;
|
||||
idev->sensor[index].pf = DF_2PF8;
|
||||
idev->sensor[index].csi_lane = 2;
|
||||
|
||||
idev->addr = idev->sensor[index].addr;
|
||||
idev->flag = idev->sensor[index].flag;
|
||||
idev->speed_cfg = idev->sensor[index].speed_cfg;
|
||||
idev->csi_index = idev->sensor[index].csi_index;
|
||||
idev->dt = idev->sensor[index].dt;
|
||||
idev->pf = idev->sensor[index].pf;
|
||||
idev->csi_lane = idev->sensor[index].csi_lane;
|
||||
idev->pwdn_gpio = idev->sensor[index].pwdn_gpio;
|
||||
idev->rst_gpio = idev->sensor[index].rst_gpio;
|
||||
|
||||
isp_ispss_enable_clock(idev);
|
||||
|
||||
mdelay(100);
|
||||
|
||||
isp_ispss_reset_all(idev);
|
||||
|
||||
mdelay(100);
|
||||
|
||||
idev->client = create_isp_i2c_client(idev);
|
||||
if (!idev->client)
|
||||
return -ENODEV;
|
||||
|
||||
i2c_client = idev->client;
|
||||
ret = i2c_client->ops->open(i2c_client);
|
||||
if (ret) {
|
||||
destroy_isp_i2c_client(i2c_client);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ov5645_power(i2c_client, 1);
|
||||
ov5645_get_chip_id(i2c_client, &chip_id);
|
||||
ov5645_power(i2c_client, 0);
|
||||
i2c_client->ops->close(i2c_client);
|
||||
destroy_isp_i2c_client(i2c_client);
|
||||
ISP_ERR("chip id is 0x%x\n", chip_id);
|
||||
if (chip_id != 0x5645) {
|
||||
ISP_ERR("chip id is 0x%x, probe failed\n", chip_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
idev->sensor[index].probe = true;
|
||||
idev->sensor[index].camera_sensor_power = ov5645_power;
|
||||
idev->sensor[index].camera_sensor_set_fmt = ov5645_set_fmt;
|
||||
idev->sensor[index].camera_stream_on_off = ov5645_stream_on_off;
|
||||
|
||||
ISP_INFO("exit!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ov5645_remove(struct platform_device *pdev)
|
||||
{
|
||||
ISP_INFO("enter!\n");
|
||||
|
||||
|
||||
ISP_INFO("exit!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ov5645_match_table[] = {
|
||||
{
|
||||
.compatible = "hisilicon,ov5645",
|
||||
.data = NULL,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ov5645_match_table);
|
||||
|
||||
static struct platform_driver ov5645_driver = {
|
||||
.probe = ov5645_probe,
|
||||
.remove = ov5645_remove,
|
||||
.driver = {
|
||||
.name = "hisi-ov5645",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(ov5645_match_table),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ov5645_module_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ISP_INFO("enter!\n");
|
||||
|
||||
ret = platform_driver_register(&ov5645_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ISP_INFO("exit!\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ov5645_module_exit(void)
|
||||
{
|
||||
ISP_INFO("enter!\n");
|
||||
|
||||
platform_driver_unregister(&ov5645_driver);
|
||||
|
||||
ISP_INFO("exit!\n");
|
||||
}
|
||||
|
||||
late_initcall(ov5645_module_init);
|
||||
module_exit(ov5645_module_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Hisilicon Isp Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Linaro Ltd.
|
||||
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef HISI_OV5645_H
|
||||
#define HISI_OV5645_H
|
||||
|
||||
#include "hisi_isp_core.h"
|
||||
#include "hisi_isp_i2c.h"
|
||||
#include "hisi_isp_common.h"
|
||||
#include "hisi_isp_cvdr.h"
|
||||
|
||||
#define OV5645_SLAVE_ID 0x78
|
||||
|
||||
#endif /* HISI_OV5645_H */
|
||||
Reference in New Issue
Block a user