oleavr-rgl-a500-mini-linux-.../drivers/media/platform/sunxi-vfe/flash_light/flash.c
Ole André Vadla Ravnås 169c65d57e Initial commit
2022-05-07 01:01:45 +02:00

391 lines
9.7 KiB
C
Executable file

/*
* linux-3.10/drivers/media/platform/sunxi-vfe/flash_light/flash.c
*
* Copyright (c) 2007-2017 Allwinnertech Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*
***************************************************************************************
*
* sunxi_flash.c
*
* Hawkview ISP - sunxi_flash.c module
*
* Copyright (c) 2015 by Allwinnertech Co., Ltd. http://www.allwinnertech.com
*
* Version Author Date Description
*
* 3.0 Yang Feng 2015/02/27 ISP Tuning Tools Support
*
****************************************************************************************
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mediabus.h>
#include <media/v4l2-subdev.h>
#include "../vfe_os.h"
#include "../platform_cfg.h"
#include "../vfe.h"
#include "flash.h"
#define FLASH_EN_POL 1
#define FLASH_MODE_POL 1
struct flash_dev *flash_gbl;
static int flash_power_flag = 0;
int io_set_flash_ctrl(struct v4l2_subdev *sd, enum sunxi_flash_ctrl ctrl)
{
int ret=0;
unsigned int flash_en, flash_dis, flash_mode, torch_mode;
struct flash_dev_info *fls_info = &flash_gbl->fl_info;
if(!flash_gbl->flash_used)
return 0;
if(NULL == fls_info || NULL == sd)
{
vfe_err("error flash config!\n");
return -1;
}
flash_en=(fls_info->en_pol!=0)?1:0;
flash_dis=!flash_en;
flash_mode=(fls_info->fl_mode_pol!=0)?1:0;
torch_mode=!flash_mode;
if(FLASH_RELATING == fls_info->flash_driver_ic)
{
switch(ctrl) {
case SW_CTRL_FLASH_OFF:
vfe_dbg(0,"FLASH_RELATING SW_CTRL_FLASH_OFF\n");
vfe_gpio_set_status(sd,FLASH_EN,1);//set the gpio to output
vfe_gpio_set_status(sd,FLASH_MODE,1);//set the gpio to output
ret|=vfe_gpio_write(sd, FLASH_EN, flash_dis);
ret|=vfe_gpio_write(sd, FLASH_MODE, torch_mode);
//vfe_gpio_set_status(sd,FLASH_EN,0);//set the gpio to hi-z
//vfe_gpio_set_status(sd,FLASH_MODE,0);//set the gpio to hi-z
break;
case SW_CTRL_FLASH_ON:
vfe_dbg(0,"FLASH_RELATING SW_CTRL_FLASH_ON\n");
vfe_gpio_set_status(sd,FLASH_EN,1);//set the gpio to output
vfe_gpio_set_status(sd,FLASH_MODE,1);//set the gpio to output
ret|=vfe_gpio_write(sd, FLASH_MODE, flash_mode);
ret|=vfe_gpio_write(sd, FLASH_EN, flash_en);
break;
case SW_CTRL_TORCH_ON:
vfe_dbg(0,"FLASH_RELATING SW_CTRL_TORCH_ON\n");
vfe_gpio_set_status(sd,FLASH_EN,1);//set the gpio to output
vfe_gpio_set_status(sd,FLASH_MODE,1);//set the gpio to output
ret|=vfe_gpio_write(sd, FLASH_MODE, torch_mode);
ret|=vfe_gpio_write(sd, FLASH_EN, flash_en);
break;
default:
return -EINVAL;
}
}
else if(FLASH_EN_INDEPEND == fls_info->flash_driver_ic)
{
switch(ctrl) {
case SW_CTRL_FLASH_OFF:
vfe_dbg(0,"FLASH_EN_INDEPEND SW_CTRL_FLASH_OFF\n");
vfe_gpio_set_status(sd,FLASH_EN,1);//set the gpio to output
vfe_gpio_set_status(sd,FLASH_MODE,1);//set the gpio to output
ret|=vfe_gpio_write(sd, FLASH_EN, 0);
ret|=vfe_gpio_write(sd, FLASH_MODE, 0);
//vfe_gpio_set_status(sd,FLASH_EN,0);//set the gpio to hi-z
//vfe_gpio_set_status(sd,FLASH_MODE,0);//set the gpio to hi-z
break;
case SW_CTRL_FLASH_ON:
vfe_dbg(0,"FLASH_EN_INDEPEND SW_CTRL_FLASH_ON\n");
vfe_gpio_set_status(sd,FLASH_EN,1);//set the gpio to output
vfe_gpio_set_status(sd,FLASH_MODE,1);//set the gpio to output
ret|=vfe_gpio_write(sd, FLASH_MODE, 1);
ret|=vfe_gpio_write(sd, FLASH_EN, 0);
break;
case SW_CTRL_TORCH_ON:
vfe_dbg(0,"FLASH_EN_INDEPEND SW_CTRL_TORCH_ON\n");
vfe_gpio_set_status(sd,FLASH_EN,1);//set the gpio to output
vfe_gpio_set_status(sd,FLASH_MODE,1);//set the gpio to output
ret|=vfe_gpio_write(sd, FLASH_MODE, 0);
ret|=vfe_gpio_write(sd, FLASH_EN, 1);
break;
default:
return -EINVAL;
}
}
else
{
switch(ctrl) {
case SW_CTRL_FLASH_OFF:
vfe_dbg(0,"FLASH_POWER SW_CTRL_FLASH_OFF\n");
if (1 == flash_power_flag)
{
vfe_set_pmu_channel(sd,FLVDD,OFF);
flash_power_flag --;
}
break;
case SW_CTRL_FLASH_ON:
vfe_dbg(0,"FLASH_POWER SW_CTRL_FLASH_ON\n");
if (0 == flash_power_flag)
{
vfe_set_pmu_channel(sd,FLVDD,ON);
flash_power_flag ++;
}
break;
case SW_CTRL_TORCH_ON:
vfe_dbg(0,"FLASH_POWER SW_CTRL_TORCH_ON\n");
if (0 == flash_power_flag)
{
vfe_set_pmu_channel(sd,FLVDD,ON);
flash_power_flag ++;
}
break;
default:
return -EINVAL;
}
}
if(ret!=0)
{
vfe_dbg(0,"flash set ctrl fail, force shut off\n");
ret|=vfe_gpio_write(sd, FLASH_EN, flash_dis);
ret|=vfe_gpio_write(sd, FLASH_MODE, torch_mode);
}
return ret;
}
int sunxi_flash_check_to_start(struct v4l2_subdev *sd, enum sunxi_flash_ctrl ctrl)
{
struct vfe_dev *dev = (sd == NULL) ? NULL :
(struct vfe_dev *)dev_get_drvdata(sd->v4l2_dev->dev);
unsigned int flag, to_flash;
if(!flash_gbl->flash_used)
return 0;
if (NULL == sd) {
vfe_err("flash sd is NULL!\n");
return -1;
}
if (flash_gbl->fl_info.flash_mode ==V4L2_FLASH_LED_MODE_FLASH) {
to_flash = 1;
} else if (flash_gbl->fl_info.flash_mode ==V4L2_FLASH_LED_MODE_AUTO) {
v4l2_subdev_call(dev->sd, core, ioctl, GET_FLASH_FLAG, &flag);
if(flag)
to_flash = 1;
else
to_flash = 0;
} else {
to_flash = 0;
}
if(to_flash)
io_set_flash_ctrl(sd, ctrl);
return 0;
}
int sunxi_flash_stop(struct v4l2_subdev *sd)
{
if(!flash_gbl->flash_used)
return 0;
if (NULL == sd) {
vfe_err("flash sd is NULL!\n");
return -1;
}
if(flash_gbl->fl_info.flash_mode != V4L2_FLASH_LED_MODE_NONE)
io_set_flash_ctrl(sd, SW_CTRL_FLASH_OFF);
return 0;
}
static int config_flash_mode(struct v4l2_subdev *sd,
enum v4l2_flash_led_mode mode,
struct flash_dev_info *fls_info)
{
if(fls_info==NULL)
{
vfe_err("camera flash not support!\n");
return -1;
}
if((fls_info->light_src!=0x01)&&(fls_info->light_src!=0x02)&&(fls_info->light_src!=0x10))
{
vfe_err("unsupported light source, force LEDx1\n");
fls_info->light_src=0x01;
}
fls_info->flash_mode = mode;
if(mode == V4L2_FLASH_LED_MODE_TORCH)
{
io_set_flash_ctrl(sd, SW_CTRL_TORCH_ON);
}
else if(mode == V4L2_FLASH_LED_MODE_NONE)
{
io_set_flash_ctrl(sd, SW_CTRL_FLASH_OFF);
}
return 0;
}
static int sunxi_flash_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
{
switch (qc->id) {
case V4L2_CID_FLASH_LED_MODE:
return v4l2_ctrl_query_fill(qc, 0, 5, 1, 0);
default:
break;
}
return -EINVAL;
}
static int sunxi_flash_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
switch (ctrl->id) {
case V4L2_CID_FLASH_LED_MODE:
ctrl->value = flash_gbl->fl_info.flash_mode;
return 0;
default:
break;
}
return -EINVAL;
}
static int sunxi_flash_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
int ret;
struct v4l2_queryctrl qc;
qc.id = ctrl->id;
ret = sunxi_flash_queryctrl(sd, &qc);
if (ret < 0) {
return ret;
}
if (ctrl->value < qc.minimum || ctrl->value > qc.maximum) {
return -ERANGE;
}
switch (ctrl->id) {
case V4L2_CID_FLASH_LED_MODE:
return config_flash_mode(sd, ctrl->value, &flash_gbl->fl_info);
default:
break;
}
return -EINVAL;
}
static const struct v4l2_subdev_core_ops sunxi_flash_core_ops = {
.g_ctrl = sunxi_flash_g_ctrl,
.s_ctrl = sunxi_flash_s_ctrl,
};
static struct v4l2_subdev_ops sunxi_flash_subdev_ops = {
.core = &sunxi_flash_core_ops,
};
int sunxi_flash_info_init(struct v4l2_subdev *sd)
{
struct vfe_dev *dev = (sd == NULL) ? NULL :
(struct vfe_dev *)dev_get_drvdata(sd->v4l2_dev->dev);
flash_gbl->flash_used = dev->flash_used;
if(!flash_gbl->flash_used)
return 0;
if (NULL == sd) {
vfe_err("flash sd is NULL!\n");
return 0;
}
flash_gbl->fl_info.dev_if=0;
flash_gbl->fl_info.en_pol=FLASH_EN_POL;
flash_gbl->fl_info.fl_mode_pol=FLASH_MODE_POL;
flash_gbl->fl_info.light_src=0x01;
flash_gbl->fl_info.flash_intensity=400;
flash_gbl->fl_info.flash_level=0x01;
flash_gbl->fl_info.torch_intensity=200;
flash_gbl->fl_info.torch_level=0x01;
flash_gbl->fl_info.timeout_counter=300*1000;
flash_gbl->fl_info.flash_driver_ic = dev->flash_type;
config_flash_mode(sd, V4L2_FLASH_LED_MODE_NONE, &flash_gbl->fl_info);
return 0;
}
static int sunxi_flash_subdev_init(struct flash_dev *flash)
{
struct v4l2_subdev *sd = &flash->subdev;
v4l2_subdev_init(sd, &sunxi_flash_subdev_ops);
snprintf(sd->name, sizeof(sd->name), "sunxi_flash");
v4l2_set_subdevdata(sd, flash);
return 0;
}
static int sunxi_flash_probe(void)
{
struct flash_dev *flash = NULL;
int ret = 0;
flash = kzalloc(sizeof(struct flash_dev), GFP_KERNEL);
if (!flash) {
ret = -ENOMEM;
vfe_err("sunxi flash kzalloc failed!\n");
goto ekzalloc;
}
flash_gbl = flash;
sunxi_flash_subdev_init(flash);
ekzalloc:
return ret;
}
static int sunxi_flash_remove(struct flash_dev *flash)
{
kfree(flash);
return 0;
}
int sunxi_flash_register_subdev(struct v4l2_device *v4l2_dev, struct v4l2_subdev *sd)
{
return v4l2_device_register_subdev(v4l2_dev, sd);
}
void sunxi_flash_unregister_subdev(struct v4l2_subdev *sd)
{
v4l2_device_unregister_subdev(sd);
v4l2_set_subdevdata(sd, NULL);
}
int sunxi_flash_get_subdev(struct v4l2_subdev **sd, int sel)
{
*sd = &flash_gbl->subdev;
return 0;
}
int sunxi_flash_put_subdev(struct v4l2_subdev **sd, int sel)
{
*sd = NULL;
return 0;
}
int sunxi_flash_platform_register(void)
{
sunxi_flash_probe();
vfe_print("flash_init end\n");
return 0;
}
void sunxi_flash_platform_unregister(void)
{
vfe_print("flash_exit start\n");
sunxi_flash_remove(flash_gbl);
vfe_print("flash_exit end\n");
}