msm: ais: Register and listen to bridge-chip interrupts

Changes that help facilitate sending the FPD-III to CSI bridge chip's
input signal status to the user-mode components.

Change-Id: I5e39c75b61f05edc8a1dc77677b9cad85fc563eb
Signed-off-by: Terence Ho <terenceh@codeaurora.org>
Signed-off-by: Andy Sun <bins@codeaurora.org>
This commit is contained in:
Terence Ho 2017-07-05 14:09:12 -04:00 committed by Andy Sun
parent 285229fa97
commit 36463959af
5 changed files with 271 additions and 8 deletions

View file

@ -10,6 +10,12 @@
* GNU General Public License for more details.
*/
#include <media/v4l2-subdev.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
#include "msm_sensor.h"
#include "msm_sd.h"
#include "msm_cci.h"
@ -21,6 +27,7 @@
#undef CDBG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
#define MAX_SENSOR_V4l2_EVENTS 100
static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl;
static struct msm_camera_i2c_fn_t msm_sensor_secure_func_tbl;
@ -405,12 +412,26 @@ static long msm_sensor_subdev_do_ioctl(
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
struct v4l2_fh *vfh = file->private_data;
switch (cmd) {
case VIDIOC_MSM_SENSOR_CFG32:
cmd = VIDIOC_MSM_SENSOR_CFG;
case VIDIOC_DQEVENT: {
if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
return -ENOIOCTLCMD;
return v4l2_event_dequeue(vfh, arg,
file->f_flags & O_NONBLOCK);
}
break;
case VIDIOC_SUBSCRIBE_EVENT:
pr_debug("msm_sensor_subdev_do_ioctl:VIDIOC_SUBSCRIBE_EVENT");
return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
case VIDIOC_UNSUBSCRIBE_EVENT:
return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
default:
return msm_sensor_subdev_ioctl(sd, cmd, arg);
pr_debug("msm_sensor.c msm_sensor_subdev_do_ioctl");
return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
}
}
@ -1459,8 +1480,108 @@ static int msm_sensor_power(struct v4l2_subdev *sd, int on)
return rc;
}
static u32 msm_sensor_evt_mask_to_sensor_event(u32 evt_mask)
{
u32 evt_id = SENSOR_EVENT_SUBS_MASK_NONE;
switch (evt_mask) {
case SENSOR_EVENT_MASK_INDEX_SIGNAL_STATUS:
evt_id = SENSOR_EVENT_SIGNAL_STATUS;
break;
default:
evt_id = SENSOR_EVENT_SUBS_MASK_NONE;
break;
}
return evt_id;
}
static int msm_sensor_subscribe_event_mask(struct v4l2_fh *fh,
struct v4l2_event_subscription *sub, int evt_mask_index,
u32 evt_id, bool subscribe_flag)
{
int rc = 0;
sub->type = evt_id;
if (subscribe_flag)
rc = v4l2_event_subscribe(fh, sub,
MAX_SENSOR_V4l2_EVENTS, NULL);
else
rc = v4l2_event_unsubscribe(fh, sub);
if (rc != 0) {
pr_err("%s: Subs event_type =0x%x failed\n",
__func__, sub->type);
return rc;
}
return rc;
}
static int msm_sensor_process_event_subscription(struct v4l2_fh *fh,
struct v4l2_event_subscription *sub, bool subscribe_flag)
{
int rc = 0, evt_mask_index = 0;
u32 evt_mask = sub->type;
u32 evt_id = 0;
if (SENSOR_EVENT_SUBS_MASK_NONE == evt_mask) {
pr_err("%s: Subs event_type is None=0x%x\n",
__func__, evt_mask);
return 0;
}
evt_mask_index = SENSOR_EVENT_MASK_INDEX_SIGNAL_STATUS;
if (evt_mask & (1<<evt_mask_index)) {
evt_id =
msm_sensor_evt_mask_to_sensor_event(
evt_mask_index);
rc = msm_sensor_subscribe_event_mask(fh, sub,
evt_mask_index, evt_id, subscribe_flag);
if (rc != 0) {
pr_err("%s: Subs event index:%d failed\n",
__func__, evt_mask_index);
return rc;
}
}
return rc;
}
int msm_sensor_send_event(struct msm_sensor_ctrl_t *s_ctrl,
uint32_t event_type,
struct msm_sensor_event_data *event_data)
{
struct v4l2_event sensor_event;
memset(&sensor_event, 0, sizeof(struct v4l2_event));
sensor_event.id = 0;
sensor_event.type = event_type;
memcpy(&sensor_event.u.data[0], event_data,
sizeof(struct msm_sensor_event_data));
v4l2_event_queue(s_ctrl->msm_sd.sd.devnode, &sensor_event);
return 0;
}
static int msm_sensor_subscribe_event(struct v4l2_subdev *sd,
struct v4l2_fh *fh,
struct v4l2_event_subscription *sub)
{
return msm_sensor_process_event_subscription(fh, sub, true);
}
static int msm_sensor_unsubscribe_event(struct v4l2_subdev *sd,
struct v4l2_fh *fh,
struct v4l2_event_subscription *sub)
{
return msm_sensor_process_event_subscription(fh, sub, false);
}
static struct v4l2_subdev_core_ops msm_sensor_subdev_core_ops = {
.ioctl = msm_sensor_subdev_ioctl,
.subscribe_event = msm_sensor_subscribe_event,
.unsubscribe_event = msm_sensor_unsubscribe_event,
.s_power = msm_sensor_power,
};

View file

@ -90,10 +90,18 @@ struct msm_sensor_ctrl_t {
uint32_t set_mclk_23880000;
uint8_t is_csid_tg_mode;
uint32_t is_secure;
/* Interrupt GPIOs */
struct gpio gpio_array[1];
/* device status and Flags */
int irq;
struct msm_sensor_init_t s_init;
/* worker to handle interrupts */
struct delayed_work irq_delayed_work;
};
int msm_sensor_send_event(struct msm_sensor_ctrl_t *s_ctrl,
uint32_t event_type, struct msm_sensor_event_data *event_data);
int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void *argp);
int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl);

View file

@ -132,6 +132,7 @@ static int32_t msm_sensor_driver_create_v4l_subdev
s_ctrl->sensordata->sensor_name);
v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, s_ctrl->pdev);
s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0);
s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR;
@ -143,6 +144,8 @@ static int32_t msm_sensor_driver_create_v4l_subdev
return rc;
}
msm_cam_copy_v4l2_subdev_fops(&msm_sensor_v4l2_subdev_fops);
msm_sensor_v4l2_subdev_fops.unlocked_ioctl =
msm_sensor_subdev_fops_ioctl;
#ifdef CONFIG_COMPAT
msm_sensor_v4l2_subdev_fops.compat_ioctl32 =
msm_sensor_subdev_fops_ioctl;
@ -632,6 +635,56 @@ static void msm_sensor_fill_sensor_info(struct msm_sensor_ctrl_t *s_ctrl,
strlcpy(entity_name, s_ctrl->msm_sd.sd.entity.name, MAX_SENSOR_NAME);
}
static irqreturn_t bridge_irq(int irq, void *dev)
{
struct msm_sensor_ctrl_t *s_ctrl = dev;
pr_err("msm_sensor_driver: received bridge interrupt:0x%x",
s_ctrl->sensordata->slave_info->sensor_slave_addr);
schedule_delayed_work(&s_ctrl->irq_delayed_work,
msecs_to_jiffies(0));
return IRQ_HANDLED;
}
static void bridge_irq_delay_work(struct work_struct *work)
{
struct msm_sensor_ctrl_t *s_ctrl;
struct msm_camera_i2c_client *sensor_i2c_client;
struct msm_camera_slave_info *slave_info;
const char *sensor_name;
struct msm_sensor_event_data sensor_event;
s_ctrl = container_of(work, struct msm_sensor_ctrl_t,
irq_delayed_work.work);
if (!s_ctrl) {
pr_err("%s:%d failed: %pK\n",
__func__, __LINE__, s_ctrl);
goto exit_queue;
}
sensor_i2c_client = s_ctrl->sensor_i2c_client;
slave_info = s_ctrl->sensordata->slave_info;
sensor_name = s_ctrl->sensordata->sensor_name;
if (!sensor_i2c_client || !slave_info || !sensor_name) {
pr_err("%s:%d failed: %pK %pK %pK\n",
__func__, __LINE__, sensor_i2c_client, slave_info,
sensor_name);
goto exit_queue;
}
mutex_lock(s_ctrl->msm_sensor_mutex);
/* Fill the sensor event */
sensor_event.sensor_slave_addr =
slave_info->sensor_slave_addr;
/* Queue the event */
msm_sensor_send_event(s_ctrl, SENSOR_EVENT_SIGNAL_STATUS,
&sensor_event);
mutex_unlock(s_ctrl->msm_sensor_mutex);
exit_queue:
pr_err("Work IRQ exit");
}
/* static function definition */
int32_t msm_sensor_driver_probe(void *setting,
struct msm_sensor_info_t *probed_info, char *entity_name)
@ -934,12 +987,66 @@ CSID_TG:
msm_sensor_fill_sensor_info(s_ctrl, probed_info, entity_name);
/* Set probe succeeded flag to 1 so that no other camera shall
* probed on this slot
*/
if (slave_info->gpio_intr_config.gpio_num != -1) {
/* Configure INTB interrupt */
s_ctrl->gpio_array[0].gpio =
slave_info->gpio_intr_config.gpio_num;
s_ctrl->gpio_array[0].flags = 0;
/* Only setup IRQ1 for now... */
INIT_DELAYED_WORK(&s_ctrl->irq_delayed_work,
bridge_irq_delay_work);
rc = gpio_request_array(&s_ctrl->gpio_array[0], 1);
if (rc < 0) {
pr_err("%s: Failed to request irq_gpio %d",
__func__, rc);
goto cancel_work;
}
if (gpio_is_valid(s_ctrl->gpio_array[0].gpio)) {
rc |= gpio_direction_input(
s_ctrl->gpio_array[0].gpio);
if (rc) {
pr_err("%s: Failed gpio_direction irq %d",
__func__, rc);
goto cancel_work;
} else {
pr_err("sensor probe IRQ direction succeeded");
}
}
s_ctrl->irq = gpio_to_irq(s_ctrl->gpio_array[0].gpio);
if (s_ctrl->irq) {
rc = request_irq(s_ctrl->irq, bridge_irq,
IRQF_ONESHOT |
(slave_info->
gpio_intr_config.gpio_trigger),
"qcom,camera", s_ctrl);
if (rc) {
pr_err("%s: Failed request_irq %d",
__func__, rc);
goto cancel_work;
}
} else {
pr_err("%s: Failed gpio_to_irq %d",
__func__, rc);
rc = -EINVAL;
goto cancel_work;
}
/* Keep irq enabled */
pr_err("msm_sensor_driver.c irq number = %d", s_ctrl->irq);
}
/*
Set probe succeeded flag to 1 so that no other camera shall
* probed on this slot
*/
s_ctrl->is_probe_succeed = 1;
return rc;
cancel_work:
cancel_delayed_work(&s_ctrl->irq_delayed_work);
free_camera_info:
kfree(camera_info);
free_slave_info:
@ -1125,7 +1232,6 @@ static int32_t msm_sensor_driver_parse(struct msm_sensor_ctrl_t *s_ctrl)
/* Store sensor control structure in static database */
g_sctrl[s_ctrl->id] = s_ctrl;
CDBG("g_sctrl[%d] %pK", s_ctrl->id, g_sctrl[s_ctrl->id]);
return rc;
FREE_DT_DATA:
@ -1178,7 +1284,6 @@ static int32_t msm_sensor_driver_platform_probe(struct platform_device *pdev)
/* Fill platform device id*/
pdev->id = s_ctrl->id;
/* Fill device in power info */
s_ctrl->sensordata->power_info.dev = &pdev->dev;

View file

@ -178,6 +178,27 @@ enum cci_i2c_master_t {
MASTER_MAX,
};
struct msm_sensor_event_data {
uint16_t sensor_slave_addr;
};
enum msm_sensor_event_mask_index {
SENSOR_EVENT_MASK_INDEX_SIGNAL_STATUS = 2,
};
#define SENSOR_EVENT_SUBS_MASK_NONE 0
#define SENSOR_EVENT_SUBS_MASK_SIGNAL_STATUS \
(1 << SENSOR_EVENT_MASK_INDEX_SIGNAL_STATUS)
enum msm_sensor_event_idx {
SENSOR_SIGNAL_STATUS = 2,
SENSOR_EVENT_MAX = 15
};
#define SENSOR_EVENT_BASE (V4L2_EVENT_PRIVATE_START)
#define SENSOR_EVENT_SIGNAL_STATUS (SENSOR_EVENT_BASE + SENSOR_SIGNAL_STATUS)
struct msm_camera_i2c_array_write_config {
struct msm_camera_i2c_reg_setting conf_array;
uint16_t slave_addr;

View file

@ -285,6 +285,11 @@ struct msm_sensor_id_info_t {
unsigned short sensor_id_mask;
};
struct msm_camera_sensor_gpio_intr_config {
int gpio_num;
uint32_t gpio_trigger;
};
struct msm_camera_sensor_slave_info {
char sensor_name[32];
char eeprom_name[32];
@ -300,6 +305,9 @@ struct msm_camera_sensor_slave_info {
unsigned char is_init_params_valid;
struct msm_sensor_init_params sensor_init_params;
enum msm_sensor_output_format_t output_format;
struct msm_camera_sensor_gpio_intr_config
gpio_intr_config;
unsigned int camera_sensor_device_id;
};
struct msm_camera_i2c_reg_array {