msm: camera: Add I2C mux control driver
add i2c mux control driver to control i2c bus
The driver will control which camera the i2c
control message will send to. (etc left, right, both)
Change-Id: I592701b8445d6acc8dfc60f81d562ee52dd65971
Signed-off-by: Kevin Chan <ktchan@codeaurora.org>
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 4525bab..0c1d4ab 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1134,27 +1134,27 @@
};
#ifdef CONFIG_MSM_CAMERA
-struct resource msm_camera_resources[] = {
+static struct resource msm_cam_gsbi4_i2c_mux_resources[] = {
{
- .name = "s3d_rw",
+ .name = "i2c_mux_rw",
.start = 0x008003E0,
- .end = 0x008003E0 + SZ_16 - 1,
+ .end = 0x008003E0 + SZ_8 - 1,
.flags = IORESOURCE_MEM,
},
{
- .name = "s3d_ctl",
+ .name = "i2c_mux_ctl",
.start = 0x008020B8,
- .end = 0x008020B8 + SZ_16 - 1,
+ .end = 0x008020B8 + SZ_4 - 1,
.flags = IORESOURCE_MEM,
},
};
-int __init msm_get_cam_resources(struct msm_camera_sensor_info *s_info)
-{
- s_info->resource = msm_camera_resources;
- s_info->num_resources = ARRAY_SIZE(msm_camera_resources);
- return 0;
-}
+struct platform_device msm8960_device_i2c_mux_gsbi4 = {
+ .name = "msm_cam_i2c_mux",
+ .id = 0,
+ .resource = msm_cam_gsbi4_i2c_mux_resources,
+ .num_resources = ARRAY_SIZE(msm_cam_gsbi4_i2c_mux_resources),
+};
static struct resource msm_csiphy0_resources[] = {
{
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index c4f57ab..78cb73e 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -59,6 +59,7 @@
extern struct platform_device msm8960_device_qup_i2c_gsbi12;
extern struct platform_device msm8960_device_qup_spi_gsbi1;
extern struct platform_device msm8960_gemini_device;
+extern struct platform_device msm8960_device_i2c_mux_gsbi4;
extern struct platform_device msm8960_device_csiphy0;
extern struct platform_device msm8960_device_csiphy1;
extern struct platform_device msm8960_device_csid0;
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index ba9fc70..5d22d66 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -202,6 +202,18 @@
uint8_t cam_gpio_set_tbl_size;
};
+enum msm_camera_i2c_mux_mode {
+ MODE_R,
+ MODE_L,
+ MODE_DUAL
+};
+
+struct msm_camera_i2c_conf {
+ uint8_t use_i2c_mux;
+ struct platform_device *mux_dev;
+ enum msm_camera_i2c_mux_mode i2c_mux_mode;
+};
+
struct msm_camera_sensor_platform_info {
int mount_angle;
int sensor_reset;
@@ -209,6 +221,7 @@
int num_vreg;
int32_t (*ext_power_ctrl) (int enable);
struct msm_camera_gpio_conf *gpio_conf;
+ struct msm_camera_i2c_conf *i2c_conf;
};
struct msm_actuator_info {
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 700e28c..ef7be45 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -631,12 +631,6 @@
S_EXIT
};
-enum msm_cam_mode {
- MODE_R,
- MODE_L,
- MODE_DUAL
-};
-
struct msm_cam_clk_info {
const char *clk_name;
long clk_rate;
@@ -648,7 +642,7 @@
int msm_camio_vpe_clk_enable(uint32_t);
int msm_camio_vpe_clk_disable(void);
-void msm_camio_mode_config(enum msm_cam_mode mode);
+void msm_camio_mode_config(enum msm_camera_i2c_mux_mode mode);
int msm_camio_clk_enable(enum msm_camio_clk_type clk);
int msm_camio_clk_disable(enum msm_camio_clk_type clk);
int msm_camio_clk_config(uint32_t freq);
diff --git a/drivers/media/video/msm/io/Makefile b/drivers/media/video/msm/io/Makefile
index 584738d..c567be2 100644
--- a/drivers/media/video/msm/io/Makefile
+++ b/drivers/media/video/msm/io/Makefile
@@ -1,3 +1,4 @@
GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
-obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c.o msm_camera_eeprom.o
+EXTRA_CFLAGS += -Idrivers/media/video/msm
+obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c.o msm_camera_eeprom.o msm_camera_i2c_mux.o
obj-$(CONFIG_MSM_CAMERA) += msm_io_util.o
diff --git a/drivers/media/video/msm/io/msm_camera_i2c_mux.c b/drivers/media/video/msm/io/msm_camera_i2c_mux.c
new file mode 100644
index 0000000..ad3128b
--- /dev/null
+++ b/drivers/media/video/msm/io/msm_camera_i2c_mux.c
@@ -0,0 +1,186 @@
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include "msm.h"
+#include "msm_camera_i2c_mux.h"
+
+static int msm_i2c_mux_config(struct i2c_mux_device *mux_device, uint8_t *mode)
+{
+ uint32_t val;
+ val = msm_io_r(mux_device->ctl_base);
+ if (*mode == MODE_DUAL) {
+ msm_io_w(val | 0x3, mux_device->ctl_base);
+ } else if (*mode == MODE_L) {
+ msm_io_w(((val | 0x2) & ~(0x1)), mux_device->ctl_base);
+ val = msm_io_r(mux_device->ctl_base);
+ CDBG("the camio mode config left value is %d\n", val);
+ } else {
+ msm_io_w(((val | 0x1) & ~(0x2)), mux_device->ctl_base);
+ val = msm_io_r(mux_device->ctl_base);
+ CDBG("the camio mode config right value is %d\n", val);
+ }
+ return 0;
+}
+
+static int msm_i2c_mux_init(struct i2c_mux_device *mux_device)
+{
+ int rc = 0, val = 0;
+ if (mux_device->use_count == 0) {
+ mux_device->ctl_base = ioremap(mux_device->ctl_mem->start,
+ resource_size(mux_device->ctl_mem));
+ if (!mux_device->ctl_base) {
+ rc = -ENOMEM;
+ return rc;
+ }
+ mux_device->rw_base = ioremap(mux_device->rw_mem->start,
+ resource_size(mux_device->rw_mem));
+ if (!mux_device->rw_base) {
+ rc = -ENOMEM;
+ iounmap(mux_device->ctl_base);
+ return rc;
+ }
+ val = msm_io_r(mux_device->rw_base);
+ msm_io_w((val | 0x200), mux_device->rw_base);
+ }
+ mux_device->use_count++;
+ return 0;
+};
+
+static int msm_i2c_mux_release(struct i2c_mux_device *mux_device)
+{
+ int val = 0;
+ mux_device->use_count--;
+ if (mux_device->use_count == 0) {
+ val = msm_io_r(mux_device->rw_base);
+ msm_io_w((val & ~0x200), mux_device->rw_base);
+ iounmap(mux_device->rw_base);
+ iounmap(mux_device->ctl_base);
+ }
+ return 0;
+}
+
+static long msm_i2c_mux_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ struct i2c_mux_device *mux_device;
+ int rc = 0;
+ mux_device = v4l2_get_subdevdata(sd);
+ if (mux_device == NULL) {
+ rc = -ENOMEM;
+ return rc;
+ }
+ mutex_lock(&mux_device->mutex);
+ switch (cmd) {
+ case VIDIOC_MSM_I2C_MUX_CFG:
+ rc = msm_i2c_mux_config(mux_device, (uint8_t *) arg);
+ break;
+ case VIDIOC_MSM_I2C_MUX_INIT:
+ rc = msm_i2c_mux_init(mux_device);
+ break;
+ case VIDIOC_MSM_I2C_MUX_RELEASE:
+ rc = msm_i2c_mux_release(mux_device);
+ break;
+ default:
+ rc = -ENOIOCTLCMD;
+ }
+ mutex_unlock(&mux_device->mutex);
+ return rc;
+}
+
+static struct v4l2_subdev_core_ops msm_i2c_mux_subdev_core_ops = {
+ .ioctl = &msm_i2c_mux_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_i2c_mux_subdev_ops = {
+ .core = &msm_i2c_mux_subdev_core_ops,
+};
+
+static int __devinit i2c_mux_probe(struct platform_device *pdev)
+{
+ struct i2c_mux_device *mux_device;
+ int rc = 0;
+ CDBG("%s: device id = %d\n", __func__, pdev->id);
+ mux_device = kzalloc(sizeof(struct i2c_mux_device), GFP_KERNEL);
+ if (!mux_device) {
+ pr_err("%s: no enough memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ v4l2_subdev_init(&mux_device->subdev, &msm_i2c_mux_subdev_ops);
+ v4l2_set_subdevdata(&mux_device->subdev, mux_device);
+ platform_set_drvdata(pdev, &mux_device->subdev);
+ mutex_init(&mux_device->mutex);
+
+ mux_device->ctl_mem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "i2c_mux_ctl");
+ if (!mux_device->ctl_mem) {
+ pr_err("%s: no mem resource?\n", __func__);
+ rc = -ENODEV;
+ goto i2c_mux_no_resource;
+ }
+ mux_device->ctl_io = request_mem_region(mux_device->ctl_mem->start,
+ resource_size(mux_device->ctl_mem), pdev->name);
+ if (!mux_device->ctl_io) {
+ pr_err("%s: no valid mem region\n", __func__);
+ rc = -EBUSY;
+ goto i2c_mux_no_resource;
+ }
+ mux_device->rw_mem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "i2c_mux_rw");
+ if (!mux_device->rw_mem) {
+ pr_err("%s: no mem resource?\n", __func__);
+ rc = -ENODEV;
+ goto i2c_mux_no_resource;
+ }
+ mux_device->rw_io = request_mem_region(mux_device->rw_mem->start,
+ resource_size(mux_device->rw_mem), pdev->name);
+ if (!mux_device->rw_io) {
+ pr_err("%s: no valid mem region\n", __func__);
+ rc = -EBUSY;
+ goto i2c_mux_no_resource;
+ }
+ mux_device->pdev = pdev;
+ return 0;
+
+i2c_mux_no_resource:
+ mutex_destroy(&mux_device->mutex);
+ kfree(mux_device);
+ return 0;
+}
+
+static struct platform_driver i2c_mux_driver = {
+ .probe = i2c_mux_probe,
+ .driver = {
+ .name = MSM_I2C_MUX_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_camera_i2c_mux_init_module(void)
+{
+ return platform_driver_register(&i2c_mux_driver);
+}
+
+static void __exit msm_camera_i2c_mux_exit_module(void)
+{
+ platform_driver_unregister(&i2c_mux_driver);
+}
+
+module_init(msm_camera_i2c_mux_init_module);
+module_exit(msm_camera_i2c_mux_exit_module);
+MODULE_DESCRIPTION("MSM Camera I2C mux driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/io/msm_camera_i2c_mux.h b/drivers/media/video/msm/io/msm_camera_i2c_mux.h
new file mode 100644
index 0000000..94394fc
--- /dev/null
+++ b/drivers/media/video/msm/io/msm_camera_i2c_mux.h
@@ -0,0 +1,46 @@
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef MSM_I2C_MUX_H
+#define MSM_I2C_MUX_H
+
+#include <linux/io.h>
+#include <media/v4l2-subdev.h>
+
+struct i2c_mux_device {
+ struct platform_device *pdev;
+ struct v4l2_subdev subdev;
+ struct resource *ctl_mem;
+ struct resource *ctl_io;
+ void __iomem *ctl_base;
+ struct resource *rw_mem;
+ struct resource *rw_io;
+ void __iomem *rw_base;
+ struct mutex mutex;
+ unsigned use_count;
+};
+
+struct i2c_mux_cfg_params {
+ struct v4l2_subdev *subdev;
+ void *parms;
+};
+
+#define VIDIOC_MSM_I2C_MUX_CFG \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct i2c_mux_cfg_params)
+
+#define VIDIOC_MSM_I2C_MUX_INIT \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct v4l2_subdev*)
+
+#define VIDIOC_MSM_I2C_MUX_RELEASE \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct v4l2_subdev*)
+
+#endif
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 40bc160..55c0da1 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -48,6 +48,7 @@
#define MSM_VFE_DRV_NAME "msm_vfe"
#define MSM_VPE_DRV_NAME "msm_vpe"
#define MSM_GEMINI_DRV_NAME "msm_gemini"
+#define MSM_I2C_MUX_DRV_NAME "msm_cam_i2c_mux"
/* msm queue management APIs*/
diff --git a/drivers/media/video/msm/msm_io_8960.c b/drivers/media/video/msm/msm_io_8960.c
index d111452..ea969cf 100644
--- a/drivers/media/video/msm/msm_io_8960.c
+++ b/drivers/media/video/msm/msm_io_8960.c
@@ -32,11 +32,6 @@
static struct clk *camio_imem_clk;
static struct regulator *fs_ijpeg;
-static struct platform_device *camio_dev;
-static struct resource *s3drw_io, *s3dctl_io;
-static struct resource *s3drw_mem, *s3dctl_mem;
-void __iomem *s3d_rw, *s3d_ctl;
-
void msm_io_w(u32 data, void __iomem *addr)
{
CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
@@ -234,89 +229,6 @@
return rc;
}
-int32_t msm_camio_3d_enable(const struct msm_camera_sensor_info *s_info)
-{
- int32_t val = 0, rc = 0;
- char s3drw[] = "s3d_rw";
- char s3dctl[] = "s3d_ctl";
- struct platform_device *pdev = camio_dev;
- pdev->resource = s_info->resource;
- pdev->num_resources = s_info->num_resources;
-
- s3drw_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, s3drw);
- if (!s3drw_mem) {
- pr_err("%s: no mem resource?\n", __func__);
- return -ENODEV;
- }
- s3dctl_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, s3dctl);
- if (!s3dctl_mem) {
- pr_err("%s: no mem resource?\n", __func__);
- return -ENODEV;
- }
- s3drw_io = request_mem_region(s3drw_mem->start,
- resource_size(s3drw_mem), pdev->name);
- if (!s3drw_io)
- return -EBUSY;
-
- s3d_rw = ioremap(s3drw_mem->start,
- resource_size(s3drw_mem));
- if (!s3d_rw) {
- rc = -ENOMEM;
- goto s3drw_nomem;
- }
- s3dctl_io = request_mem_region(s3dctl_mem->start,
- resource_size(s3dctl_mem), pdev->name);
- if (!s3dctl_io) {
- rc = -EBUSY;
- goto s3dctl_busy;
- }
- s3d_ctl = ioremap(s3dctl_mem->start,
- resource_size(s3dctl_mem));
- if (!s3d_ctl) {
- rc = -ENOMEM;
- goto s3dctl_nomem;
- }
-
- val = msm_io_r(s3d_rw);
- msm_io_w((val | 0x200), s3d_rw);
- return rc;
-
-s3dctl_nomem:
- release_mem_region(s3dctl_mem->start, resource_size(s3dctl_mem));
-s3dctl_busy:
- iounmap(s3d_rw);
-s3drw_nomem:
- release_mem_region(s3drw_mem->start, resource_size(s3drw_mem));
-return rc;
-}
-
-void msm_camio_3d_disable(void)
-{
- int32_t val = 0;
- msm_io_w((val & ~0x200), s3d_rw);
- iounmap(s3d_ctl);
- release_mem_region(s3dctl_mem->start, resource_size(s3dctl_mem));
- iounmap(s3d_rw);
- release_mem_region(s3drw_mem->start, resource_size(s3drw_mem));
-}
-
-void msm_camio_mode_config(enum msm_cam_mode mode)
-{
- uint32_t val;
- val = msm_io_r(s3d_ctl);
- if (mode == MODE_DUAL) {
- msm_io_w(val | 0x3, s3d_ctl);
- } else if (mode == MODE_L) {
- msm_io_w(((val | 0x2) & ~(0x1)), s3d_ctl);
- val = msm_io_r(s3d_ctl);
- CDBG("the camio mode config left value is %d\n", val);
- } else {
- msm_io_w(((val | 0x1) & ~(0x2)), s3d_ctl);
- val = msm_io_r(s3d_ctl);
- CDBG("the camio mode config right value is %d\n", val);
- }
-}
-
void msm_camio_bus_scale_cfg(struct msm_bus_scale_pdata *cam_bus_scale_table,
enum msm_bus_perf_setting perf_setting)
{
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index d0b4f1f..cade3d6 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -13,6 +13,7 @@
#include "msm_sensor.h"
#include "msm.h"
#include "msm_ispif.h"
+#include "msm_camera_i2c_mux.h"
/*=============================================================*/
@@ -449,6 +450,26 @@
{"cam_clk", MSM_SENSOR_MCLK_24HZ},
};
+int32_t msm_sensor_enable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf)
+{
+ struct v4l2_subdev *i2c_mux_sd =
+ dev_get_drvdata(&i2c_conf->mux_dev->dev);
+ v4l2_subdev_call(i2c_mux_sd, core, ioctl,
+ VIDIOC_MSM_I2C_MUX_INIT, NULL);
+ v4l2_subdev_call(i2c_mux_sd, core, ioctl,
+ VIDIOC_MSM_I2C_MUX_CFG, (void *)&i2c_conf->i2c_mux_mode);
+ return 0;
+}
+
+int32_t msm_sensor_disable_i2c_mux(struct msm_camera_i2c_conf *i2c_conf)
+{
+ struct v4l2_subdev *i2c_mux_sd =
+ dev_get_drvdata(&i2c_conf->mux_dev->dev);
+ v4l2_subdev_call(i2c_mux_sd, core, ioctl,
+ VIDIOC_MSM_I2C_MUX_RELEASE, NULL);
+ return 0;
+}
+
int32_t msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
{
int32_t rc = 0;
@@ -506,6 +527,10 @@
if (data->sensor_platform_info->ext_power_ctrl != NULL)
data->sensor_platform_info->ext_power_ctrl(1);
+ if (data->sensor_platform_info->i2c_conf &&
+ data->sensor_platform_info->i2c_conf->use_i2c_mux)
+ msm_sensor_enable_i2c_mux(data->sensor_platform_info->i2c_conf);
+
return rc;
enable_clk_failed:
msm_camera_config_gpio_table(data, 0);
@@ -531,6 +556,11 @@
{
struct msm_camera_sensor_info *data = s_ctrl->sensordata;
CDBG("%s\n", __func__);
+ if (data->sensor_platform_info->i2c_conf &&
+ data->sensor_platform_info->i2c_conf->use_i2c_mux)
+ msm_sensor_disable_i2c_mux(
+ data->sensor_platform_info->i2c_conf);
+
if (data->sensor_platform_info->ext_power_ctrl != NULL)
data->sensor_platform_info->ext_power_ctrl(0);
msm_cam_clk_enable(&s_ctrl->sensor_i2c_client->client->dev,