Maemo patchset 20101501+0m5
[h-e-n] / arch / arm / mach-omap2 / board-rx51-camera.c
diff --git a/arch/arm/mach-omap2/board-rx51-camera.c b/arch/arm/mach-omap2/board-rx51-camera.c
new file mode 100644 (file)
index 0000000..15da589
--- /dev/null
@@ -0,0 +1,754 @@
+/*
+ * arch/arm/mach-omap2/board-rx51-camera.c
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *          Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/videodev2.h>
+#include <linux/device.h>
+
+#include <asm/gpio.h>
+#include <mach/control.h>
+#include <mach/omap-pm.h>
+
+#include "../../../drivers/media/video/omap34xxcam.h"
+#include "../../../drivers/media/video/isp/ispreg.h"
+#include "../../../drivers/media/video/et8ek8.h"
+#include "../../../drivers/media/video/smia-sensor.h"
+
+#include <media/ad5820.h>
+#include <media/adp1653.h>
+#include <media/smiaregs.h>
+
+#include "board-rx51-camera.h"
+
+#define ADP1653_GPIO_ENABLE    88      /* Used for resetting ADP1653 */
+#define ADP1653_GPIO_INT       167     /* Fault interrupt */
+#define ADP1653_GPIO_STROBE    126     /* Pin used in cam_strobe mode ->
+                                        * control using ISP drivers */
+
+#define STINGRAY_RESET_GPIO    102
+#define ACMELITE_RESET_GPIO    97      /* Used also to MUX between cameras */
+
+#define RX51_CAMERA_STINGRAY   0
+#define RX51_CAMERA_ACMELITE   1
+
+#define RX51_SENSOR            1
+#define RX51_LENS              2
+
+#define GPIO_DIR_OUTPUT                0
+
+/*
+ *
+ * Power control
+ *
+ */
+
+/* Assign camera to peripheral power group P3 */
+#define CAMERA_DEV_GRP         (0x4 << 5)
+#define VAUX2_1V8              0x05
+#define VAUX3_1V8              0x01
+#define VAUX4_2V8              0x09
+
+/* Earlier rx51 builds require VAUX3. */
+#define NEEDS_VAUX3            (system_rev >= 0x100 && system_rev < 0x900)
+
+static struct rx51_camera {
+       int okay;
+       int inuse;
+} rx51_camera[2];
+
+static DEFINE_MUTEX(rx51_camera_mutex);
+
+/* Acquires the given slave `which' for camera if possible.
+ * Returns the bitmask containing previously acquired slaves for the device.
+ */
+static int rx51_camera_acquire(int camera, int which)
+{
+       int other = 1 - camera;
+       int old_which;
+
+       if (!rx51_camera[camera].okay)
+               return -EINVAL;
+
+       if (rx51_camera[other].inuse)
+               return -EBUSY;
+
+       old_which = rx51_camera[camera].inuse;
+       rx51_camera[camera].inuse |= which;
+
+       return old_which;
+}
+
+/* Releases the given slave `which' for camera.
+ * Returns the bitmask containing still acquired slaves for the device.
+ */
+static int rx51_camera_release(int camera, int which)
+{
+       rx51_camera[camera].inuse &= ~which;
+
+       return rx51_camera[camera].inuse;
+}
+
+static int rx51_camera_power_on_nolock(int camera)
+{
+       int rval;
+
+       /* Reset Stingray */
+       gpio_set_value(STINGRAY_RESET_GPIO, 0);
+
+       /* Mux to Stingray and reset Acme Lite */
+       gpio_set_value(ACMELITE_RESET_GPIO, 0);
+
+       /* VAUX2=1.8 V (muxer voltage) */
+       rval = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                   VAUX2_1V8, TWL4030_VAUX2_DEDICATED);
+       if (rval)
+               goto out;
+       rval = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                   CAMERA_DEV_GRP, TWL4030_VAUX2_DEV_GRP);
+       if (rval)
+               goto out;
+
+       /* Off & sleep -> Active state */
+       rval = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                   0xEE, TWL4030_VAUX2_REMAP);
+       if (rval)
+               goto out;
+
+       /* VAUX4=2.8 V (camera VANA) */
+       rval = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                   VAUX4_2V8, TWL4030_VAUX4_DEDICATED);
+       if (rval)
+               goto out;
+       rval = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                   CAMERA_DEV_GRP, TWL4030_VAUX4_DEV_GRP);
+       if (rval)
+               goto out;
+       rval = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                   0xEE, TWL4030_VAUX4_REMAP);
+       if (rval)
+               goto out;
+
+       if (NEEDS_VAUX3) {
+               /* VAUX3=1.8 V (camera VDIG) */
+               printk(KERN_INFO "%s: VAUX3 on for old board\n", __func__);
+               rval = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                           VAUX3_1V8,
+                                           TWL4030_VAUX3_DEDICATED);
+               if (rval)
+                       goto out;
+               rval = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                           CAMERA_DEV_GRP,
+                                           TWL4030_VAUX3_DEV_GRP);
+               if (rval)
+                       goto out;
+               rval = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                           0xEE, TWL4030_VAUX3_REMAP);
+               if (rval)
+                       goto out;
+       }
+
+       /* Let the voltages stabilize */
+       udelay(15);
+
+       /* XSHUTDOWN on, enable camera and set muxer */
+       gpio_set_value(camera == RX51_CAMERA_STINGRAY ?
+                      STINGRAY_RESET_GPIO : ACMELITE_RESET_GPIO, 1);
+
+       /* CONTROL_CSIRXFE */
+       omap_writel(
+               /*
+                * CSIb receiver data/clock or data/strobe mode
+                *
+                * Stingray uses data/strobe.
+                */
+               ((camera ? 0 : 1) << 10)
+               | BIT(12)       /* Enable differential transceiver */
+               | BIT(13)       /* Disable reset */
+               , OMAP343X_CTRL_BASE + OMAP343X_CONTROL_CSIRXFE);
+
+       /* Let the voltages stabilize */
+       udelay(15);
+
+       return 0;
+
+out:
+       printk(KERN_ALERT "%s: Error %d in writing to TWL4030!\n", __func__,
+              rval);
+
+       return rval;
+}
+
+static int rx51_camera_power_on(int camera, int which)
+{
+       int rval;
+
+       mutex_lock(&rx51_camera_mutex);
+
+       rval = rx51_camera_acquire(camera, which);
+
+       if (!rval)
+               rval = rx51_camera_power_on_nolock(camera);
+       else if (rval > 0)
+               rval = 0;
+
+       mutex_unlock(&rx51_camera_mutex);
+
+       if (rval < 0)
+               printk(KERN_INFO "%s: power_on camera %d which %d failed\n",
+                      __func__, camera, which);
+
+       return rval;
+}
+
+static void rx51_camera_power_off_nolock(int camera)
+{
+       int rval;
+
+       /* Reset cameras */
+       gpio_set_value(STINGRAY_RESET_GPIO, 0);
+       gpio_set_value(ACMELITE_RESET_GPIO, 0);
+
+       /* VAUX2 (muxer voltage) off */
+       rval = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                   0, TWL4030_VAUX2_DEV_GRP);
+       if (rval)
+               goto out;
+       /* Off & sleep -> Off state */
+       rval = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                   0x00, TWL4030_VAUX2_REMAP);
+       if (rval)
+               goto out;
+
+       /* VAUX4 (camera VANA) off */
+       rval = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                   0, TWL4030_VAUX4_DEV_GRP);
+       if (rval)
+               goto out;
+       rval = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                   0x00, TWL4030_VAUX4_REMAP);
+       if (rval)
+               goto out;
+
+       if (NEEDS_VAUX3) {
+               printk(KERN_INFO "%s: VAUX3 off for old board\n", __func__);
+               /* VAUX3 (camera VDIG) off */
+               rval = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                           0, TWL4030_VAUX3_DEV_GRP);
+               if (rval)
+                       goto out;
+               rval = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                           0x00, TWL4030_VAUX3_REMAP);
+               if (rval)
+                       goto out;
+       }
+
+       return;
+
+out:
+       printk(KERN_ALERT "%s: Error %d in writing to TWL4030!\n", __func__,
+              rval);
+}
+
+static void rx51_camera_power_off(int camera, int which)
+{
+       int rval;
+
+       mutex_lock(&rx51_camera_mutex);
+
+       rval = rx51_camera_release(camera, which);
+       if (!rval)
+               rx51_camera_power_off_nolock(camera);
+
+       mutex_unlock(&rx51_camera_mutex);
+}
+
+static void __init rx51_stingray_init(void)
+{
+       if (gpio_request(STINGRAY_RESET_GPIO, "stingray reset") != 0) {
+               printk(KERN_INFO "%s: unable to acquire Stingray reset gpio\n",
+                      __FUNCTION__);
+               return;
+       }
+
+       /* XSHUTDOWN off, reset  */
+       gpio_direction_output(STINGRAY_RESET_GPIO, 0);
+       rx51_camera_power_off_nolock(RX51_CAMERA_STINGRAY);
+       rx51_camera[RX51_CAMERA_STINGRAY].okay = 1;
+       rx51_camera[RX51_CAMERA_STINGRAY].inuse = 0;
+}
+
+static void __init rx51_acmelite_init(void)
+{
+       if (gpio_request(ACMELITE_RESET_GPIO, "acmelite reset") != 0) {
+               printk(KERN_INFO "%s: unable to acquire Acme Lite reset gpio\n",
+                      __FUNCTION__);
+               return;
+       }
+
+       /* XSHUTDOWN off, reset  */
+       gpio_direction_output(ACMELITE_RESET_GPIO, 0);
+       rx51_camera_power_off_nolock(RX51_CAMERA_ACMELITE);
+       rx51_camera[RX51_CAMERA_ACMELITE].okay = 1;
+       rx51_camera[RX51_CAMERA_ACMELITE].inuse = 0;
+}
+
+static int __init rx51_adp1653_init(void)
+{
+       int err;
+
+       err = gpio_request(ADP1653_GPIO_ENABLE, "adp1653 enable");
+       if (err) {
+               printk(KERN_ERR ADP1653_NAME
+                      " Failed to request EN gpio\n");
+               err = -ENODEV;
+               goto err_omap_request_gpio;
+       }
+
+       err = gpio_request(ADP1653_GPIO_INT, "adp1653 interrupt");
+       if (err) {
+               printk(KERN_ERR ADP1653_NAME " Failed to request IRQ gpio\n");
+               err = -ENODEV;
+               goto err_omap_request_gpio_2;
+       }
+
+       err = gpio_request(ADP1653_GPIO_STROBE, "adp1653 strobe");
+       if (err) {
+               printk(KERN_ERR ADP1653_NAME
+                      " Failed to request STROBE gpio\n");
+               err = -ENODEV;
+               goto err_omap_request_gpio_3;
+       }
+
+       gpio_direction_output(ADP1653_GPIO_ENABLE, 0);
+       gpio_direction_input(ADP1653_GPIO_INT);
+       gpio_direction_output(ADP1653_GPIO_STROBE, 0);
+
+       return 0;
+
+err_omap_request_gpio_3:
+       gpio_free(ADP1653_GPIO_INT);
+
+err_omap_request_gpio_2:
+       gpio_free(ADP1653_GPIO_ENABLE);
+
+err_omap_request_gpio:
+       return err;
+}
+
+static int __init rx51_camera_hw_init(void)
+{
+       int rval;
+
+       rval = rx51_adp1653_init();
+       if (rval)
+               return rval;
+
+       mutex_init(&rx51_camera_mutex);
+       rx51_stingray_init();
+       rx51_acmelite_init();
+
+       return 0;
+}
+
+/*
+ *
+ * Stingray
+ *
+ */
+
+#define STINGRAY_XCLK          OMAP34XXCAM_XCLK_A
+
+static struct isp_interface_config rx51_stingray_config = {
+       .ccdc_par_ser = ISP_CSIB,
+       .dataline_shift = 0,
+       .hsvs_syncdetect = ISPCTRL_SYNC_DETECT_VSRISE,
+       .strobe = 0,
+       .prestrobe = 0,
+       .shutter = 0,
+       .wait_hs_vs = 1,
+       .u = {
+               .csi = {
+                        .crc           =       1,
+                        .mode          =       0,
+                        .edge          =       1,
+                        .signalling    =       1,
+                        .strobe_clock_inv =    0,
+                        .vs_edge       =       0,
+                        .channel       =       0,
+                        .vpclk         =       1,
+                        .data_start    =       0,
+                },
+       },
+};
+
+static struct omap34xxcam_hw_config rx51_stingray_omap34xxcam_hw_config = {
+       .dev_index      = 0,
+       .dev_minor      = 0,
+       .dev_type       = OMAP34XXCAM_SLAVE_SENSOR,
+       .u              = {
+               .sensor         = {
+                        .sensor_isp    = 0,
+                        .capture_mem   = PAGE_ALIGN(2608 * 1966 * 2) * 2,
+                        .ival_default  = { 1, 30 },
+                },
+       },
+};
+
+static int rx51_stingray_configure_interface(struct v4l2_int_device *s,
+                                            struct smia_mode *mode)
+{
+       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+       static const int S = 8;
+
+       /* Configure sensor interface. */
+       rx51_stingray_config.u.csi.format = mode->pixel_format;
+       rx51_stingray_config.u.csi.data_size = mode->window_height;
+       /* Calculate average pixel clock per line. Assume buffers can spread
+        * the data over horizontal blanking time. Rounding upwards. */
+       rx51_stingray_config.pixelclk =
+               mode->window_width
+               * (((mode->pixel_clock + (1<<S) - 1) >> S) + mode->width - 1)
+               / mode->width;
+       rx51_stingray_config.pixelclk <<= S;
+       return isp_configure_interface(vdev->cam->isp, &rx51_stingray_config);
+}
+
+static int rx51_stingray_set_xclk(struct v4l2_int_device *s, int hz)
+{
+       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+
+       isp_set_xclk(vdev->cam->isp, hz, STINGRAY_XCLK);
+
+       return 0;
+}
+
+static int rx51_stingray_power_on(struct v4l2_int_device *s)
+{
+       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+       struct device *dev = vdev->cam->isp;
+       int rval;
+
+       omap_pm_set_min_bus_tput(dev, OCP_INITIATOR_AGENT, 400000);
+
+       rval = rx51_camera_power_on(RX51_CAMERA_STINGRAY, RX51_SENSOR);
+
+       if (rval)
+               omap_pm_set_min_bus_tput(dev, 2, 0);
+
+       return rval;
+}
+
+static int rx51_stingray_power_off(struct v4l2_int_device *s)
+{
+       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+       struct device *dev = vdev->cam->isp;
+
+       rx51_camera_power_off(RX51_CAMERA_STINGRAY, RX51_SENSOR);
+
+       omap_pm_set_min_bus_tput(dev, OCP_INITIATOR_AGENT, 0);
+
+       return 0;
+}
+
+static int rx51_stingray_g_priv(struct v4l2_int_device *s, void *priv)
+{
+       *(struct omap34xxcam_hw_config *)priv =
+               rx51_stingray_omap34xxcam_hw_config;
+
+       return 0;
+}
+
+static struct et8ek8_platform_data et8ek8_tmp_platform_data;
+
+static struct et8ek8_platform_data et8ek8_my_platform_data = {
+       .g_priv                 = rx51_stingray_g_priv,
+       .configure_interface    = rx51_stingray_configure_interface,
+       .set_xclk               = rx51_stingray_set_xclk,
+       .power_on               = rx51_stingray_power_on,
+       .power_off              = rx51_stingray_power_off,
+};
+
+/*
+ *
+ * AD5820
+ *
+ */
+
+static struct omap34xxcam_hw_config ad5820_omap34xxcam_hw_config = {
+       .dev_index      = 0,
+       .dev_minor      = 0,
+       .dev_type       = OMAP34XXCAM_SLAVE_LENS,
+       .u              = {
+               .lens           = {
+                },
+       },
+};
+
+static int ad5820_g_priv(struct v4l2_int_device *s, void *priv)
+{
+       *(struct omap34xxcam_hw_config *)priv = ad5820_omap34xxcam_hw_config;
+
+       return 0;
+}
+
+static int ad5820_s_power(struct v4l2_int_device *s, enum v4l2_power state)
+{
+       if (state == V4L2_POWER_ON)
+               return rx51_camera_power_on(RX51_CAMERA_STINGRAY, RX51_LENS);
+       else
+               rx51_camera_power_off(RX51_CAMERA_STINGRAY, RX51_LENS);
+
+       return 0;
+}
+
+static struct ad5820_platform_data ad5820_tmp_platform_data;
+
+static struct ad5820_platform_data ad5820_my_platform_data = {
+       .g_priv         = ad5820_g_priv,
+       .s_power        = ad5820_s_power,
+
+};
+
+/*
+ *
+ * ADP1653
+ *
+ */
+
+static struct omap34xxcam_hw_config adp1653_omap34xxcam_hw_config = {
+       .dev_index      = 0,
+       .dev_minor      = 0,
+       .dev_type       = OMAP34XXCAM_SLAVE_FLASH,
+       .u              = {
+               .flash          = {
+                },
+       },
+};
+
+static int rx51_adp1653_g_priv(struct v4l2_int_device *s, void *priv)
+{
+       *(struct omap34xxcam_hw_config *)priv = adp1653_omap34xxcam_hw_config;
+
+       return 0;
+}
+
+static int rx51_adp1653_power_on(struct v4l2_int_device *s)
+{
+       gpio_set_value(ADP1653_GPIO_ENABLE, 1);
+
+       /* Some delay is apparently required. */
+       udelay(400);
+
+       return 0;
+}
+
+static int rx51_adp1653_power_off(struct v4l2_int_device *s)
+{
+       gpio_set_value(ADP1653_GPIO_ENABLE, 0);
+
+       return 0;
+}
+
+static struct adp1653_platform_data adp1653_tmp_platform_data;
+
+static struct adp1653_platform_data adp1653_my_platform_data = {
+       .g_priv                  = rx51_adp1653_g_priv,
+       .power_on                = rx51_adp1653_power_on,
+       .power_off               = rx51_adp1653_power_off,
+       /* Must be limited to 500 ms in RX-51 */
+       .max_flash_timeout       = 500000,              /* us */
+       /* Must be limited to 320 mA in RX-51 B3 and newer hardware */
+       .max_flash_intensity     = 19,
+       /* Must be limited to 50 mA in RX-51 */
+       .max_torch_intensity     = 1,
+       .max_indicator_intensity = ADP1653_REG_OUT_SEL_ILED_MAX,
+};
+
+/*
+ *
+ * Acmelite
+ *
+ */
+
+#define ACMELITE_XCLK          OMAP34XXCAM_XCLK_A
+
+static struct isp_interface_config rx51_acmelite_config = {
+       .ccdc_par_ser = ISP_CSIB,
+       .dataline_shift = 0,
+       .hsvs_syncdetect = ISPCTRL_SYNC_DETECT_VSRISE,
+       .strobe = 0,
+       .prestrobe = 0,
+       .shutter = 0,
+       .wait_hs_vs = 1,
+       .u = {
+               .csi = {
+                        .crc           =       0,
+                        .mode          =       0,
+                        .edge          =       1,
+                        .signalling    =       0,
+                        .strobe_clock_inv =    0,
+                        .vs_edge       =       0,
+                        .channel       =       0,
+                        .vpclk         =       2,
+                        .data_start    =       4,
+                        .format        =       V4L2_PIX_FMT_SGRBG10,
+                },
+       },
+};
+
+static struct omap34xxcam_hw_config rx51_acmelite_omap34xxcam_hw_config = {
+       .dev_index      = 1,
+       .dev_minor      = 1,
+       .dev_type       = OMAP34XXCAM_SLAVE_SENSOR,
+       .u              = {
+               .sensor         = {
+                        .sensor_isp    = 0,
+                        .capture_mem   = PAGE_ALIGN(648 * 488 * 2) * 4,
+                        .ival_default  = { 1, 30 },
+                },
+       },
+};
+
+static int rx51_acmelite_configure_interface(struct v4l2_int_device *s,
+                                            int width, int height)
+{
+       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+
+       /* Configure sensor interface. */
+       rx51_acmelite_config.u.csi.data_size = height;
+
+       return isp_configure_interface(vdev->cam->isp, &rx51_acmelite_config);
+}
+
+static int rx51_acmelite_set_xclk(struct v4l2_int_device *s, int hz)
+{
+       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+
+       isp_set_xclk(vdev->cam->isp, hz, ACMELITE_XCLK);
+
+       return 0;
+}
+
+static int rx51_acmelite_power_on(struct v4l2_int_device *s)
+{
+       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+       struct device *dev = vdev->cam->isp;
+       int rval;
+
+       omap_pm_set_min_bus_tput(dev, OCP_INITIATOR_AGENT, 400000);
+
+       rval = rx51_camera_power_on(RX51_CAMERA_ACMELITE, RX51_SENSOR);
+
+       if (rval)
+               omap_pm_set_min_bus_tput(dev, 2, 0);
+
+       return rval;
+}
+
+static int rx51_acmelite_power_off(struct v4l2_int_device *s)
+{
+       struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+       struct device *dev = vdev->cam->isp;
+
+       rx51_camera_power_off(RX51_CAMERA_ACMELITE, RX51_SENSOR);
+
+       omap_pm_set_min_bus_tput(dev, OCP_INITIATOR_AGENT, 0);
+
+       return 0;
+}
+
+static int rx51_acmelite_g_priv(struct v4l2_int_device *s, void *priv)
+{
+       *(struct omap34xxcam_hw_config *)priv =
+               rx51_acmelite_omap34xxcam_hw_config;
+
+       return 0;
+}
+
+static struct smia_sensor_platform_data smia_sensor_tmp_platform_data;
+
+static struct smia_sensor_platform_data smia_sensor_my_platform_data = {
+       .g_priv                 = rx51_acmelite_g_priv,
+       .configure_interface    = rx51_acmelite_configure_interface,
+       .set_xclk               = rx51_acmelite_set_xclk,
+       .power_on               = rx51_acmelite_power_on,
+       .power_off              = rx51_acmelite_power_off,
+};
+
+/*
+ *
+ * Init it all
+ *
+ */
+
+static int __init rx51_camera_init(void) {
+       int err;
+
+       err = rx51_camera_hw_init();
+       if (err)
+               return err;
+
+       /* ADP1653 */
+       adp1653_tmp_platform_data = rx51_adp1653_platform_data;
+       rx51_adp1653_platform_data = adp1653_my_platform_data;
+
+       /* Stingray */
+       et8ek8_tmp_platform_data = rx51_et8ek8_platform_data;
+       rx51_et8ek8_platform_data = et8ek8_my_platform_data;
+
+       /* AD5820 */
+       ad5820_tmp_platform_data = rx51_ad5820_platform_data;
+       rx51_ad5820_platform_data = ad5820_my_platform_data;
+
+       /* Acmelite */
+       smia_sensor_tmp_platform_data = rx51_smia_sensor_platform_data;
+       rx51_smia_sensor_platform_data = smia_sensor_my_platform_data;
+
+       /* FIXME: can't unload yet. */
+       __module_get(THIS_MODULE);
+
+       /* FIXME: somehow initiate device init. */
+       v4l2_int_device_try_attach_all();
+
+       return 0;
+}
+
+static void __exit rx51_camera_exit(void) {
+       rx51_et8ek8_platform_data = et8ek8_tmp_platform_data;
+       rx51_ad5820_platform_data = ad5820_tmp_platform_data;
+       rx51_adp1653_platform_data = adp1653_tmp_platform_data;
+       rx51_smia_sensor_platform_data = smia_sensor_tmp_platform_data;
+
+       gpio_free(ADP1653_GPIO_ENABLE);
+       gpio_free(ADP1653_GPIO_INT);
+       gpio_free(ADP1653_GPIO_STROBE);
+}
+
+module_init(rx51_camera_init);
+module_exit(rx51_camera_exit);
+
+MODULE_LICENSE("GPL");