diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2011-07-01 10:19:58 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-07-27 16:56:08 -0400 |
commit | 6b526fed0e688e3926bd43a09f2f36cba3983ce2 (patch) | |
tree | c45123c4f78a64e54811ee46c30d3c26da8e3c9f /drivers/media | |
parent | 91c7953005247c9563408bbdbf35e27de33e6ec3 (diff) |
[media] V4L: sh_mobile_csi2: switch away from using the soc-camera bus notifier
This moves us one more step closer to eliminating the soc-camera bus
and devices on it. Besides, as a side effect, CSI-2 runtime PM on
sh-mobile secomes finer grained now: we only have to power on the
interface, when the device nodes are open.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Acked-by: Paul Mundt <lethal@linux-sh.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/sh_mobile_ceu_camera.c | 117 | ||||
-rw-r--r-- | drivers/media/video/sh_mobile_csi2.c | 135 |
2 files changed, 162 insertions, 90 deletions
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 33e126e43b1f..152a65993286 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <media/v4l2-dev.h> | 38 | #include <media/v4l2-dev.h> |
39 | #include <media/soc_camera.h> | 39 | #include <media/soc_camera.h> |
40 | #include <media/sh_mobile_ceu.h> | 40 | #include <media/sh_mobile_ceu.h> |
41 | #include <media/sh_mobile_csi2.h> | ||
41 | #include <media/videobuf2-dma-contig.h> | 42 | #include <media/videobuf2-dma-contig.h> |
42 | #include <media/v4l2-mediabus.h> | 43 | #include <media/v4l2-mediabus.h> |
43 | #include <media/soc_mediabus.h> | 44 | #include <media/soc_mediabus.h> |
@@ -95,6 +96,7 @@ struct sh_mobile_ceu_buffer { | |||
95 | struct sh_mobile_ceu_dev { | 96 | struct sh_mobile_ceu_dev { |
96 | struct soc_camera_host ici; | 97 | struct soc_camera_host ici; |
97 | struct soc_camera_device *icd; | 98 | struct soc_camera_device *icd; |
99 | struct platform_device *csi2_pdev; | ||
98 | 100 | ||
99 | unsigned int irq; | 101 | unsigned int irq; |
100 | void __iomem *base; | 102 | void __iomem *base; |
@@ -498,11 +500,26 @@ out: | |||
498 | return IRQ_HANDLED; | 500 | return IRQ_HANDLED; |
499 | } | 501 | } |
500 | 502 | ||
503 | static struct v4l2_subdev *find_csi2(struct sh_mobile_ceu_dev *pcdev) | ||
504 | { | ||
505 | struct v4l2_subdev *sd; | ||
506 | |||
507 | if (!pcdev->csi2_pdev) | ||
508 | return NULL; | ||
509 | |||
510 | v4l2_device_for_each_subdev(sd, &pcdev->ici.v4l2_dev) | ||
511 | if (&pcdev->csi2_pdev->dev == v4l2_get_subdevdata(sd)) | ||
512 | return sd; | ||
513 | |||
514 | return NULL; | ||
515 | } | ||
516 | |||
501 | /* Called with .video_lock held */ | 517 | /* Called with .video_lock held */ |
502 | static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) | 518 | static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) |
503 | { | 519 | { |
504 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 520 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
505 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 521 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
522 | struct v4l2_subdev *csi2_sd; | ||
506 | int ret; | 523 | int ret; |
507 | 524 | ||
508 | if (pcdev->icd) | 525 | if (pcdev->icd) |
@@ -515,8 +532,16 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) | |||
515 | pm_runtime_get_sync(ici->v4l2_dev.dev); | 532 | pm_runtime_get_sync(ici->v4l2_dev.dev); |
516 | 533 | ||
517 | ret = sh_mobile_ceu_soft_reset(pcdev); | 534 | ret = sh_mobile_ceu_soft_reset(pcdev); |
518 | if (!ret) | 535 | |
536 | csi2_sd = find_csi2(pcdev); | ||
537 | |||
538 | ret = v4l2_subdev_call(csi2_sd, core, s_power, 1); | ||
539 | if (ret != -ENODEV && ret != -ENOIOCTLCMD && ret < 0) { | ||
540 | pm_runtime_put_sync(ici->v4l2_dev.dev); | ||
541 | } else { | ||
519 | pcdev->icd = icd; | 542 | pcdev->icd = icd; |
543 | ret = 0; | ||
544 | } | ||
520 | 545 | ||
521 | return ret; | 546 | return ret; |
522 | } | 547 | } |
@@ -526,9 +551,11 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) | |||
526 | { | 551 | { |
527 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 552 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
528 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 553 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
554 | struct v4l2_subdev *csi2_sd = find_csi2(pcdev); | ||
529 | 555 | ||
530 | BUG_ON(icd != pcdev->icd); | 556 | BUG_ON(icd != pcdev->icd); |
531 | 557 | ||
558 | v4l2_subdev_call(csi2_sd, core, s_power, 0); | ||
532 | /* disable capture, disable interrupts */ | 559 | /* disable capture, disable interrupts */ |
533 | ceu_write(pcdev, CEIER, 0); | 560 | ceu_write(pcdev, CEIER, 0); |
534 | sh_mobile_ceu_soft_reset(pcdev); | 561 | sh_mobile_ceu_soft_reset(pcdev); |
@@ -640,7 +667,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) | |||
640 | } | 667 | } |
641 | 668 | ||
642 | /* CSI2 special configuration */ | 669 | /* CSI2 special configuration */ |
643 | if (pcdev->pdata->csi2_dev) { | 670 | if (pcdev->pdata->csi2) { |
644 | in_width = ((in_width - 2) * 2); | 671 | in_width = ((in_width - 2) * 2); |
645 | left_offset *= 2; | 672 | left_offset *= 2; |
646 | } | 673 | } |
@@ -782,7 +809,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
782 | value |= pcdev->is_16bit ? 1 << 12 : 0; | 809 | value |= pcdev->is_16bit ? 1 << 12 : 0; |
783 | 810 | ||
784 | /* CSI2 mode */ | 811 | /* CSI2 mode */ |
785 | if (pcdev->pdata->csi2_dev) | 812 | if (pcdev->pdata->csi2) |
786 | value |= 3 << 12; | 813 | value |= 3 << 12; |
787 | 814 | ||
788 | ceu_write(pcdev, CAMCR, value); | 815 | ceu_write(pcdev, CAMCR, value); |
@@ -920,7 +947,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int | |||
920 | return 0; | 947 | return 0; |
921 | } | 948 | } |
922 | 949 | ||
923 | if (!pcdev->pdata->csi2_dev) { | 950 | if (!pcdev->pdata->csi2) { |
924 | ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample); | 951 | ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample); |
925 | if (ret < 0) | 952 | if (ret < 0) |
926 | return 0; | 953 | return 0; |
@@ -1943,7 +1970,7 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev) | |||
1943 | .completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion), | 1970 | .completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion), |
1944 | .notifier.notifier_call = bus_notify, | 1971 | .notifier.notifier_call = bus_notify, |
1945 | }; | 1972 | }; |
1946 | struct device *csi2; | 1973 | struct sh_mobile_ceu_companion *csi2; |
1947 | 1974 | ||
1948 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1975 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1949 | irq = platform_get_irq(pdev, 0); | 1976 | irq = platform_get_irq(pdev, 0); |
@@ -2016,26 +2043,61 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev) | |||
2016 | pcdev->ici.drv_name = dev_name(&pdev->dev); | 2043 | pcdev->ici.drv_name = dev_name(&pdev->dev); |
2017 | pcdev->ici.ops = &sh_mobile_ceu_host_ops; | 2044 | pcdev->ici.ops = &sh_mobile_ceu_host_ops; |
2018 | 2045 | ||
2046 | pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | ||
2047 | if (IS_ERR(pcdev->alloc_ctx)) { | ||
2048 | err = PTR_ERR(pcdev->alloc_ctx); | ||
2049 | goto exit_free_clk; | ||
2050 | } | ||
2051 | |||
2052 | err = soc_camera_host_register(&pcdev->ici); | ||
2053 | if (err) | ||
2054 | goto exit_free_ctx; | ||
2055 | |||
2019 | /* CSI2 interfacing */ | 2056 | /* CSI2 interfacing */ |
2020 | csi2 = pcdev->pdata->csi2_dev; | 2057 | csi2 = pcdev->pdata->csi2; |
2021 | if (csi2) { | 2058 | if (csi2) { |
2022 | wait.dev = csi2; | 2059 | struct platform_device *csi2_pdev = |
2060 | platform_device_alloc("sh-mobile-csi2", csi2->id); | ||
2061 | struct sh_csi2_pdata *csi2_pdata = csi2->platform_data; | ||
2062 | |||
2063 | if (!csi2_pdev) { | ||
2064 | err = -ENOMEM; | ||
2065 | goto exit_host_unregister; | ||
2066 | } | ||
2067 | |||
2068 | pcdev->csi2_pdev = csi2_pdev; | ||
2069 | |||
2070 | err = platform_device_add_data(csi2_pdev, csi2_pdata, sizeof(*csi2_pdata)); | ||
2071 | if (err < 0) | ||
2072 | goto exit_pdev_put; | ||
2073 | |||
2074 | csi2_pdata = csi2_pdev->dev.platform_data; | ||
2075 | csi2_pdata->v4l2_dev = &pcdev->ici.v4l2_dev; | ||
2076 | |||
2077 | csi2_pdev->resource = csi2->resource; | ||
2078 | csi2_pdev->num_resources = csi2->num_resources; | ||
2079 | |||
2080 | err = platform_device_add(csi2_pdev); | ||
2081 | if (err < 0) | ||
2082 | goto exit_pdev_put; | ||
2083 | |||
2084 | wait.dev = &csi2_pdev->dev; | ||
2023 | 2085 | ||
2024 | err = bus_register_notifier(&platform_bus_type, &wait.notifier); | 2086 | err = bus_register_notifier(&platform_bus_type, &wait.notifier); |
2025 | if (err < 0) | 2087 | if (err < 0) |
2026 | goto exit_free_clk; | 2088 | goto exit_pdev_unregister; |
2027 | 2089 | ||
2028 | /* | 2090 | /* |
2029 | * From this point the driver module will not unload, until | 2091 | * From this point the driver module will not unload, until |
2030 | * we complete the completion. | 2092 | * we complete the completion. |
2031 | */ | 2093 | */ |
2032 | 2094 | ||
2033 | if (!csi2->driver) { | 2095 | if (!csi2_pdev->dev.driver) { |
2034 | complete(&wait.completion); | 2096 | complete(&wait.completion); |
2035 | /* Either too late, or probing failed */ | 2097 | /* Either too late, or probing failed */ |
2036 | bus_unregister_notifier(&platform_bus_type, &wait.notifier); | 2098 | bus_unregister_notifier(&platform_bus_type, &wait.notifier); |
2037 | err = -ENXIO; | 2099 | err = -ENXIO; |
2038 | goto exit_free_clk; | 2100 | goto exit_pdev_unregister; |
2039 | } | 2101 | } |
2040 | 2102 | ||
2041 | /* | 2103 | /* |
@@ -2044,34 +2106,28 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev) | |||
2044 | * the "owner" is safe! | 2106 | * the "owner" is safe! |
2045 | */ | 2107 | */ |
2046 | 2108 | ||
2047 | err = try_module_get(csi2->driver->owner); | 2109 | err = try_module_get(csi2_pdev->dev.driver->owner); |
2048 | 2110 | ||
2049 | /* Let notifier complete, if it has been locked */ | 2111 | /* Let notifier complete, if it has been locked */ |
2050 | complete(&wait.completion); | 2112 | complete(&wait.completion); |
2051 | bus_unregister_notifier(&platform_bus_type, &wait.notifier); | 2113 | bus_unregister_notifier(&platform_bus_type, &wait.notifier); |
2052 | if (!err) { | 2114 | if (!err) { |
2053 | err = -ENODEV; | 2115 | err = -ENODEV; |
2054 | goto exit_free_clk; | 2116 | goto exit_pdev_unregister; |
2055 | } | 2117 | } |
2056 | } | 2118 | } |
2057 | 2119 | ||
2058 | pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | ||
2059 | if (IS_ERR(pcdev->alloc_ctx)) { | ||
2060 | err = PTR_ERR(pcdev->alloc_ctx); | ||
2061 | goto exit_module_put; | ||
2062 | } | ||
2063 | |||
2064 | err = soc_camera_host_register(&pcdev->ici); | ||
2065 | if (err) | ||
2066 | goto exit_free_ctx; | ||
2067 | |||
2068 | return 0; | 2120 | return 0; |
2069 | 2121 | ||
2122 | exit_pdev_unregister: | ||
2123 | platform_device_del(pcdev->csi2_pdev); | ||
2124 | exit_pdev_put: | ||
2125 | pcdev->csi2_pdev->resource = NULL; | ||
2126 | platform_device_put(pcdev->csi2_pdev); | ||
2127 | exit_host_unregister: | ||
2128 | soc_camera_host_unregister(&pcdev->ici); | ||
2070 | exit_free_ctx: | 2129 | exit_free_ctx: |
2071 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | 2130 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); |
2072 | exit_module_put: | ||
2073 | if (csi2 && csi2->driver) | ||
2074 | module_put(csi2->driver->owner); | ||
2075 | exit_free_clk: | 2131 | exit_free_clk: |
2076 | pm_runtime_disable(&pdev->dev); | 2132 | pm_runtime_disable(&pdev->dev); |
2077 | free_irq(pcdev->irq, pcdev); | 2133 | free_irq(pcdev->irq, pcdev); |
@@ -2091,7 +2147,7 @@ static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev) | |||
2091 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); | 2147 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); |
2092 | struct sh_mobile_ceu_dev *pcdev = container_of(soc_host, | 2148 | struct sh_mobile_ceu_dev *pcdev = container_of(soc_host, |
2093 | struct sh_mobile_ceu_dev, ici); | 2149 | struct sh_mobile_ceu_dev, ici); |
2094 | struct device *csi2 = pcdev->pdata->csi2_dev; | 2150 | struct platform_device *csi2_pdev = pcdev->csi2_pdev; |
2095 | 2151 | ||
2096 | soc_camera_host_unregister(soc_host); | 2152 | soc_camera_host_unregister(soc_host); |
2097 | pm_runtime_disable(&pdev->dev); | 2153 | pm_runtime_disable(&pdev->dev); |
@@ -2100,8 +2156,13 @@ static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev) | |||
2100 | dma_release_declared_memory(&pdev->dev); | 2156 | dma_release_declared_memory(&pdev->dev); |
2101 | iounmap(pcdev->base); | 2157 | iounmap(pcdev->base); |
2102 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | 2158 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); |
2103 | if (csi2 && csi2->driver) | 2159 | if (csi2_pdev && csi2_pdev->dev.driver) { |
2104 | module_put(csi2->driver->owner); | 2160 | struct module *csi2_drv = csi2_pdev->dev.driver->owner; |
2161 | platform_device_del(csi2_pdev); | ||
2162 | csi2_pdev->resource = NULL; | ||
2163 | platform_device_put(csi2_pdev); | ||
2164 | module_put(csi2_drv); | ||
2165 | } | ||
2105 | kfree(pcdev); | 2166 | kfree(pcdev); |
2106 | 2167 | ||
2107 | return 0; | 2168 | return 0; |
diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index 98b87481fa94..2893a0134c7e 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/videodev2.h> | 17 | #include <linux/videodev2.h> |
18 | 18 | ||
19 | #include <media/sh_mobile_ceu.h> | ||
19 | #include <media/sh_mobile_csi2.h> | 20 | #include <media/sh_mobile_csi2.h> |
20 | #include <media/soc_camera.h> | 21 | #include <media/soc_camera.h> |
21 | #include <media/v4l2-common.h> | 22 | #include <media/v4l2-common.h> |
@@ -33,7 +34,6 @@ | |||
33 | struct sh_csi2 { | 34 | struct sh_csi2 { |
34 | struct v4l2_subdev subdev; | 35 | struct v4l2_subdev subdev; |
35 | struct list_head list; | 36 | struct list_head list; |
36 | struct notifier_block notifier; | ||
37 | unsigned int irq; | 37 | unsigned int irq; |
38 | void __iomem *base; | 38 | void __iomem *base; |
39 | struct platform_device *pdev; | 39 | struct platform_device *pdev; |
@@ -132,13 +132,6 @@ static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = { | |||
132 | .try_mbus_fmt = sh_csi2_try_fmt, | 132 | .try_mbus_fmt = sh_csi2_try_fmt, |
133 | }; | 133 | }; |
134 | 134 | ||
135 | static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops; | ||
136 | |||
137 | static struct v4l2_subdev_ops sh_csi2_subdev_ops = { | ||
138 | .core = &sh_csi2_subdev_core_ops, | ||
139 | .video = &sh_csi2_subdev_video_ops, | ||
140 | }; | ||
141 | |||
142 | static void sh_csi2_hwinit(struct sh_csi2 *priv) | 135 | static void sh_csi2_hwinit(struct sh_csi2 *priv) |
143 | { | 136 | { |
144 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; | 137 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; |
@@ -186,65 +179,84 @@ static unsigned long sh_csi2_query_bus_param(struct soc_camera_device *icd) | |||
186 | return soc_camera_apply_sensor_flags(icl, flags); | 179 | return soc_camera_apply_sensor_flags(icl, flags); |
187 | } | 180 | } |
188 | 181 | ||
189 | static int sh_csi2_notify(struct notifier_block *nb, | 182 | static int sh_csi2_client_connect(struct sh_csi2 *priv) |
190 | unsigned long action, void *data) | ||
191 | { | 183 | { |
192 | struct device *dev = data; | ||
193 | struct soc_camera_device *icd = to_soc_camera_dev(dev); | ||
194 | struct v4l2_device *v4l2_dev = dev_get_drvdata(dev->parent); | ||
195 | struct sh_csi2 *priv = | ||
196 | container_of(nb, struct sh_csi2, notifier); | ||
197 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; | 184 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; |
198 | int ret, i; | 185 | struct v4l2_subdev *sd, *csi2_sd = &priv->subdev; |
186 | struct soc_camera_device *icd = NULL; | ||
187 | struct device *dev = v4l2_get_subdevdata(&priv->subdev); | ||
188 | int i; | ||
189 | |||
190 | v4l2_device_for_each_subdev(sd, csi2_sd->v4l2_dev) | ||
191 | if (sd->grp_id) { | ||
192 | icd = (struct soc_camera_device *)sd->grp_id; | ||
193 | break; | ||
194 | } | ||
195 | |||
196 | if (!icd) | ||
197 | return -EINVAL; | ||
199 | 198 | ||
200 | for (i = 0; i < pdata->num_clients; i++) | 199 | for (i = 0; i < pdata->num_clients; i++) |
201 | if (&pdata->clients[i].pdev->dev == icd->pdev) | 200 | if (&pdata->clients[i].pdev->dev == icd->pdev) |
202 | break; | 201 | break; |
203 | 202 | ||
204 | dev_dbg(dev, "%s(%p): action = %lu, found #%d\n", __func__, dev, action, i); | 203 | dev_dbg(dev, "%s(%p): found #%d\n", __func__, dev, i); |
205 | 204 | ||
206 | if (i == pdata->num_clients) | 205 | if (i == pdata->num_clients) |
207 | return NOTIFY_DONE; | 206 | return -ENODEV; |
208 | 207 | ||
209 | switch (action) { | 208 | priv->client = pdata->clients + i; |
210 | case BUS_NOTIFY_BOUND_DRIVER: | ||
211 | snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s%s", | ||
212 | dev_name(v4l2_dev->dev), ".mipi-csi"); | ||
213 | priv->subdev.grp_id = (long)icd; | ||
214 | ret = v4l2_device_register_subdev(v4l2_dev, &priv->subdev); | ||
215 | dev_dbg(dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret); | ||
216 | if (ret < 0) | ||
217 | return NOTIFY_DONE; | ||
218 | 209 | ||
219 | priv->client = pdata->clients + i; | 210 | priv->set_bus_param = icd->ops->set_bus_param; |
211 | priv->query_bus_param = icd->ops->query_bus_param; | ||
212 | icd->ops->set_bus_param = sh_csi2_set_bus_param; | ||
213 | icd->ops->query_bus_param = sh_csi2_query_bus_param; | ||
220 | 214 | ||
221 | priv->set_bus_param = icd->ops->set_bus_param; | 215 | csi2_sd->grp_id = (long)icd; |
222 | priv->query_bus_param = icd->ops->query_bus_param; | ||
223 | icd->ops->set_bus_param = sh_csi2_set_bus_param; | ||
224 | icd->ops->query_bus_param = sh_csi2_query_bus_param; | ||
225 | 216 | ||
226 | pm_runtime_get_sync(v4l2_get_subdevdata(&priv->subdev)); | 217 | pm_runtime_get_sync(dev); |
227 | 218 | ||
228 | sh_csi2_hwinit(priv); | 219 | sh_csi2_hwinit(priv); |
229 | break; | ||
230 | case BUS_NOTIFY_UNBIND_DRIVER: | ||
231 | priv->client = NULL; | ||
232 | 220 | ||
233 | /* Driver is about to be unbound */ | 221 | return 0; |
234 | icd->ops->set_bus_param = priv->set_bus_param; | 222 | } |
235 | icd->ops->query_bus_param = priv->query_bus_param; | ||
236 | priv->set_bus_param = NULL; | ||
237 | priv->query_bus_param = NULL; | ||
238 | 223 | ||
239 | v4l2_device_unregister_subdev(&priv->subdev); | 224 | static void sh_csi2_client_disconnect(struct sh_csi2 *priv) |
225 | { | ||
226 | struct soc_camera_device *icd = (struct soc_camera_device *)priv->subdev.grp_id; | ||
240 | 227 | ||
241 | pm_runtime_put(v4l2_get_subdevdata(&priv->subdev)); | 228 | priv->client = NULL; |
242 | break; | 229 | priv->subdev.grp_id = 0; |
243 | } | ||
244 | 230 | ||
245 | return NOTIFY_OK; | 231 | /* Driver is about to be unbound */ |
232 | icd->ops->set_bus_param = priv->set_bus_param; | ||
233 | icd->ops->query_bus_param = priv->query_bus_param; | ||
234 | priv->set_bus_param = NULL; | ||
235 | priv->query_bus_param = NULL; | ||
236 | |||
237 | pm_runtime_put(v4l2_get_subdevdata(&priv->subdev)); | ||
246 | } | 238 | } |
247 | 239 | ||
240 | static int sh_csi2_s_power(struct v4l2_subdev *sd, int on) | ||
241 | { | ||
242 | struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); | ||
243 | |||
244 | if (on) | ||
245 | return sh_csi2_client_connect(priv); | ||
246 | |||
247 | sh_csi2_client_disconnect(priv); | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops = { | ||
252 | .s_power = sh_csi2_s_power, | ||
253 | }; | ||
254 | |||
255 | static struct v4l2_subdev_ops sh_csi2_subdev_ops = { | ||
256 | .core = &sh_csi2_subdev_core_ops, | ||
257 | .video = &sh_csi2_subdev_video_ops, | ||
258 | }; | ||
259 | |||
248 | static __devinit int sh_csi2_probe(struct platform_device *pdev) | 260 | static __devinit int sh_csi2_probe(struct platform_device *pdev) |
249 | { | 261 | { |
250 | struct resource *res; | 262 | struct resource *res; |
@@ -274,14 +286,6 @@ static __devinit int sh_csi2_probe(struct platform_device *pdev) | |||
274 | return -ENOMEM; | 286 | return -ENOMEM; |
275 | 287 | ||
276 | priv->irq = irq; | 288 | priv->irq = irq; |
277 | priv->notifier.notifier_call = sh_csi2_notify; | ||
278 | |||
279 | /* We MUST attach after the MIPI sensor */ | ||
280 | ret = bus_register_notifier(&soc_camera_bus_type, &priv->notifier); | ||
281 | if (ret < 0) { | ||
282 | dev_err(&pdev->dev, "CSI2 cannot register notifier\n"); | ||
283 | goto ernotify; | ||
284 | } | ||
285 | 289 | ||
286 | if (!request_mem_region(res->start, resource_size(res), pdev->name)) { | 290 | if (!request_mem_region(res->start, resource_size(res), pdev->name)) { |
287 | dev_err(&pdev->dev, "CSI2 register region already claimed\n"); | 291 | dev_err(&pdev->dev, "CSI2 register region already claimed\n"); |
@@ -297,11 +301,17 @@ static __devinit int sh_csi2_probe(struct platform_device *pdev) | |||
297 | } | 301 | } |
298 | 302 | ||
299 | priv->pdev = pdev; | 303 | priv->pdev = pdev; |
304 | platform_set_drvdata(pdev, priv); | ||
300 | 305 | ||
301 | v4l2_subdev_init(&priv->subdev, &sh_csi2_subdev_ops); | 306 | v4l2_subdev_init(&priv->subdev, &sh_csi2_subdev_ops); |
302 | v4l2_set_subdevdata(&priv->subdev, &pdev->dev); | 307 | v4l2_set_subdevdata(&priv->subdev, &pdev->dev); |
303 | 308 | ||
304 | platform_set_drvdata(pdev, priv); | 309 | snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s.mipi-csi", |
310 | dev_name(pdata->v4l2_dev->dev)); | ||
311 | ret = v4l2_device_register_subdev(pdata->v4l2_dev, &priv->subdev); | ||
312 | dev_dbg(&pdev->dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret); | ||
313 | if (ret < 0) | ||
314 | goto esdreg; | ||
305 | 315 | ||
306 | pm_runtime_enable(&pdev->dev); | 316 | pm_runtime_enable(&pdev->dev); |
307 | 317 | ||
@@ -309,11 +319,11 @@ static __devinit int sh_csi2_probe(struct platform_device *pdev) | |||
309 | 319 | ||
310 | return 0; | 320 | return 0; |
311 | 321 | ||
322 | esdreg: | ||
323 | iounmap(priv->base); | ||
312 | eremap: | 324 | eremap: |
313 | release_mem_region(res->start, resource_size(res)); | 325 | release_mem_region(res->start, resource_size(res)); |
314 | ereqreg: | 326 | ereqreg: |
315 | bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier); | ||
316 | ernotify: | ||
317 | kfree(priv); | 327 | kfree(priv); |
318 | 328 | ||
319 | return ret; | 329 | return ret; |
@@ -324,7 +334,7 @@ static __devexit int sh_csi2_remove(struct platform_device *pdev) | |||
324 | struct sh_csi2 *priv = platform_get_drvdata(pdev); | 334 | struct sh_csi2 *priv = platform_get_drvdata(pdev); |
325 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 335 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
326 | 336 | ||
327 | bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier); | 337 | v4l2_device_unregister_subdev(&priv->subdev); |
328 | pm_runtime_disable(&pdev->dev); | 338 | pm_runtime_disable(&pdev->dev); |
329 | iounmap(priv->base); | 339 | iounmap(priv->base); |
330 | release_mem_region(res->start, resource_size(res)); | 340 | release_mem_region(res->start, resource_size(res)); |
@@ -335,8 +345,9 @@ static __devexit int sh_csi2_remove(struct platform_device *pdev) | |||
335 | } | 345 | } |
336 | 346 | ||
337 | static struct platform_driver __refdata sh_csi2_pdrv = { | 347 | static struct platform_driver __refdata sh_csi2_pdrv = { |
338 | .remove = __devexit_p(sh_csi2_remove), | 348 | .remove = __devexit_p(sh_csi2_remove), |
339 | .driver = { | 349 | .probe = sh_csi2_probe, |
350 | .driver = { | ||
340 | .name = "sh-mobile-csi2", | 351 | .name = "sh-mobile-csi2", |
341 | .owner = THIS_MODULE, | 352 | .owner = THIS_MODULE, |
342 | }, | 353 | }, |
@@ -344,7 +355,7 @@ static struct platform_driver __refdata sh_csi2_pdrv = { | |||
344 | 355 | ||
345 | static int __init sh_csi2_init(void) | 356 | static int __init sh_csi2_init(void) |
346 | { | 357 | { |
347 | return platform_driver_probe(&sh_csi2_pdrv, sh_csi2_probe); | 358 | return platform_driver_register(&sh_csi2_pdrv); |
348 | } | 359 | } |
349 | 360 | ||
350 | static void __exit sh_csi2_exit(void) | 361 | static void __exit sh_csi2_exit(void) |