.. | .. |
---|
4 | 4 | * so it needs platform-specific support outside of the core. |
---|
5 | 5 | * |
---|
6 | 6 | * Copyright 2011 Jonathan Corbet corbet@lwn.net |
---|
| 7 | + * Copyright 2018 Lubomir Rintel <lkundrak@v3.sk> |
---|
7 | 8 | */ |
---|
8 | 9 | #include <linux/kernel.h> |
---|
9 | 10 | #include <linux/module.h> |
---|
.. | .. |
---|
21 | 22 | #include <linux/vmalloc.h> |
---|
22 | 23 | #include <linux/io.h> |
---|
23 | 24 | #include <linux/clk.h> |
---|
| 25 | +#include <linux/clk-provider.h> |
---|
24 | 26 | #include <linux/videodev2.h> |
---|
| 27 | +#include <linux/pm_runtime.h> |
---|
25 | 28 | #include <media/v4l2-device.h> |
---|
26 | 29 | #include <media/v4l2-ioctl.h> |
---|
27 | 30 | #include <media/v4l2-ctrls.h> |
---|
28 | 31 | #include <media/v4l2-event.h> |
---|
29 | | -#include <media/i2c/ov7670.h> |
---|
30 | 32 | #include <media/videobuf2-vmalloc.h> |
---|
31 | 33 | #include <media/videobuf2-dma-contig.h> |
---|
32 | 34 | #include <media/videobuf2-dma-sg.h> |
---|
.. | .. |
---|
93 | 95 | #define sensor_call(cam, o, f, args...) \ |
---|
94 | 96 | v4l2_subdev_call(cam->sensor, o, f, ##args) |
---|
95 | 97 | |
---|
| 98 | +#define notifier_to_mcam(notifier) \ |
---|
| 99 | + container_of(notifier, struct mcam_camera, notifier) |
---|
| 100 | + |
---|
96 | 101 | static struct mcam_format_struct { |
---|
97 | | - __u8 *desc; |
---|
98 | 102 | __u32 pixelformat; |
---|
99 | 103 | int bpp; /* Bytes per pixel */ |
---|
100 | 104 | bool planar; |
---|
101 | 105 | u32 mbus_code; |
---|
102 | 106 | } mcam_formats[] = { |
---|
103 | 107 | { |
---|
104 | | - .desc = "YUYV 4:2:2", |
---|
105 | 108 | .pixelformat = V4L2_PIX_FMT_YUYV, |
---|
106 | 109 | .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, |
---|
107 | 110 | .bpp = 2, |
---|
108 | 111 | .planar = false, |
---|
109 | 112 | }, |
---|
110 | 113 | { |
---|
111 | | - .desc = "YVYU 4:2:2", |
---|
112 | 114 | .pixelformat = V4L2_PIX_FMT_YVYU, |
---|
113 | 115 | .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, |
---|
114 | 116 | .bpp = 2, |
---|
115 | 117 | .planar = false, |
---|
116 | 118 | }, |
---|
117 | 119 | { |
---|
118 | | - .desc = "YUV 4:2:0 PLANAR", |
---|
119 | 120 | .pixelformat = V4L2_PIX_FMT_YUV420, |
---|
120 | 121 | .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, |
---|
121 | 122 | .bpp = 1, |
---|
122 | 123 | .planar = true, |
---|
123 | 124 | }, |
---|
124 | 125 | { |
---|
125 | | - .desc = "YVU 4:2:0 PLANAR", |
---|
126 | 126 | .pixelformat = V4L2_PIX_FMT_YVU420, |
---|
127 | 127 | .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, |
---|
128 | 128 | .bpp = 1, |
---|
129 | 129 | .planar = true, |
---|
130 | 130 | }, |
---|
131 | 131 | { |
---|
132 | | - .desc = "XRGB 444", |
---|
133 | 132 | .pixelformat = V4L2_PIX_FMT_XRGB444, |
---|
134 | 133 | .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, |
---|
135 | 134 | .bpp = 2, |
---|
136 | 135 | .planar = false, |
---|
137 | 136 | }, |
---|
138 | 137 | { |
---|
139 | | - .desc = "RGB 565", |
---|
140 | 138 | .pixelformat = V4L2_PIX_FMT_RGB565, |
---|
141 | 139 | .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, |
---|
142 | 140 | .bpp = 2, |
---|
143 | 141 | .planar = false, |
---|
144 | 142 | }, |
---|
145 | 143 | { |
---|
146 | | - .desc = "Raw RGB Bayer", |
---|
147 | 144 | .pixelformat = V4L2_PIX_FMT_SBGGR8, |
---|
148 | 145 | .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, |
---|
149 | 146 | .bpp = 1, |
---|
.. | .. |
---|
281 | 278 | static void mcam_enable_mipi(struct mcam_camera *mcam) |
---|
282 | 279 | { |
---|
283 | 280 | /* Using MIPI mode and enable MIPI */ |
---|
| 281 | + if (mcam->calc_dphy) |
---|
| 282 | + mcam->calc_dphy(mcam); |
---|
284 | 283 | cam_dbg(mcam, "camera: DPHY3=0x%x, DPHY5=0x%x, DPHY6=0x%x\n", |
---|
285 | 284 | mcam->dphy[0], mcam->dphy[1], mcam->dphy[2]); |
---|
286 | 285 | mcam_reg_write(mcam, REG_CSI2_DPHY3, mcam->dphy[0]); |
---|
.. | .. |
---|
300 | 299 | */ |
---|
301 | 300 | mcam_reg_write(mcam, REG_CSI2_CTRL0, |
---|
302 | 301 | CSI2_C0_MIPI_EN | CSI2_C0_ACT_LANE(mcam->lane)); |
---|
303 | | - mcam_reg_write(mcam, REG_CLKCTRL, |
---|
304 | | - (mcam->mclk_src << 29) | mcam->mclk_div); |
---|
305 | | - |
---|
306 | 302 | mcam->mipi_enabled = true; |
---|
307 | 303 | } |
---|
308 | 304 | } |
---|
.. | .. |
---|
393 | 389 | dma_free_coherent(cam->dev, cam->dma_buf_size, |
---|
394 | 390 | cam->dma_bufs[0], cam->dma_handles[0]); |
---|
395 | 391 | cam->nbufs = 0; |
---|
396 | | - /* fall-through */ |
---|
| 392 | + fallthrough; |
---|
397 | 393 | case 0: |
---|
398 | 394 | cam_err(cam, "Insufficient DMA buffers, cannot operate\n"); |
---|
399 | 395 | return -ENOMEM; |
---|
.. | .. |
---|
443 | 439 | /* |
---|
444 | 440 | * Copy data out to user space in the vmalloc case |
---|
445 | 441 | */ |
---|
446 | | -static void mcam_frame_tasklet(unsigned long data) |
---|
| 442 | +static void mcam_frame_tasklet(struct tasklet_struct *t) |
---|
447 | 443 | { |
---|
448 | | - struct mcam_camera *cam = (struct mcam_camera *) data; |
---|
| 444 | + struct mcam_camera *cam = from_tasklet(cam, t, s_tasklet); |
---|
449 | 445 | int i; |
---|
450 | 446 | unsigned long flags; |
---|
451 | 447 | struct mcam_vb_buffer *buf; |
---|
.. | .. |
---|
792 | 788 | * Make sure it knows we want to use hsync/vsync. |
---|
793 | 789 | */ |
---|
794 | 790 | mcam_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC, C0_SIFM_MASK); |
---|
795 | | - /* |
---|
796 | | - * This field controls the generation of EOF(DVP only) |
---|
797 | | - */ |
---|
798 | | - if (cam->bus_type != V4L2_MBUS_CSI2) |
---|
799 | | - mcam_reg_set_bit(cam, REG_CTRL0, |
---|
800 | | - C0_EOF_VSYNC | C0_VEDGE_CTRL); |
---|
801 | 791 | } |
---|
802 | 792 | |
---|
803 | 793 | |
---|
.. | .. |
---|
832 | 822 | { |
---|
833 | 823 | mcam_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS); |
---|
834 | 824 | } |
---|
835 | | - |
---|
836 | | - |
---|
837 | | - |
---|
838 | | -static void mcam_ctlr_init(struct mcam_camera *cam) |
---|
839 | | -{ |
---|
840 | | - unsigned long flags; |
---|
841 | | - |
---|
842 | | - spin_lock_irqsave(&cam->dev_lock, flags); |
---|
843 | | - /* |
---|
844 | | - * Make sure it's not powered down. |
---|
845 | | - */ |
---|
846 | | - mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); |
---|
847 | | - /* |
---|
848 | | - * Turn off the enable bit. It sure should be off anyway, |
---|
849 | | - * but it's good to be sure. |
---|
850 | | - */ |
---|
851 | | - mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); |
---|
852 | | - /* |
---|
853 | | - * Clock the sensor appropriately. Controller clock should |
---|
854 | | - * be 48MHz, sensor "typical" value is half that. |
---|
855 | | - */ |
---|
856 | | - mcam_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK); |
---|
857 | | - spin_unlock_irqrestore(&cam->dev_lock, flags); |
---|
858 | | -} |
---|
859 | | - |
---|
860 | 825 | |
---|
861 | 826 | /* |
---|
862 | 827 | * Stop the controller, and don't return until we're really sure that no |
---|
.. | .. |
---|
901 | 866 | int ret; |
---|
902 | 867 | |
---|
903 | 868 | spin_lock_irqsave(&cam->dev_lock, flags); |
---|
904 | | - ret = cam->plat_power_up(cam); |
---|
905 | | - if (ret) { |
---|
906 | | - spin_unlock_irqrestore(&cam->dev_lock, flags); |
---|
907 | | - return ret; |
---|
| 869 | + if (cam->plat_power_up) { |
---|
| 870 | + ret = cam->plat_power_up(cam); |
---|
| 871 | + if (ret) { |
---|
| 872 | + spin_unlock_irqrestore(&cam->dev_lock, flags); |
---|
| 873 | + return ret; |
---|
| 874 | + } |
---|
908 | 875 | } |
---|
909 | 876 | mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); |
---|
910 | 877 | spin_unlock_irqrestore(&cam->dev_lock, flags); |
---|
911 | | - msleep(5); /* Just to be sure */ |
---|
912 | 878 | return 0; |
---|
913 | 879 | } |
---|
914 | 880 | |
---|
.. | .. |
---|
923 | 889 | * power down routine. |
---|
924 | 890 | */ |
---|
925 | 891 | mcam_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN); |
---|
926 | | - cam->plat_power_down(cam); |
---|
| 892 | + if (cam->plat_power_down) |
---|
| 893 | + cam->plat_power_down(cam); |
---|
927 | 894 | spin_unlock_irqrestore(&cam->dev_lock, flags); |
---|
928 | 895 | } |
---|
| 896 | + |
---|
| 897 | +/* ---------------------------------------------------------------------- */ |
---|
| 898 | +/* |
---|
| 899 | + * Master sensor clock. |
---|
| 900 | + */ |
---|
| 901 | +static int mclk_prepare(struct clk_hw *hw) |
---|
| 902 | +{ |
---|
| 903 | + struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw); |
---|
| 904 | + |
---|
| 905 | + clk_prepare(cam->clk[0]); |
---|
| 906 | + return 0; |
---|
| 907 | +} |
---|
| 908 | + |
---|
| 909 | +static void mclk_unprepare(struct clk_hw *hw) |
---|
| 910 | +{ |
---|
| 911 | + struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw); |
---|
| 912 | + |
---|
| 913 | + clk_unprepare(cam->clk[0]); |
---|
| 914 | +} |
---|
| 915 | + |
---|
| 916 | +static int mclk_enable(struct clk_hw *hw) |
---|
| 917 | +{ |
---|
| 918 | + struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw); |
---|
| 919 | + int mclk_src; |
---|
| 920 | + int mclk_div; |
---|
| 921 | + int ret; |
---|
| 922 | + |
---|
| 923 | + /* |
---|
| 924 | + * Clock the sensor appropriately. Controller clock should |
---|
| 925 | + * be 48MHz, sensor "typical" value is half that. |
---|
| 926 | + */ |
---|
| 927 | + if (cam->bus_type == V4L2_MBUS_CSI2_DPHY) { |
---|
| 928 | + mclk_src = cam->mclk_src; |
---|
| 929 | + mclk_div = cam->mclk_div; |
---|
| 930 | + } else { |
---|
| 931 | + mclk_src = 3; |
---|
| 932 | + mclk_div = 2; |
---|
| 933 | + } |
---|
| 934 | + |
---|
| 935 | + ret = pm_runtime_resume_and_get(cam->dev); |
---|
| 936 | + if (ret < 0) |
---|
| 937 | + return ret; |
---|
| 938 | + clk_enable(cam->clk[0]); |
---|
| 939 | + mcam_reg_write(cam, REG_CLKCTRL, (mclk_src << 29) | mclk_div); |
---|
| 940 | + mcam_ctlr_power_up(cam); |
---|
| 941 | + |
---|
| 942 | + return 0; |
---|
| 943 | +} |
---|
| 944 | + |
---|
| 945 | +static void mclk_disable(struct clk_hw *hw) |
---|
| 946 | +{ |
---|
| 947 | + struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw); |
---|
| 948 | + |
---|
| 949 | + mcam_ctlr_power_down(cam); |
---|
| 950 | + clk_disable(cam->clk[0]); |
---|
| 951 | + pm_runtime_put(cam->dev); |
---|
| 952 | +} |
---|
| 953 | + |
---|
| 954 | +static unsigned long mclk_recalc_rate(struct clk_hw *hw, |
---|
| 955 | + unsigned long parent_rate) |
---|
| 956 | +{ |
---|
| 957 | + return 48000000; |
---|
| 958 | +} |
---|
| 959 | + |
---|
| 960 | +static const struct clk_ops mclk_ops = { |
---|
| 961 | + .prepare = mclk_prepare, |
---|
| 962 | + .unprepare = mclk_unprepare, |
---|
| 963 | + .enable = mclk_enable, |
---|
| 964 | + .disable = mclk_disable, |
---|
| 965 | + .recalc_rate = mclk_recalc_rate, |
---|
| 966 | +}; |
---|
929 | 967 | |
---|
930 | 968 | /* -------------------------------------------------------------------- */ |
---|
931 | 969 | /* |
---|
.. | .. |
---|
951 | 989 | ret = __mcam_cam_reset(cam); |
---|
952 | 990 | /* Get/set parameters? */ |
---|
953 | 991 | cam->state = S_IDLE; |
---|
954 | | - mcam_ctlr_power_down(cam); |
---|
955 | 992 | return ret; |
---|
956 | 993 | } |
---|
957 | 994 | |
---|
.. | .. |
---|
1017 | 1054 | spin_lock_irqsave(&cam->dev_lock, flags); |
---|
1018 | 1055 | clear_bit(CF_DMA_ACTIVE, &cam->flags); |
---|
1019 | 1056 | mcam_reset_buffers(cam); |
---|
1020 | | - /* |
---|
1021 | | - * Update CSI2_DPHY value |
---|
1022 | | - */ |
---|
1023 | | - if (cam->calc_dphy) |
---|
1024 | | - cam->calc_dphy(cam); |
---|
1025 | | - cam_dbg(cam, "camera: DPHY sets: dphy3=0x%x, dphy5=0x%x, dphy6=0x%x\n", |
---|
1026 | | - cam->dphy[0], cam->dphy[1], cam->dphy[2]); |
---|
1027 | | - if (cam->bus_type == V4L2_MBUS_CSI2) |
---|
| 1057 | + if (cam->bus_type == V4L2_MBUS_CSI2_DPHY) |
---|
1028 | 1058 | mcam_enable_mipi(cam); |
---|
1029 | 1059 | else |
---|
1030 | 1060 | mcam_disable_mipi(cam); |
---|
.. | .. |
---|
1161 | 1191 | return; |
---|
1162 | 1192 | mcam_ctlr_stop_dma(cam); |
---|
1163 | 1193 | /* |
---|
1164 | | - * Reset the CCIC PHY after stopping streaming, |
---|
1165 | | - * otherwise, the CCIC may be unstable. |
---|
1166 | | - */ |
---|
1167 | | - if (cam->ctlr_reset) |
---|
1168 | | - cam->ctlr_reset(cam); |
---|
1169 | | - /* |
---|
1170 | 1194 | * VB2 reclaims the buffers, so we need to forget |
---|
1171 | 1195 | * about them. |
---|
1172 | 1196 | */ |
---|
.. | .. |
---|
1281 | 1305 | break; |
---|
1282 | 1306 | case B_vmalloc: |
---|
1283 | 1307 | #ifdef MCAM_MODE_VMALLOC |
---|
1284 | | - tasklet_init(&cam->s_tasklet, mcam_frame_tasklet, |
---|
1285 | | - (unsigned long) cam); |
---|
| 1308 | + tasklet_setup(&cam->s_tasklet, mcam_frame_tasklet); |
---|
1286 | 1309 | vq->ops = &mcam_vb2_ops; |
---|
1287 | 1310 | vq->mem_ops = &vb2_vmalloc_memops; |
---|
1288 | 1311 | cam->dma_setup = mcam_ctlr_dma_vmalloc; |
---|
.. | .. |
---|
1304 | 1327 | { |
---|
1305 | 1328 | struct mcam_camera *cam = video_drvdata(file); |
---|
1306 | 1329 | |
---|
1307 | | - strcpy(cap->driver, "marvell_ccic"); |
---|
1308 | | - strcpy(cap->card, "marvell_ccic"); |
---|
1309 | | - strlcpy(cap->bus_info, cam->bus_info, sizeof(cap->bus_info)); |
---|
1310 | | - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | |
---|
1311 | | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; |
---|
1312 | | - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; |
---|
| 1330 | + strscpy(cap->driver, "marvell_ccic", sizeof(cap->driver)); |
---|
| 1331 | + strscpy(cap->card, "marvell_ccic", sizeof(cap->card)); |
---|
| 1332 | + strscpy(cap->bus_info, cam->bus_info, sizeof(cap->bus_info)); |
---|
1313 | 1333 | return 0; |
---|
1314 | 1334 | } |
---|
1315 | 1335 | |
---|
.. | .. |
---|
1319 | 1339 | { |
---|
1320 | 1340 | if (fmt->index >= N_MCAM_FMTS) |
---|
1321 | 1341 | return -EINVAL; |
---|
1322 | | - strlcpy(fmt->description, mcam_formats[fmt->index].desc, |
---|
1323 | | - sizeof(fmt->description)); |
---|
1324 | 1342 | fmt->pixelformat = mcam_formats[fmt->index].pixelformat; |
---|
1325 | 1343 | return 0; |
---|
1326 | 1344 | } |
---|
.. | .. |
---|
1422 | 1440 | return -EINVAL; |
---|
1423 | 1441 | |
---|
1424 | 1442 | input->type = V4L2_INPUT_TYPE_CAMERA; |
---|
1425 | | - strcpy(input->name, "Camera"); |
---|
| 1443 | + strscpy(input->name, "Camera", sizeof(input->name)); |
---|
1426 | 1444 | return 0; |
---|
1427 | 1445 | } |
---|
1428 | 1446 | |
---|
.. | .. |
---|
1593 | 1611 | if (ret) |
---|
1594 | 1612 | goto out; |
---|
1595 | 1613 | if (v4l2_fh_is_singular_file(filp)) { |
---|
1596 | | - ret = mcam_ctlr_power_up(cam); |
---|
| 1614 | + ret = sensor_call(cam, core, s_power, 1); |
---|
1597 | 1615 | if (ret) |
---|
| 1616 | + goto out; |
---|
| 1617 | + ret = pm_runtime_resume_and_get(cam->dev); |
---|
| 1618 | + if (ret < 0) |
---|
1598 | 1619 | goto out; |
---|
1599 | 1620 | __mcam_cam_reset(cam); |
---|
1600 | 1621 | mcam_set_config_needed(cam, 1); |
---|
.. | .. |
---|
1617 | 1638 | _vb2_fop_release(filp, NULL); |
---|
1618 | 1639 | if (last_open) { |
---|
1619 | 1640 | mcam_disable_mipi(cam); |
---|
1620 | | - mcam_ctlr_power_down(cam); |
---|
| 1641 | + sensor_call(cam, core, s_power, 0); |
---|
| 1642 | + pm_runtime_put(cam->dev); |
---|
1621 | 1643 | if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read) |
---|
1622 | 1644 | mcam_free_dma_bufs(cam); |
---|
1623 | 1645 | } |
---|
.. | .. |
---|
1646 | 1668 | .fops = &mcam_v4l_fops, |
---|
1647 | 1669 | .ioctl_ops = &mcam_v4l_ioctl_ops, |
---|
1648 | 1670 | .release = video_device_release_empty, |
---|
| 1671 | + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | |
---|
| 1672 | + V4L2_CAP_STREAMING, |
---|
1649 | 1673 | }; |
---|
1650 | 1674 | |
---|
1651 | 1675 | /* ---------------------------------------------------------------------- */ |
---|
.. | .. |
---|
1727 | 1751 | /* |
---|
1728 | 1752 | * Registration and such. |
---|
1729 | 1753 | */ |
---|
1730 | | -static struct ov7670_config sensor_cfg = { |
---|
1731 | | - /* |
---|
1732 | | - * Exclude QCIF mode, because it only captures a tiny portion |
---|
1733 | | - * of the sensor FOV |
---|
1734 | | - */ |
---|
1735 | | - .min_width = 320, |
---|
1736 | | - .min_height = 240, |
---|
1737 | | -}; |
---|
1738 | 1754 | |
---|
| 1755 | +static int mccic_notify_bound(struct v4l2_async_notifier *notifier, |
---|
| 1756 | + struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd) |
---|
| 1757 | +{ |
---|
| 1758 | + struct mcam_camera *cam = notifier_to_mcam(notifier); |
---|
| 1759 | + int ret; |
---|
| 1760 | + |
---|
| 1761 | + mutex_lock(&cam->s_mutex); |
---|
| 1762 | + if (cam->sensor) { |
---|
| 1763 | + cam_err(cam, "sensor already bound\n"); |
---|
| 1764 | + ret = -EBUSY; |
---|
| 1765 | + goto out; |
---|
| 1766 | + } |
---|
| 1767 | + |
---|
| 1768 | + v4l2_set_subdev_hostdata(subdev, cam); |
---|
| 1769 | + cam->sensor = subdev; |
---|
| 1770 | + |
---|
| 1771 | + ret = mcam_cam_init(cam); |
---|
| 1772 | + if (ret) { |
---|
| 1773 | + cam->sensor = NULL; |
---|
| 1774 | + goto out; |
---|
| 1775 | + } |
---|
| 1776 | + |
---|
| 1777 | + ret = mcam_setup_vb2(cam); |
---|
| 1778 | + if (ret) { |
---|
| 1779 | + cam->sensor = NULL; |
---|
| 1780 | + goto out; |
---|
| 1781 | + } |
---|
| 1782 | + |
---|
| 1783 | + cam->vdev = mcam_v4l_template; |
---|
| 1784 | + cam->vdev.v4l2_dev = &cam->v4l2_dev; |
---|
| 1785 | + cam->vdev.lock = &cam->s_mutex; |
---|
| 1786 | + cam->vdev.queue = &cam->vb_queue; |
---|
| 1787 | + video_set_drvdata(&cam->vdev, cam); |
---|
| 1788 | + ret = video_register_device(&cam->vdev, VFL_TYPE_VIDEO, -1); |
---|
| 1789 | + if (ret) { |
---|
| 1790 | + cam->sensor = NULL; |
---|
| 1791 | + goto out; |
---|
| 1792 | + } |
---|
| 1793 | + |
---|
| 1794 | + cam_dbg(cam, "sensor %s bound\n", subdev->name); |
---|
| 1795 | +out: |
---|
| 1796 | + mutex_unlock(&cam->s_mutex); |
---|
| 1797 | + return ret; |
---|
| 1798 | +} |
---|
| 1799 | + |
---|
| 1800 | +static void mccic_notify_unbind(struct v4l2_async_notifier *notifier, |
---|
| 1801 | + struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd) |
---|
| 1802 | +{ |
---|
| 1803 | + struct mcam_camera *cam = notifier_to_mcam(notifier); |
---|
| 1804 | + |
---|
| 1805 | + mutex_lock(&cam->s_mutex); |
---|
| 1806 | + if (cam->sensor != subdev) { |
---|
| 1807 | + cam_err(cam, "sensor %s not bound\n", subdev->name); |
---|
| 1808 | + goto out; |
---|
| 1809 | + } |
---|
| 1810 | + |
---|
| 1811 | + video_unregister_device(&cam->vdev); |
---|
| 1812 | + cam->sensor = NULL; |
---|
| 1813 | + cam_dbg(cam, "sensor %s unbound\n", subdev->name); |
---|
| 1814 | + |
---|
| 1815 | +out: |
---|
| 1816 | + mutex_unlock(&cam->s_mutex); |
---|
| 1817 | +} |
---|
| 1818 | + |
---|
| 1819 | +static int mccic_notify_complete(struct v4l2_async_notifier *notifier) |
---|
| 1820 | +{ |
---|
| 1821 | + struct mcam_camera *cam = notifier_to_mcam(notifier); |
---|
| 1822 | + int ret; |
---|
| 1823 | + |
---|
| 1824 | + /* |
---|
| 1825 | + * Get the v4l2 setup done. |
---|
| 1826 | + */ |
---|
| 1827 | + ret = v4l2_ctrl_handler_init(&cam->ctrl_handler, 10); |
---|
| 1828 | + if (!ret) |
---|
| 1829 | + cam->v4l2_dev.ctrl_handler = &cam->ctrl_handler; |
---|
| 1830 | + |
---|
| 1831 | + return ret; |
---|
| 1832 | +} |
---|
| 1833 | + |
---|
| 1834 | +static const struct v4l2_async_notifier_operations mccic_notify_ops = { |
---|
| 1835 | + .bound = mccic_notify_bound, |
---|
| 1836 | + .unbind = mccic_notify_unbind, |
---|
| 1837 | + .complete = mccic_notify_complete, |
---|
| 1838 | +}; |
---|
1739 | 1839 | |
---|
1740 | 1840 | int mccic_register(struct mcam_camera *cam) |
---|
1741 | 1841 | { |
---|
1742 | | - struct i2c_board_info ov7670_info = { |
---|
1743 | | - .type = "ov7670", |
---|
1744 | | - .addr = 0x42 >> 1, |
---|
1745 | | - .platform_data = &sensor_cfg, |
---|
1746 | | - }; |
---|
| 1842 | + struct clk_init_data mclk_init = { }; |
---|
1747 | 1843 | int ret; |
---|
1748 | 1844 | |
---|
1749 | 1845 | /* |
---|
.. | .. |
---|
1756 | 1852 | printk(KERN_ERR "marvell-cam: Cafe can't do S/G I/O, attempting vmalloc mode instead\n"); |
---|
1757 | 1853 | cam->buffer_mode = B_vmalloc; |
---|
1758 | 1854 | } |
---|
| 1855 | + |
---|
1759 | 1856 | if (!mcam_buffer_mode_supported(cam->buffer_mode)) { |
---|
1760 | 1857 | printk(KERN_ERR "marvell-cam: buffer mode %d unsupported\n", |
---|
1761 | 1858 | cam->buffer_mode); |
---|
1762 | | - return -EINVAL; |
---|
| 1859 | + ret = -EINVAL; |
---|
| 1860 | + goto out; |
---|
1763 | 1861 | } |
---|
| 1862 | + |
---|
1764 | 1863 | /* |
---|
1765 | 1864 | * Register with V4L |
---|
1766 | 1865 | */ |
---|
1767 | 1866 | ret = v4l2_device_register(cam->dev, &cam->v4l2_dev); |
---|
1768 | 1867 | if (ret) |
---|
1769 | | - return ret; |
---|
| 1868 | + goto out; |
---|
1770 | 1869 | |
---|
1771 | 1870 | mutex_init(&cam->s_mutex); |
---|
1772 | 1871 | cam->state = S_NOTREADY; |
---|
1773 | 1872 | mcam_set_config_needed(cam, 1); |
---|
1774 | 1873 | cam->pix_format = mcam_def_pix_format; |
---|
1775 | 1874 | cam->mbus_code = mcam_def_mbus_code; |
---|
1776 | | - mcam_ctlr_init(cam); |
---|
1777 | 1875 | |
---|
1778 | 1876 | /* |
---|
1779 | | - * Get the v4l2 setup done. |
---|
| 1877 | + * Register sensor notifier. |
---|
1780 | 1878 | */ |
---|
1781 | | - ret = v4l2_ctrl_handler_init(&cam->ctrl_handler, 10); |
---|
1782 | | - if (ret) |
---|
1783 | | - goto out_unregister; |
---|
1784 | | - cam->v4l2_dev.ctrl_handler = &cam->ctrl_handler; |
---|
1785 | | - |
---|
1786 | | - /* |
---|
1787 | | - * Try to find the sensor. |
---|
1788 | | - */ |
---|
1789 | | - sensor_cfg.clock_speed = cam->clock_speed; |
---|
1790 | | - sensor_cfg.use_smbus = cam->use_smbus; |
---|
1791 | | - cam->sensor_addr = ov7670_info.addr; |
---|
1792 | | - cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, |
---|
1793 | | - cam->i2c_adapter, &ov7670_info, NULL); |
---|
1794 | | - if (cam->sensor == NULL) { |
---|
1795 | | - ret = -ENODEV; |
---|
1796 | | - goto out_unregister; |
---|
| 1879 | + v4l2_async_notifier_init(&cam->notifier); |
---|
| 1880 | + ret = v4l2_async_notifier_add_subdev(&cam->notifier, &cam->asd); |
---|
| 1881 | + if (ret) { |
---|
| 1882 | + cam_warn(cam, "failed to add subdev to a notifier"); |
---|
| 1883 | + goto out; |
---|
1797 | 1884 | } |
---|
1798 | 1885 | |
---|
1799 | | - ret = mcam_cam_init(cam); |
---|
1800 | | - if (ret) |
---|
1801 | | - goto out_unregister; |
---|
| 1886 | + cam->notifier.ops = &mccic_notify_ops; |
---|
| 1887 | + ret = v4l2_async_notifier_register(&cam->v4l2_dev, &cam->notifier); |
---|
| 1888 | + if (ret < 0) { |
---|
| 1889 | + cam_warn(cam, "failed to register a sensor notifier"); |
---|
| 1890 | + goto out; |
---|
| 1891 | + } |
---|
1802 | 1892 | |
---|
1803 | | - ret = mcam_setup_vb2(cam); |
---|
1804 | | - if (ret) |
---|
1805 | | - goto out_unregister; |
---|
| 1893 | + /* |
---|
| 1894 | + * Register sensor master clock. |
---|
| 1895 | + */ |
---|
| 1896 | + mclk_init.parent_names = NULL; |
---|
| 1897 | + mclk_init.num_parents = 0; |
---|
| 1898 | + mclk_init.ops = &mclk_ops; |
---|
| 1899 | + mclk_init.name = "mclk"; |
---|
1806 | 1900 | |
---|
1807 | | - mutex_lock(&cam->s_mutex); |
---|
1808 | | - cam->vdev = mcam_v4l_template; |
---|
1809 | | - cam->vdev.v4l2_dev = &cam->v4l2_dev; |
---|
1810 | | - cam->vdev.lock = &cam->s_mutex; |
---|
1811 | | - cam->vdev.queue = &cam->vb_queue; |
---|
1812 | | - video_set_drvdata(&cam->vdev, cam); |
---|
1813 | | - ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); |
---|
1814 | | - if (ret) { |
---|
1815 | | - mutex_unlock(&cam->s_mutex); |
---|
1816 | | - goto out_unregister; |
---|
| 1901 | + of_property_read_string(cam->dev->of_node, "clock-output-names", |
---|
| 1902 | + &mclk_init.name); |
---|
| 1903 | + |
---|
| 1904 | + cam->mclk_hw.init = &mclk_init; |
---|
| 1905 | + |
---|
| 1906 | + cam->mclk = devm_clk_register(cam->dev, &cam->mclk_hw); |
---|
| 1907 | + if (IS_ERR(cam->mclk)) { |
---|
| 1908 | + ret = PTR_ERR(cam->mclk); |
---|
| 1909 | + dev_err(cam->dev, "can't register clock\n"); |
---|
| 1910 | + goto out; |
---|
1817 | 1911 | } |
---|
1818 | 1912 | |
---|
1819 | 1913 | /* |
---|
.. | .. |
---|
1824 | 1918 | cam_warn(cam, "Unable to alloc DMA buffers at load will try again later."); |
---|
1825 | 1919 | } |
---|
1826 | 1920 | |
---|
1827 | | - mutex_unlock(&cam->s_mutex); |
---|
1828 | 1921 | return 0; |
---|
1829 | 1922 | |
---|
1830 | | -out_unregister: |
---|
1831 | | - v4l2_ctrl_handler_free(&cam->ctrl_handler); |
---|
| 1923 | +out: |
---|
| 1924 | + v4l2_async_notifier_unregister(&cam->notifier); |
---|
1832 | 1925 | v4l2_device_unregister(&cam->v4l2_dev); |
---|
| 1926 | + v4l2_async_notifier_cleanup(&cam->notifier); |
---|
1833 | 1927 | return ret; |
---|
1834 | 1928 | } |
---|
1835 | 1929 | EXPORT_SYMBOL_GPL(mccic_register); |
---|
.. | .. |
---|
1844 | 1938 | */ |
---|
1845 | 1939 | if (!list_empty(&cam->vdev.fh_list)) { |
---|
1846 | 1940 | cam_warn(cam, "Removing a device with users!\n"); |
---|
1847 | | - mcam_ctlr_power_down(cam); |
---|
| 1941 | + sensor_call(cam, core, s_power, 0); |
---|
1848 | 1942 | } |
---|
1849 | 1943 | if (cam->buffer_mode == B_vmalloc) |
---|
1850 | 1944 | mcam_free_dma_bufs(cam); |
---|
1851 | | - video_unregister_device(&cam->vdev); |
---|
1852 | 1945 | v4l2_ctrl_handler_free(&cam->ctrl_handler); |
---|
| 1946 | + v4l2_async_notifier_unregister(&cam->notifier); |
---|
1853 | 1947 | v4l2_device_unregister(&cam->v4l2_dev); |
---|
| 1948 | + v4l2_async_notifier_cleanup(&cam->notifier); |
---|
1854 | 1949 | } |
---|
1855 | 1950 | EXPORT_SYMBOL_GPL(mccic_shutdown); |
---|
1856 | 1951 | |
---|
1857 | 1952 | /* |
---|
1858 | 1953 | * Power management |
---|
1859 | 1954 | */ |
---|
1860 | | -#ifdef CONFIG_PM |
---|
1861 | | - |
---|
1862 | 1955 | void mccic_suspend(struct mcam_camera *cam) |
---|
1863 | 1956 | { |
---|
1864 | 1957 | mutex_lock(&cam->s_mutex); |
---|
.. | .. |
---|
1866 | 1959 | enum mcam_state cstate = cam->state; |
---|
1867 | 1960 | |
---|
1868 | 1961 | mcam_ctlr_stop_dma(cam); |
---|
1869 | | - mcam_ctlr_power_down(cam); |
---|
| 1962 | + sensor_call(cam, core, s_power, 0); |
---|
1870 | 1963 | cam->state = cstate; |
---|
1871 | 1964 | } |
---|
1872 | 1965 | mutex_unlock(&cam->s_mutex); |
---|
.. | .. |
---|
1879 | 1972 | |
---|
1880 | 1973 | mutex_lock(&cam->s_mutex); |
---|
1881 | 1974 | if (!list_empty(&cam->vdev.fh_list)) { |
---|
1882 | | - ret = mcam_ctlr_power_up(cam); |
---|
| 1975 | + ret = sensor_call(cam, core, s_power, 1); |
---|
1883 | 1976 | if (ret) { |
---|
1884 | 1977 | mutex_unlock(&cam->s_mutex); |
---|
1885 | 1978 | return ret; |
---|
1886 | 1979 | } |
---|
1887 | 1980 | __mcam_cam_reset(cam); |
---|
1888 | 1981 | } else { |
---|
1889 | | - mcam_ctlr_power_down(cam); |
---|
| 1982 | + sensor_call(cam, core, s_power, 0); |
---|
1890 | 1983 | } |
---|
1891 | 1984 | mutex_unlock(&cam->s_mutex); |
---|
1892 | 1985 | |
---|
.. | .. |
---|
1903 | 1996 | return ret; |
---|
1904 | 1997 | } |
---|
1905 | 1998 | EXPORT_SYMBOL_GPL(mccic_resume); |
---|
1906 | | -#endif /* CONFIG_PM */ |
---|
1907 | 1999 | |
---|
1908 | 2000 | MODULE_LICENSE("GPL v2"); |
---|
1909 | 2001 | MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); |
---|