mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 04:10:18 +09:00
media: i2c: nvp6324: add v4l2 interface
Change-Id: I536d01151572f30ca73f1da1f76ea3d9c4d7b726 Signed-off-by: Hu Kejun <william.hu@rock-chips.com>
This commit is contained in:
@@ -2,4 +2,4 @@ subdir-ccflags-y += -DNC_DEBUG
|
||||
obj-y := jaguar1_drv.o jaguar1_i2c.o \
|
||||
jaguar1_video.o jaguar1_coax_protocol.o \
|
||||
jaguar1_motion.o jaguar1_video_eq.o \
|
||||
jaguar1_mipi.o
|
||||
jaguar1_mipi.o jaguar1_v4l2.o
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
#include "jaguar1_ioctl.h"
|
||||
#include "jaguar1_video_eq.h"
|
||||
#include "jaguar1_mipi.h"
|
||||
#include "jaguar1_drv.h"
|
||||
#ifdef FOR_IMX6
|
||||
#include "imx_mipi.h"
|
||||
#endif
|
||||
@@ -690,6 +691,29 @@ static long jaguar1_ioctl(struct file *file, unsigned int cmd, unsigned long arg
|
||||
return 0;
|
||||
}
|
||||
|
||||
void jaguar1_start(video_init_all *video_init)
|
||||
{
|
||||
down(&jaguar1_lock);
|
||||
vd_set_all(video_init);
|
||||
up(&jaguar1_lock);
|
||||
}
|
||||
|
||||
void jaguar1_stop(void)
|
||||
{
|
||||
video_input_init video_val;
|
||||
|
||||
down(&jaguar1_lock);
|
||||
arb_disable(0);
|
||||
gpio_i2c_write(0x60, 0xff, 0x20);
|
||||
|
||||
// ARB RESET High
|
||||
gpio_i2c_write(0x60, 0x40, 0x11);
|
||||
usleep_range(3000, 5000);
|
||||
gpio_i2c_write(0x60, 0x40, 0x00);
|
||||
vd_jaguar1_sw_reset(&video_val);
|
||||
up(&jaguar1_lock);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Description : i2c client initial
|
||||
* Argurments : void
|
||||
@@ -743,14 +767,15 @@ static struct miscdevice jaguar1_dev = {
|
||||
*******************************************************************************/
|
||||
static int __init jaguar1_module_init(void)
|
||||
{
|
||||
video_init_all sVideoall;
|
||||
int ret = 0;
|
||||
int ch;
|
||||
#ifdef FMT_SETTING_SAMPLE
|
||||
int dev_num = 0;
|
||||
#endif
|
||||
|
||||
#ifdef STREAM_ON_DEFLAULT
|
||||
video_init_all sVideoall;
|
||||
int ch;
|
||||
|
||||
jaguar1_mclk= 3;
|
||||
init = true;
|
||||
fmt = 2;
|
||||
@@ -779,6 +804,7 @@ static int __init jaguar1_module_init(void)
|
||||
down(&jaguar1_lock);
|
||||
video_decoder_init();
|
||||
|
||||
#ifdef STREAM_ON_DEFLAULT
|
||||
if(init)
|
||||
{
|
||||
for(ch=0;ch<jaguar1_cnt*4;ch++)
|
||||
@@ -810,6 +836,7 @@ static int __init jaguar1_module_init(void)
|
||||
}
|
||||
vd_set_all(&sVideoall);
|
||||
}
|
||||
#endif
|
||||
|
||||
up(&jaguar1_lock);
|
||||
|
||||
|
||||
24
drivers/media/i2c/jaguar1_drv/jaguar1_drv.h
Normal file
24
drivers/media/i2c/jaguar1_drv/jaguar1_drv.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/********************************************************************************
|
||||
*
|
||||
* Copyright (C) 2017 NEXTCHIP Inc. All rights reserved.
|
||||
* Module : Jaguar1 Device Driver
|
||||
* Description : MIPI
|
||||
* Author :
|
||||
* Date :
|
||||
* Version : Version 1.0
|
||||
*
|
||||
********************************************************************************
|
||||
* History :
|
||||
*
|
||||
*
|
||||
********************************************************************************/
|
||||
#ifndef _JAGUAR1_DRV_
|
||||
#define _JAGUAR1_DRV_
|
||||
|
||||
#include "jaguar1_video.h"
|
||||
|
||||
void jaguar1_start(video_init_all *video_init);
|
||||
void jaguar1_stop(void);
|
||||
|
||||
#endif
|
||||
@@ -42,7 +42,7 @@ static void arb_scale_set(video_input_init *dev_ch_info, unsigned char val)
|
||||
gpio_i2c_write(jaguar1_i2c_addr[devnum], 0x01, arb_scale);
|
||||
}
|
||||
|
||||
static void arb_enable(int dev_num)
|
||||
void arb_enable(int dev_num)
|
||||
{
|
||||
if((dev_num < 0) || (dev_num > 3))
|
||||
{
|
||||
@@ -55,8 +55,7 @@ static void arb_enable(int dev_num)
|
||||
printk("VDEC_ARBITER_INIT done 0x%X\n", en_param);
|
||||
}
|
||||
|
||||
|
||||
static void arb_disable(int dev_num)
|
||||
void arb_disable(int dev_num)
|
||||
{
|
||||
gpio_i2c_write(jaguar1_i2c_addr[dev_num], 0xff, 0x20);
|
||||
gpio_i2c_write(jaguar1_i2c_addr[dev_num], 0x00, 0x00);
|
||||
|
||||
@@ -31,8 +31,11 @@ extern unsigned int jaguar1_mclk;
|
||||
extern unsigned int jaguar1_lane;
|
||||
|
||||
void arb_init(int dev_num);
|
||||
void arb_enable(int dev_num);
|
||||
void arb_disable(int dev_num);
|
||||
int mipi_datatype_set(unsigned char data_type);
|
||||
void mipi_tx_init(int dev_num);
|
||||
void mipi_video_format_set(video_input_init *dev_ch_info);
|
||||
void disable_parallel(int dev_num);
|
||||
|
||||
#endif
|
||||
|
||||
828
drivers/media/i2c/jaguar1_drv/jaguar1_v4l2.c
Normal file
828
drivers/media/i2c/jaguar1_drv/jaguar1_v4l2.c
Normal file
@@ -0,0 +1,828 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* jaguar1 driver
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <media/media-entity.h>
|
||||
#include <media/v4l2-async.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/rk-camera-module.h>
|
||||
#include <linux/rk-preisp.h>
|
||||
|
||||
#include "jaguar1_common.h"
|
||||
#include "jaguar1_video.h"
|
||||
#include "jaguar1_coax_protocol.h"
|
||||
#include "jaguar1_motion.h"
|
||||
#include "jaguar1_ioctl.h"
|
||||
#include "jaguar1_video_eq.h"
|
||||
#include "jaguar1_mipi.h"
|
||||
#include "jaguar1_drv.h"
|
||||
|
||||
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x0)
|
||||
|
||||
#ifndef V4L2_CID_DIGITAL_GAIN
|
||||
#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
|
||||
#endif
|
||||
|
||||
#define JAGUAR1_XVCLK_FREQ 24000000
|
||||
|
||||
#define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default"
|
||||
#define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep"
|
||||
|
||||
#define OF_CAMERA_MODULE_REGULATORS "rockchip,regulator-names"
|
||||
#define OF_CAMERA_MODULE_REGULATOR_VOLTAGES "rockchip,regulator-voltages"
|
||||
|
||||
#define JAGUAR1_NAME "jaguar1"
|
||||
|
||||
struct jaguar1_gpio {
|
||||
int pltfrm_gpio;
|
||||
const char *label;
|
||||
enum of_gpio_flags active_low;
|
||||
};
|
||||
|
||||
struct jaguar1_regulator {
|
||||
struct regulator *regulator;
|
||||
u32 min_uV;
|
||||
u32 max_uV;
|
||||
};
|
||||
|
||||
struct jaguar1_regulators {
|
||||
u32 cnt;
|
||||
struct jaguar1_regulator *regulator;
|
||||
};
|
||||
|
||||
struct jaguar1_pixfmt {
|
||||
u32 code;
|
||||
};
|
||||
|
||||
struct jaguar1_framesize {
|
||||
u16 width;
|
||||
u16 height;
|
||||
enum NC_VIVO_CH_FORMATDEF fmt_idx;
|
||||
};
|
||||
|
||||
struct jaguar1 {
|
||||
struct i2c_client *client;
|
||||
struct clk *xvclk;
|
||||
struct gpio_desc *rst_gpio;
|
||||
struct gpio_desc *rst2_gpio;
|
||||
struct gpio_desc *pd_gpio;
|
||||
struct gpio_desc *pd2_gpio;
|
||||
struct gpio_desc *pwd_gpio;
|
||||
struct gpio_desc *pwd2_gpio;
|
||||
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pins_default;
|
||||
struct pinctrl_state *pins_sleep;
|
||||
|
||||
struct v4l2_subdev subdev;
|
||||
struct media_pad pad;
|
||||
struct mutex mutex;
|
||||
bool power_on;
|
||||
struct jaguar1_regulators regulators;
|
||||
|
||||
u32 module_index;
|
||||
const char *module_facing;
|
||||
const char *module_name;
|
||||
const char *len_name;
|
||||
|
||||
struct v4l2_mbus_framefmt format;
|
||||
const struct jaguar1_framesize *frame_size;
|
||||
int streaming;
|
||||
};
|
||||
|
||||
#define to_jaguar1(sd) container_of(sd, struct jaguar1, subdev)
|
||||
|
||||
static const struct jaguar1_framesize jaguar1_framesizes[] = {
|
||||
{
|
||||
.width = 1280,
|
||||
.height = 720,
|
||||
.fmt_idx = AHD20_720P_25P,
|
||||
},
|
||||
{
|
||||
.width = 1920,
|
||||
.height = 1080,
|
||||
.fmt_idx = AHD20_1080P_25P,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct jaguar1_pixfmt jaguar1_formats[] = {
|
||||
{
|
||||
.code = MEDIA_BUS_FMT_UYVY8_2X8,
|
||||
}
|
||||
};
|
||||
|
||||
static int __jaguar1_power_on(struct jaguar1 *jaguar1)
|
||||
{
|
||||
u32 i;
|
||||
int ret;
|
||||
struct jaguar1_regulator *regulator;
|
||||
struct device *dev = &jaguar1->client->dev;
|
||||
|
||||
if (!IS_ERR_OR_NULL(jaguar1->pins_default)) {
|
||||
ret = pinctrl_select_state(jaguar1->pinctrl,
|
||||
jaguar1->pins_default);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "could not set pins. ret=%d\n", ret);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(jaguar1->xvclk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to enable xvclk\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (jaguar1->regulators.regulator) {
|
||||
for (i = 0; i < jaguar1->regulators.cnt; i++) {
|
||||
regulator = jaguar1->regulators.regulator + i;
|
||||
if (IS_ERR(regulator->regulator))
|
||||
continue;
|
||||
regulator_set_voltage(
|
||||
regulator->regulator,
|
||||
regulator->min_uV,
|
||||
regulator->max_uV);
|
||||
if (regulator_enable(regulator->regulator)) {
|
||||
dev_err(dev,
|
||||
"regulator_enable failed!\n");
|
||||
goto disable_clk;
|
||||
}
|
||||
}
|
||||
}
|
||||
usleep_range(3000, 5000);
|
||||
|
||||
if (!IS_ERR(jaguar1->pwd_gpio)) {
|
||||
gpiod_direction_output(jaguar1->pwd_gpio, 1);
|
||||
usleep_range(3000, 5000);
|
||||
}
|
||||
|
||||
if (!IS_ERR(jaguar1->pwd2_gpio)) {
|
||||
gpiod_direction_output(jaguar1->pwd2_gpio, 1);
|
||||
usleep_range(3000, 5000);
|
||||
}
|
||||
|
||||
if (!IS_ERR(jaguar1->pd_gpio)) {
|
||||
gpiod_direction_output(jaguar1->pd_gpio, 1);
|
||||
usleep_range(1500, 2000);
|
||||
}
|
||||
|
||||
if (!IS_ERR(jaguar1->pd2_gpio)) {
|
||||
gpiod_direction_output(jaguar1->pd2_gpio, 1);
|
||||
usleep_range(1500, 2000);
|
||||
}
|
||||
|
||||
if (!IS_ERR(jaguar1->rst_gpio)) {
|
||||
gpiod_direction_output(jaguar1->rst_gpio, 0);
|
||||
usleep_range(1500, 2000);
|
||||
gpiod_direction_output(jaguar1->rst_gpio, 1);
|
||||
}
|
||||
|
||||
if (!IS_ERR(jaguar1->rst2_gpio)) {
|
||||
gpiod_direction_output(jaguar1->rst2_gpio, 0);
|
||||
usleep_range(1500, 2000);
|
||||
gpiod_direction_output(jaguar1->rst2_gpio, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
disable_clk:
|
||||
clk_disable_unprepare(jaguar1->xvclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __jaguar1_power_off(struct jaguar1 *jaguar1)
|
||||
{
|
||||
u32 i;
|
||||
int ret;
|
||||
struct jaguar1_regulator *regulator;
|
||||
struct device *dev = &jaguar1->client->dev;
|
||||
|
||||
if (!IS_ERR(jaguar1->pd_gpio))
|
||||
gpiod_direction_output(jaguar1->pd_gpio, 0);
|
||||
|
||||
if (!IS_ERR(jaguar1->pd2_gpio))
|
||||
gpiod_direction_output(jaguar1->pd2_gpio, 0);
|
||||
|
||||
clk_disable_unprepare(jaguar1->xvclk);
|
||||
|
||||
if (!IS_ERR(jaguar1->rst_gpio))
|
||||
gpiod_direction_output(jaguar1->rst_gpio, 0);
|
||||
|
||||
if (!IS_ERR(jaguar1->rst2_gpio))
|
||||
gpiod_direction_output(jaguar1->rst2_gpio, 0);
|
||||
|
||||
if (!IS_ERR(jaguar1->pwd_gpio))
|
||||
gpiod_direction_output(jaguar1->pwd_gpio, 0);
|
||||
|
||||
if (!IS_ERR(jaguar1->pwd2_gpio))
|
||||
gpiod_direction_output(jaguar1->pwd2_gpio, 0);
|
||||
|
||||
if (!IS_ERR_OR_NULL(jaguar1->pins_sleep)) {
|
||||
ret = pinctrl_select_state(jaguar1->pinctrl,
|
||||
jaguar1->pins_sleep);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "could not set pins\n");
|
||||
}
|
||||
|
||||
if (jaguar1->regulators.regulator) {
|
||||
for (i = 0; i < jaguar1->regulators.cnt; i++) {
|
||||
regulator = jaguar1->regulators.regulator + i;
|
||||
if (IS_ERR(regulator->regulator))
|
||||
continue;
|
||||
regulator_disable(regulator->regulator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int jaguar1_power(struct v4l2_subdev *sd, int on)
|
||||
{
|
||||
struct jaguar1 *jaguar1 = to_jaguar1(sd);
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&jaguar1->mutex);
|
||||
|
||||
/* If the power state is not modified - no work to do. */
|
||||
if (jaguar1->power_on == !!on)
|
||||
goto exit;
|
||||
|
||||
if (on) {
|
||||
ret = __jaguar1_power_on(jaguar1);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
jaguar1->power_on = true;
|
||||
} else {
|
||||
__jaguar1_power_off(jaguar1);
|
||||
jaguar1->power_on = false;
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&jaguar1->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void jaguar1_get_default_format(struct v4l2_mbus_framefmt *format)
|
||||
{
|
||||
format->width = jaguar1_framesizes[0].width;
|
||||
format->height = jaguar1_framesizes[0].height;
|
||||
format->colorspace = V4L2_COLORSPACE_SRGB;
|
||||
format->code = jaguar1_formats[0].code;
|
||||
format->field = V4L2_FIELD_NONE;
|
||||
}
|
||||
|
||||
static int jaguar1_stream(struct v4l2_subdev *sd, int on)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
struct jaguar1 *jaguar1 = to_jaguar1(sd);
|
||||
video_init_all video_init;
|
||||
enum NC_VIVO_CH_FORMATDEF fmt_idx;
|
||||
int ch;
|
||||
|
||||
dev_dbg(&client->dev, "%s: on %d\n", __func__, on);
|
||||
mutex_lock(&jaguar1->mutex);
|
||||
on = !!on;
|
||||
|
||||
if (jaguar1->streaming == on)
|
||||
goto unlock;
|
||||
|
||||
if (on) {
|
||||
fmt_idx = jaguar1->frame_size->fmt_idx;
|
||||
for (ch = 0; ch < 4; ch++) {
|
||||
video_init.ch_param[ch].ch = ch;
|
||||
video_init.ch_param[ch].format = fmt_idx;
|
||||
video_init.ch_param[ch].input = SINGLE_ENDED;
|
||||
video_init.ch_param[ch].interface = YUV_422;
|
||||
}
|
||||
jaguar1_start(&video_init);
|
||||
} else {
|
||||
jaguar1_stop();
|
||||
}
|
||||
|
||||
jaguar1->streaming = on;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&jaguar1->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jaguar1_enum_mbus_code(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
dev_dbg(&client->dev, "%s:\n", __func__);
|
||||
|
||||
if (code->index >= ARRAY_SIZE(jaguar1_formats))
|
||||
return -EINVAL;
|
||||
|
||||
code->code = jaguar1_formats[code->index].code;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jaguar1_enum_frame_sizes(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_frame_size_enum *fse)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
int i = ARRAY_SIZE(jaguar1_formats);
|
||||
|
||||
dev_dbg(&client->dev, "%s:\n", __func__);
|
||||
|
||||
if (fse->index >= ARRAY_SIZE(jaguar1_framesizes))
|
||||
return -EINVAL;
|
||||
|
||||
while (--i)
|
||||
if (fse->code == jaguar1_formats[i].code)
|
||||
break;
|
||||
|
||||
fse->code = jaguar1_formats[i].code;
|
||||
|
||||
fse->min_width = jaguar1_framesizes[fse->index].width;
|
||||
fse->max_width = fse->min_width;
|
||||
fse->max_height = jaguar1_framesizes[fse->index].height;
|
||||
fse->min_height = fse->max_height;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jaguar1_get_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
struct jaguar1 *jaguar1 = to_jaguar1(sd);
|
||||
|
||||
dev_dbg(&client->dev, "%s enter\n", __func__);
|
||||
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
|
||||
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
||||
struct v4l2_mbus_framefmt *mf;
|
||||
|
||||
mf = v4l2_subdev_get_try_format(sd, cfg, 0);
|
||||
mutex_lock(&jaguar1->mutex);
|
||||
fmt->format = *mf;
|
||||
mutex_unlock(&jaguar1->mutex);
|
||||
return 0;
|
||||
#else
|
||||
return -ENOTTY;
|
||||
#endif
|
||||
}
|
||||
|
||||
mutex_lock(&jaguar1->mutex);
|
||||
fmt->format = jaguar1->format;
|
||||
mutex_unlock(&jaguar1->mutex);
|
||||
|
||||
dev_info(&client->dev, "%s: %x %dx%d\n", __func__,
|
||||
jaguar1->format.code, jaguar1->format.width,
|
||||
jaguar1->format.height);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __jaguar1_try_frame_size(struct v4l2_mbus_framefmt *mf,
|
||||
const struct jaguar1_framesize **size)
|
||||
{
|
||||
const struct jaguar1_framesize *fsize = &jaguar1_framesizes[0];
|
||||
const struct jaguar1_framesize *match = NULL;
|
||||
int i = ARRAY_SIZE(jaguar1_framesizes);
|
||||
unsigned int min_err = UINT_MAX;
|
||||
|
||||
while (i--) {
|
||||
unsigned int err = abs(fsize->width - mf->width)
|
||||
+ abs(fsize->height - mf->height);
|
||||
if (err < min_err) {
|
||||
min_err = err;
|
||||
match = fsize;
|
||||
}
|
||||
fsize++;
|
||||
}
|
||||
|
||||
if (!match)
|
||||
match = &jaguar1_framesizes[0];
|
||||
|
||||
mf->width = match->width;
|
||||
mf->height = match->height;
|
||||
|
||||
if (size)
|
||||
*size = match;
|
||||
}
|
||||
|
||||
static int jaguar1_set_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
int index = ARRAY_SIZE(jaguar1_formats);
|
||||
struct v4l2_mbus_framefmt *mf = &fmt->format;
|
||||
const struct jaguar1_framesize *size = NULL;
|
||||
struct jaguar1 *jaguar1 = to_jaguar1(sd);
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(&client->dev, "%s enter\n", __func__);
|
||||
|
||||
__jaguar1_try_frame_size(mf, &size);
|
||||
|
||||
while (--index >= 0)
|
||||
if (jaguar1_formats[index].code == mf->code)
|
||||
break;
|
||||
|
||||
if (index < 0)
|
||||
return -EINVAL;
|
||||
|
||||
mf->colorspace = V4L2_COLORSPACE_SRGB;
|
||||
mf->code = jaguar1_formats[index].code;
|
||||
mf->field = V4L2_FIELD_NONE;
|
||||
|
||||
mutex_lock(&jaguar1->mutex);
|
||||
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
|
||||
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
||||
mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
|
||||
*mf = fmt->format;
|
||||
#else
|
||||
return -ENOTTY;
|
||||
#endif
|
||||
} else {
|
||||
if (jaguar1->streaming) {
|
||||
mutex_unlock(&jaguar1->mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
jaguar1->frame_size = size;
|
||||
jaguar1->format = fmt->format;
|
||||
}
|
||||
|
||||
mutex_unlock(&jaguar1->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void jaguar1_get_module_inf(struct jaguar1 *jaguar1,
|
||||
struct rkmodule_inf *inf)
|
||||
{
|
||||
memset(inf, 0, sizeof(*inf));
|
||||
strlcpy(inf->base.sensor, JAGUAR1_NAME, sizeof(inf->base.sensor));
|
||||
strlcpy(inf->base.module, jaguar1->module_name,
|
||||
sizeof(inf->base.module));
|
||||
strlcpy(inf->base.lens, jaguar1->len_name, sizeof(inf->base.lens));
|
||||
}
|
||||
|
||||
static long jaguar1_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
|
||||
{
|
||||
struct jaguar1 *jaguar1 = to_jaguar1(sd);
|
||||
long ret = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case RKMODULE_GET_MODULE_INFO:
|
||||
jaguar1_get_module_inf(jaguar1, (struct rkmodule_inf *)arg);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOTTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static long jaguar1_compat_ioctl32(struct v4l2_subdev *sd,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
void __user *up = compat_ptr(arg);
|
||||
struct rkmodule_inf *inf;
|
||||
struct rkmodule_awb_cfg *cfg;
|
||||
long ret;
|
||||
|
||||
switch (cmd) {
|
||||
case RKMODULE_GET_MODULE_INFO:
|
||||
inf = kzalloc(sizeof(*inf), GFP_KERNEL);
|
||||
if (!inf) {
|
||||
ret = -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = jaguar1_ioctl(sd, cmd, inf);
|
||||
if (!ret)
|
||||
ret = copy_to_user(up, inf, sizeof(*inf));
|
||||
kfree(inf);
|
||||
break;
|
||||
case RKMODULE_AWB_CFG:
|
||||
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
|
||||
if (!cfg) {
|
||||
ret = -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = copy_from_user(cfg, up, sizeof(*cfg));
|
||||
if (!ret)
|
||||
ret = jaguar1_ioctl(sd, cmd, cfg);
|
||||
kfree(cfg);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOIOCTLCMD;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int jaguar1_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct jaguar1 *jaguar1 = to_jaguar1(sd);
|
||||
|
||||
return __jaguar1_power_on(jaguar1);
|
||||
}
|
||||
|
||||
static int jaguar1_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct jaguar1 *jaguar1 = to_jaguar1(sd);
|
||||
|
||||
__jaguar1_power_off(jaguar1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops jaguar1_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(jaguar1_runtime_suspend,
|
||||
jaguar1_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_video_ops jaguar1_video_ops = {
|
||||
.s_stream = jaguar1_stream,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops jaguar1_subdev_pad_ops = {
|
||||
.enum_mbus_code = jaguar1_enum_mbus_code,
|
||||
.enum_frame_size = jaguar1_enum_frame_sizes,
|
||||
.get_fmt = jaguar1_get_fmt,
|
||||
.set_fmt = jaguar1_set_fmt,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops jaguar1_core_ops = {
|
||||
.s_power = jaguar1_power,
|
||||
.ioctl = jaguar1_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl32 = jaguar1_compat_ioctl32,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops jaguar1_subdev_ops = {
|
||||
.core = &jaguar1_core_ops,
|
||||
.video = &jaguar1_video_ops,
|
||||
.pad = &jaguar1_subdev_pad_ops,
|
||||
};
|
||||
|
||||
static int jaguar1_analyze_dts(struct jaguar1 *jaguar1)
|
||||
{
|
||||
int ret;
|
||||
int elem_size, elem_index;
|
||||
const char *str = "";
|
||||
struct property *prop;
|
||||
struct jaguar1_regulator *regulator;
|
||||
struct device *dev = &jaguar1->client->dev;
|
||||
struct device_node *np = of_node_get(dev->of_node);
|
||||
|
||||
jaguar1->xvclk = devm_clk_get(dev, "xvclk");
|
||||
if (IS_ERR(jaguar1->xvclk)) {
|
||||
dev_err(dev, "Failed to get xvclk\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = clk_set_rate(jaguar1->xvclk, JAGUAR1_XVCLK_FREQ);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
|
||||
return ret;
|
||||
}
|
||||
if (clk_get_rate(jaguar1->xvclk) != JAGUAR1_XVCLK_FREQ)
|
||||
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
|
||||
|
||||
jaguar1->pinctrl = devm_pinctrl_get(dev);
|
||||
if (!IS_ERR(jaguar1->pinctrl)) {
|
||||
jaguar1->pins_default =
|
||||
pinctrl_lookup_state(jaguar1->pinctrl,
|
||||
OF_CAMERA_PINCTRL_STATE_DEFAULT);
|
||||
if (IS_ERR(jaguar1->pins_default))
|
||||
dev_err(dev, "could not get default pinstate\n");
|
||||
|
||||
jaguar1->pins_sleep =
|
||||
pinctrl_lookup_state(jaguar1->pinctrl,
|
||||
OF_CAMERA_PINCTRL_STATE_SLEEP);
|
||||
if (IS_ERR(jaguar1->pins_sleep))
|
||||
dev_err(dev, "could not get sleep pinstate\n");
|
||||
} else {
|
||||
dev_err(dev, "no pinctrl\n");
|
||||
}
|
||||
|
||||
elem_size = of_property_count_elems_of_size(
|
||||
np,
|
||||
OF_CAMERA_MODULE_REGULATOR_VOLTAGES,
|
||||
sizeof(u32));
|
||||
prop = of_find_property(
|
||||
np,
|
||||
OF_CAMERA_MODULE_REGULATORS,
|
||||
NULL);
|
||||
if (elem_size > 0 && !IS_ERR_OR_NULL(prop)) {
|
||||
jaguar1->regulators.regulator =
|
||||
devm_kzalloc(&jaguar1->client->dev,
|
||||
elem_size * sizeof(struct jaguar1_regulator),
|
||||
GFP_KERNEL);
|
||||
if (!jaguar1->regulators.regulator)
|
||||
dev_err(dev, "could not malloc jaguar1_regulator\n");
|
||||
|
||||
jaguar1->regulators.cnt = elem_size;
|
||||
|
||||
str = NULL;
|
||||
elem_index = 0;
|
||||
regulator = jaguar1->regulators.regulator;
|
||||
do {
|
||||
str = of_prop_next_string(prop, str);
|
||||
if (!str) {
|
||||
dev_err(dev, "%s is not match %s in dts\n",
|
||||
OF_CAMERA_MODULE_REGULATORS,
|
||||
OF_CAMERA_MODULE_REGULATOR_VOLTAGES);
|
||||
break;
|
||||
}
|
||||
regulator->regulator =
|
||||
devm_regulator_get_optional(dev, str);
|
||||
if (IS_ERR(regulator->regulator))
|
||||
dev_err(dev, "devm_regulator_get %s failed\n",
|
||||
str);
|
||||
of_property_read_u32_index(
|
||||
np,
|
||||
OF_CAMERA_MODULE_REGULATOR_VOLTAGES,
|
||||
elem_index++,
|
||||
®ulator->min_uV);
|
||||
regulator->max_uV = regulator->min_uV;
|
||||
regulator++;
|
||||
} while (--elem_size);
|
||||
}
|
||||
|
||||
jaguar1->pd_gpio = devm_gpiod_get(dev, "pd", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(jaguar1->pd_gpio))
|
||||
dev_warn(dev, "can not find pd-gpios, error %ld\n",
|
||||
PTR_ERR(jaguar1->pd_gpio));
|
||||
|
||||
jaguar1->pd2_gpio = devm_gpiod_get(dev, "pd2", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(jaguar1->pd2_gpio))
|
||||
dev_warn(dev, "can not find pd2-gpios, error %ld\n",
|
||||
PTR_ERR(jaguar1->pd2_gpio));
|
||||
|
||||
jaguar1->rst_gpio = devm_gpiod_get(dev, "rst", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(jaguar1->rst_gpio))
|
||||
dev_warn(dev, "can not find rst-gpios, error %ld\n",
|
||||
PTR_ERR(jaguar1->rst_gpio));
|
||||
|
||||
jaguar1->rst2_gpio = devm_gpiod_get(dev, "rst2", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(jaguar1->rst2_gpio))
|
||||
dev_warn(dev, "can not find rst2-gpios, error %ld\n",
|
||||
PTR_ERR(jaguar1->rst2_gpio));
|
||||
|
||||
jaguar1->pwd_gpio = devm_gpiod_get(dev, "pwd", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(jaguar1->pwd_gpio))
|
||||
dev_warn(dev, "can not find pwd-gpios, error %ld\n",
|
||||
PTR_ERR(jaguar1->pwd_gpio));
|
||||
|
||||
jaguar1->pwd2_gpio = devm_gpiod_get(dev, "pwd2", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(jaguar1->pwd2_gpio))
|
||||
dev_warn(dev, "can not find pwd2-gpios, error %ld\n",
|
||||
PTR_ERR(jaguar1->pwd2_gpio));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jaguar1_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct jaguar1 *jaguar1;
|
||||
struct v4l2_subdev *sd;
|
||||
int ret;
|
||||
|
||||
dev_info(dev, "driver version: %02x.%02x.%02x",
|
||||
DRIVER_VERSION >> 16,
|
||||
(DRIVER_VERSION & 0xff00) >> 8,
|
||||
DRIVER_VERSION & 0x00ff);
|
||||
|
||||
jaguar1 = devm_kzalloc(dev, sizeof(*jaguar1), GFP_KERNEL);
|
||||
if (!jaguar1)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
|
||||
&jaguar1->module_index);
|
||||
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
|
||||
&jaguar1->module_facing);
|
||||
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
|
||||
&jaguar1->module_name);
|
||||
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
|
||||
&jaguar1->len_name);
|
||||
if (ret) {
|
||||
dev_err(dev, "could not get %s!\n", RKMODULE_CAMERA_LENS_NAME);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
jaguar1->client = client;
|
||||
|
||||
ret = jaguar1_analyze_dts(jaguar1);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to analyze dts\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_init(&jaguar1->mutex);
|
||||
jaguar1_get_default_format(&jaguar1->format);
|
||||
jaguar1->frame_size = &jaguar1_framesizes[0];
|
||||
|
||||
sd = &jaguar1->subdev;
|
||||
v4l2_i2c_subdev_init(sd, client, &jaguar1_subdev_ops);
|
||||
|
||||
__jaguar1_power_on(jaguar1);
|
||||
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_idle(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jaguar1_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct jaguar1 *jaguar1 = to_jaguar1(sd);
|
||||
|
||||
mutex_destroy(&jaguar1->mutex);
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
if (!pm_runtime_status_suspended(&client->dev))
|
||||
__jaguar1_power_off(jaguar1);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
static const struct of_device_id jaguar1_of_match[] = {
|
||||
{ .compatible = "jaguar1-v4l2" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, jaguar1_of_match);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id jaguar1_match_id[] = {
|
||||
{ "jaguar1-v4l2", 0 },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct i2c_driver jaguar1_i2c_driver = {
|
||||
.driver = {
|
||||
.name = JAGUAR1_NAME,
|
||||
.pm = &jaguar1_pm_ops,
|
||||
.of_match_table = of_match_ptr(jaguar1_of_match),
|
||||
},
|
||||
.probe = &jaguar1_probe,
|
||||
.remove = &jaguar1_remove,
|
||||
.id_table = jaguar1_match_id,
|
||||
};
|
||||
|
||||
static int __init sensor_mod_init(void)
|
||||
{
|
||||
return i2c_add_driver(&jaguar1_i2c_driver);
|
||||
}
|
||||
|
||||
static void __exit sensor_mod_exit(void)
|
||||
{
|
||||
i2c_del_driver(&jaguar1_i2c_driver);
|
||||
}
|
||||
|
||||
device_initcall_sync(sensor_mod_init);
|
||||
module_exit(sensor_mod_exit);
|
||||
|
||||
MODULE_DESCRIPTION("jaguar1 sensor driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
Reference in New Issue
Block a user