|
@@ -8,14 +8,16 @@
|
|
|
* published by the Free Software Foundation.
|
|
|
*/
|
|
|
|
|
|
-#include <linux/videodev2.h>
|
|
|
-#include <linux/slab.h>
|
|
|
+#include <linux/device.h>
|
|
|
#include <linux/i2c.h>
|
|
|
#include <linux/log2.h>
|
|
|
+#include <linux/pm.h>
|
|
|
+#include <linux/slab.h>
|
|
|
+#include <linux/videodev2.h>
|
|
|
|
|
|
-#include <media/v4l2-subdev.h>
|
|
|
-#include <media/v4l2-chip-ident.h>
|
|
|
#include <media/soc_camera.h>
|
|
|
+#include <media/v4l2-chip-ident.h>
|
|
|
+#include <media/v4l2-subdev.h>
|
|
|
|
|
|
/*
|
|
|
* mt9t031 i2c address 0x5d
|
|
@@ -680,6 +682,59 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Power Management:
|
|
|
+ * This function does nothing for now but must be present for pm to work
|
|
|
+ */
|
|
|
+static int mt9t031_runtime_suspend(struct device *dev)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Power Management:
|
|
|
+ * COLUMN_ADDRESS_MODE and ROW_ADDRESS_MODE are not rewritten if unchanged
|
|
|
+ * they are however changed at reset if the platform hook is present
|
|
|
+ * thus we rewrite them with the values stored by the driver
|
|
|
+ */
|
|
|
+static int mt9t031_runtime_resume(struct device *dev)
|
|
|
+{
|
|
|
+ struct video_device *vdev = to_video_device(dev);
|
|
|
+ struct soc_camera_device *icd = container_of(vdev->parent,
|
|
|
+ struct soc_camera_device, dev);
|
|
|
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
|
|
|
+ struct i2c_client *client = sd->priv;
|
|
|
+ struct mt9t031 *mt9t031 = to_mt9t031(client);
|
|
|
+
|
|
|
+ int ret;
|
|
|
+ u16 xbin, ybin;
|
|
|
+
|
|
|
+ xbin = min(mt9t031->xskip, (u16)3);
|
|
|
+ ybin = min(mt9t031->yskip, (u16)3);
|
|
|
+
|
|
|
+ ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE,
|
|
|
+ ((xbin - 1) << 4) | (mt9t031->xskip - 1));
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE,
|
|
|
+ ((ybin - 1) << 4) | (mt9t031->yskip - 1));
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static struct dev_pm_ops mt9t031_dev_pm_ops = {
|
|
|
+ .runtime_suspend = mt9t031_runtime_suspend,
|
|
|
+ .runtime_resume = mt9t031_runtime_resume,
|
|
|
+};
|
|
|
+
|
|
|
+static struct device_type mt9t031_dev_type = {
|
|
|
+ .name = "MT9T031",
|
|
|
+ .pm = &mt9t031_dev_pm_ops,
|
|
|
+};
|
|
|
+
|
|
|
/*
|
|
|
* Interface active, can use i2c. If it fails, it can indeed mean, that
|
|
|
* this wasn't our capture interface, so, we wait for the right one
|
|
@@ -687,6 +742,7 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
|
|
|
static int mt9t031_video_probe(struct i2c_client *client)
|
|
|
{
|
|
|
struct mt9t031 *mt9t031 = to_mt9t031(client);
|
|
|
+ struct video_device *vdev = soc_camera_i2c_to_vdev(client);
|
|
|
s32 data;
|
|
|
int ret;
|
|
|
|
|
@@ -712,6 +768,8 @@ static int mt9t031_video_probe(struct i2c_client *client)
|
|
|
ret = mt9t031_idle(client);
|
|
|
if (ret < 0)
|
|
|
dev_err(&client->dev, "Failed to initialise the camera\n");
|
|
|
+ else
|
|
|
+ vdev->dev.type = &mt9t031_dev_type;
|
|
|
|
|
|
/* mt9t031_idle() has reset the chip to default. */
|
|
|
mt9t031->exposure = 255;
|