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:
parent
285229fa97
commit
36463959af
5 changed files with 271 additions and 8 deletions
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue