diff options
author | Valentin Longchamp <valentin.longchamp@epfl.ch> | 2010-02-09 05:59:12 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-05-17 23:46:21 -0400 |
commit | 535653b1c22c29d4e8f554928efc87fe138f917d (patch) | |
tree | 68a93e7f63c3cc62b54e2039b0fcb350a10b6b5c /drivers | |
parent | 4f9fb5ed020324d6c151db34460df572b0fdc491 (diff) |
V4L/DVB: mt9t031: use runtime pm support to restore ADDRESS_MODE registers
If the platform hooks are provided, soc_camera powers off the device
on close and powers it on on open. This resets the ADDRESS_MODE registers
which then can be different to the value the driver has computed for them.
This patch setups runtime pm usage for mt9t031 and uses the resume function
to write the ADDRESS_MODE registers in order to fix the above described
problem.
Signed-off-by: Valentin Longchamp <valentin.longchamp@epfl.ch>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/mt9t031.c | 66 |
1 files changed, 62 insertions, 4 deletions
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index a9061bff79b2..78b4e091d2d5 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c | |||
@@ -8,14 +8,16 @@ | |||
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/videodev2.h> | 11 | #include <linux/device.h> |
12 | #include <linux/slab.h> | ||
13 | #include <linux/i2c.h> | 12 | #include <linux/i2c.h> |
14 | #include <linux/log2.h> | 13 | #include <linux/log2.h> |
14 | #include <linux/pm.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/videodev2.h> | ||
15 | 17 | ||
16 | #include <media/v4l2-subdev.h> | ||
17 | #include <media/v4l2-chip-ident.h> | ||
18 | #include <media/soc_camera.h> | 18 | #include <media/soc_camera.h> |
19 | #include <media/v4l2-chip-ident.h> | ||
20 | #include <media/v4l2-subdev.h> | ||
19 | 21 | ||
20 | /* | 22 | /* |
21 | * mt9t031 i2c address 0x5d | 23 | * mt9t031 i2c address 0x5d |
@@ -681,12 +683,66 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
681 | } | 683 | } |
682 | 684 | ||
683 | /* | 685 | /* |
686 | * Power Management: | ||
687 | * This function does nothing for now but must be present for pm to work | ||
688 | */ | ||
689 | static int mt9t031_runtime_suspend(struct device *dev) | ||
690 | { | ||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | /* | ||
695 | * Power Management: | ||
696 | * COLUMN_ADDRESS_MODE and ROW_ADDRESS_MODE are not rewritten if unchanged | ||
697 | * they are however changed at reset if the platform hook is present | ||
698 | * thus we rewrite them with the values stored by the driver | ||
699 | */ | ||
700 | static int mt9t031_runtime_resume(struct device *dev) | ||
701 | { | ||
702 | struct video_device *vdev = to_video_device(dev); | ||
703 | struct soc_camera_device *icd = container_of(vdev->parent, | ||
704 | struct soc_camera_device, dev); | ||
705 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
706 | struct i2c_client *client = sd->priv; | ||
707 | struct mt9t031 *mt9t031 = to_mt9t031(client); | ||
708 | |||
709 | int ret; | ||
710 | u16 xbin, ybin; | ||
711 | |||
712 | xbin = min(mt9t031->xskip, (u16)3); | ||
713 | ybin = min(mt9t031->yskip, (u16)3); | ||
714 | |||
715 | ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE, | ||
716 | ((xbin - 1) << 4) | (mt9t031->xskip - 1)); | ||
717 | if (ret < 0) | ||
718 | return ret; | ||
719 | |||
720 | ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE, | ||
721 | ((ybin - 1) << 4) | (mt9t031->yskip - 1)); | ||
722 | if (ret < 0) | ||
723 | return ret; | ||
724 | |||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | static struct dev_pm_ops mt9t031_dev_pm_ops = { | ||
729 | .runtime_suspend = mt9t031_runtime_suspend, | ||
730 | .runtime_resume = mt9t031_runtime_resume, | ||
731 | }; | ||
732 | |||
733 | static struct device_type mt9t031_dev_type = { | ||
734 | .name = "MT9T031", | ||
735 | .pm = &mt9t031_dev_pm_ops, | ||
736 | }; | ||
737 | |||
738 | /* | ||
684 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 739 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
685 | * this wasn't our capture interface, so, we wait for the right one | 740 | * this wasn't our capture interface, so, we wait for the right one |
686 | */ | 741 | */ |
687 | static int mt9t031_video_probe(struct i2c_client *client) | 742 | static int mt9t031_video_probe(struct i2c_client *client) |
688 | { | 743 | { |
689 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 744 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
745 | struct video_device *vdev = soc_camera_i2c_to_vdev(client); | ||
690 | s32 data; | 746 | s32 data; |
691 | int ret; | 747 | int ret; |
692 | 748 | ||
@@ -712,6 +768,8 @@ static int mt9t031_video_probe(struct i2c_client *client) | |||
712 | ret = mt9t031_idle(client); | 768 | ret = mt9t031_idle(client); |
713 | if (ret < 0) | 769 | if (ret < 0) |
714 | dev_err(&client->dev, "Failed to initialise the camera\n"); | 770 | dev_err(&client->dev, "Failed to initialise the camera\n"); |
771 | else | ||
772 | vdev->dev.type = &mt9t031_dev_type; | ||
715 | 773 | ||
716 | /* mt9t031_idle() has reset the chip to default. */ | 774 | /* mt9t031_idle() has reset the chip to default. */ |
717 | mt9t031->exposure = 255; | 775 | mt9t031->exposure = 255; |