diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-23 17:39:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-23 17:39:09 -0400 |
commit | e317234975cb7463b8ca21a93bb6862d9dcf113f (patch) | |
tree | 4446fa3a21364f3cba23a22aa2a94027f169d8df /drivers/media/video/s5p-fimc | |
parent | f37ab0fba271e43edab0e3ae9fe644fcda455402 (diff) | |
parent | 7483d45f0aee3afc0646d185cabd4af9f6cab58c (diff) |
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- V4L2 API additions to better support JPEG compression control
- media API additions to properly support MPEG decoders
- V4L2 API additions for image crop/scaling
- a few other V4L2 API DocBook fixes/improvements
- two new DVB frontend drivers: m88rs2000 and rtl2830
- two new DVB drivers: az6007 and rtl28xxu
- a framework for ISA drivers, that removed lots of common code found
at the ISA radio drivers
- a new FM transmitter driver (radio-keene)
- a GPIO-based IR receiver driver
- a new sensor driver: mt9m032
- some new video drivers: adv7183, blackfin, mx2_emmaprp, sii9234_drv,
vs6624
- several new board additions, driver fixes, improvements and cleanups.
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (295 commits)
[media] update CARDLIST.em28xx
[media] partially reverts changeset fa5527c
[media] stb0899: fix the limits for signal strength values
[media] em28xx: support for 2304:0242 PCTV QuatroStick (510e)
[media] em28xx: support for 2013:0251 PCTV QuatroStick nano (520e)
[media] -EINVAL -> -ENOTTY
[media] gspca - sn9c20x: Cleanup source
[media] gspca - sn9c20x: Simplify register write for capture start/stop
[media] gspca - sn9c20x: Add automatic JPEG compression mechanism
[media] gspca - sn9c20x: Greater delay in case of sensor no response
[media] gspca - sn9c20x: Optimize the code of write sequences
[media] gspca - sn9c20x: Add the JPEG compression quality control
[media] gspca - sn9c20x: Add a delay after Omnivision sensor reset
[media] gspca - sn9c20x: Propagate USB errors to higher level
[media] gspca - sn9c20x: Use the new video control mechanism
[media] gspca - sn9c20x: Fix loss of frame start
[media] gspca - zc3xx: Lack of register 08 value for sensor cs2102k
[media] gspca - ov534_9: Add brightness to OmniVision 5621 sensor
[media] gspca - zc3xx: Add V4L2_CID_JPEG_COMPRESSION_QUALITY control support
[media] pvrusb2: fix 7MHz & 8MHz DVB-T tuner support for HVR1900 rev D1F5
...
Diffstat (limited to 'drivers/media/video/s5p-fimc')
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-capture.c | 121 | ||||
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-core.c | 85 | ||||
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-core.h | 2 | ||||
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-mdevice.c | 7 | ||||
-rw-r--r-- | drivers/media/video/s5p-fimc/mipi-csis.c | 111 |
5 files changed, 172 insertions, 154 deletions
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index a9e9653beeb4..b06efd208328 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c | |||
@@ -1019,52 +1019,117 @@ static int fimc_cap_dqbuf(struct file *file, void *priv, | |||
1019 | return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK); | 1019 | return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK); |
1020 | } | 1020 | } |
1021 | 1021 | ||
1022 | static int fimc_cap_cropcap(struct file *file, void *fh, | 1022 | static int fimc_cap_create_bufs(struct file *file, void *priv, |
1023 | struct v4l2_cropcap *cr) | 1023 | struct v4l2_create_buffers *create) |
1024 | { | 1024 | { |
1025 | struct fimc_dev *fimc = video_drvdata(file); | 1025 | struct fimc_dev *fimc = video_drvdata(file); |
1026 | struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame; | ||
1027 | 1026 | ||
1028 | if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | 1027 | return vb2_create_bufs(&fimc->vid_cap.vbq, create); |
1029 | return -EINVAL; | 1028 | } |
1030 | 1029 | ||
1031 | cr->bounds.left = 0; | 1030 | static int fimc_cap_prepare_buf(struct file *file, void *priv, |
1032 | cr->bounds.top = 0; | 1031 | struct v4l2_buffer *b) |
1033 | cr->bounds.width = f->o_width; | 1032 | { |
1034 | cr->bounds.height = f->o_height; | 1033 | struct fimc_dev *fimc = video_drvdata(file); |
1035 | cr->defrect = cr->bounds; | ||
1036 | 1034 | ||
1037 | return 0; | 1035 | return vb2_prepare_buf(&fimc->vid_cap.vbq, b); |
1038 | } | 1036 | } |
1039 | 1037 | ||
1040 | static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) | 1038 | static int fimc_cap_g_selection(struct file *file, void *fh, |
1039 | struct v4l2_selection *s) | ||
1041 | { | 1040 | { |
1042 | struct fimc_dev *fimc = video_drvdata(file); | 1041 | struct fimc_dev *fimc = video_drvdata(file); |
1043 | struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame; | 1042 | struct fimc_ctx *ctx = fimc->vid_cap.ctx; |
1043 | struct fimc_frame *f = &ctx->s_frame; | ||
1044 | 1044 | ||
1045 | cr->c.left = f->offs_h; | 1045 | if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) |
1046 | cr->c.top = f->offs_v; | 1046 | return -EINVAL; |
1047 | cr->c.width = f->width; | ||
1048 | cr->c.height = f->height; | ||
1049 | 1047 | ||
1050 | return 0; | 1048 | switch (s->target) { |
1049 | case V4L2_SEL_TGT_COMPOSE_DEFAULT: | ||
1050 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: | ||
1051 | f = &ctx->d_frame; | ||
1052 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
1053 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
1054 | s->r.left = 0; | ||
1055 | s->r.top = 0; | ||
1056 | s->r.width = f->o_width; | ||
1057 | s->r.height = f->o_height; | ||
1058 | return 0; | ||
1059 | |||
1060 | case V4L2_SEL_TGT_COMPOSE_ACTIVE: | ||
1061 | f = &ctx->d_frame; | ||
1062 | case V4L2_SEL_TGT_CROP_ACTIVE: | ||
1063 | s->r.left = f->offs_h; | ||
1064 | s->r.top = f->offs_v; | ||
1065 | s->r.width = f->width; | ||
1066 | s->r.height = f->height; | ||
1067 | return 0; | ||
1068 | } | ||
1069 | |||
1070 | return -EINVAL; | ||
1051 | } | 1071 | } |
1052 | 1072 | ||
1053 | static int fimc_cap_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) | 1073 | /* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */ |
1074 | int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) | ||
1075 | { | ||
1076 | if (a->left < b->left || a->top < b->top) | ||
1077 | return 0; | ||
1078 | if (a->left + a->width > b->left + b->width) | ||
1079 | return 0; | ||
1080 | if (a->top + a->height > b->top + b->height) | ||
1081 | return 0; | ||
1082 | |||
1083 | return 1; | ||
1084 | } | ||
1085 | |||
1086 | static int fimc_cap_s_selection(struct file *file, void *fh, | ||
1087 | struct v4l2_selection *s) | ||
1054 | { | 1088 | { |
1055 | struct fimc_dev *fimc = video_drvdata(file); | 1089 | struct fimc_dev *fimc = video_drvdata(file); |
1056 | struct fimc_ctx *ctx = fimc->vid_cap.ctx; | 1090 | struct fimc_ctx *ctx = fimc->vid_cap.ctx; |
1057 | struct fimc_frame *ff; | 1091 | struct v4l2_rect rect = s->r; |
1092 | struct fimc_frame *f; | ||
1058 | unsigned long flags; | 1093 | unsigned long flags; |
1094 | unsigned int pad; | ||
1059 | 1095 | ||
1060 | fimc_capture_try_crop(ctx, &cr->c, FIMC_SD_PAD_SINK); | 1096 | if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) |
1061 | ff = &ctx->s_frame; | 1097 | return -EINVAL; |
1062 | 1098 | ||
1099 | switch (s->target) { | ||
1100 | case V4L2_SEL_TGT_COMPOSE_DEFAULT: | ||
1101 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: | ||
1102 | case V4L2_SEL_TGT_COMPOSE_ACTIVE: | ||
1103 | f = &ctx->d_frame; | ||
1104 | pad = FIMC_SD_PAD_SOURCE; | ||
1105 | break; | ||
1106 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
1107 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
1108 | case V4L2_SEL_TGT_CROP_ACTIVE: | ||
1109 | f = &ctx->s_frame; | ||
1110 | pad = FIMC_SD_PAD_SINK; | ||
1111 | break; | ||
1112 | default: | ||
1113 | return -EINVAL; | ||
1114 | } | ||
1115 | |||
1116 | fimc_capture_try_crop(ctx, &rect, pad); | ||
1117 | |||
1118 | if (s->flags & V4L2_SEL_FLAG_LE && | ||
1119 | !enclosed_rectangle(&rect, &s->r)) | ||
1120 | return -ERANGE; | ||
1121 | |||
1122 | if (s->flags & V4L2_SEL_FLAG_GE && | ||
1123 | !enclosed_rectangle(&s->r, &rect)) | ||
1124 | return -ERANGE; | ||
1125 | |||
1126 | s->r = rect; | ||
1063 | spin_lock_irqsave(&fimc->slock, flags); | 1127 | spin_lock_irqsave(&fimc->slock, flags); |
1064 | set_frame_crop(ff, cr->c.left, cr->c.top, cr->c.width, cr->c.height); | 1128 | set_frame_crop(f, s->r.left, s->r.top, s->r.width, |
1065 | set_bit(ST_CAPT_APPLY_CFG, &fimc->state); | 1129 | s->r.height); |
1066 | spin_unlock_irqrestore(&fimc->slock, flags); | 1130 | spin_unlock_irqrestore(&fimc->slock, flags); |
1067 | 1131 | ||
1132 | set_bit(ST_CAPT_APPLY_CFG, &fimc->state); | ||
1068 | return 0; | 1133 | return 0; |
1069 | } | 1134 | } |
1070 | 1135 | ||
@@ -1082,12 +1147,14 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { | |||
1082 | .vidioc_qbuf = fimc_cap_qbuf, | 1147 | .vidioc_qbuf = fimc_cap_qbuf, |
1083 | .vidioc_dqbuf = fimc_cap_dqbuf, | 1148 | .vidioc_dqbuf = fimc_cap_dqbuf, |
1084 | 1149 | ||
1150 | .vidioc_prepare_buf = fimc_cap_prepare_buf, | ||
1151 | .vidioc_create_bufs = fimc_cap_create_bufs, | ||
1152 | |||
1085 | .vidioc_streamon = fimc_cap_streamon, | 1153 | .vidioc_streamon = fimc_cap_streamon, |
1086 | .vidioc_streamoff = fimc_cap_streamoff, | 1154 | .vidioc_streamoff = fimc_cap_streamoff, |
1087 | 1155 | ||
1088 | .vidioc_g_crop = fimc_cap_g_crop, | 1156 | .vidioc_g_selection = fimc_cap_g_selection, |
1089 | .vidioc_s_crop = fimc_cap_s_crop, | 1157 | .vidioc_s_selection = fimc_cap_s_selection, |
1090 | .vidioc_cropcap = fimc_cap_cropcap, | ||
1091 | 1158 | ||
1092 | .vidioc_enum_input = fimc_cap_enum_input, | 1159 | .vidioc_enum_input = fimc_cap_enum_input, |
1093 | .vidioc_s_input = fimc_cap_s_input, | 1160 | .vidioc_s_input = fimc_cap_s_input, |
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 81bcbb9492ea..e184e650022a 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c | |||
@@ -1602,24 +1602,35 @@ static void fimc_clk_put(struct fimc_dev *fimc) | |||
1602 | { | 1602 | { |
1603 | int i; | 1603 | int i; |
1604 | for (i = 0; i < fimc->num_clocks; i++) { | 1604 | for (i = 0; i < fimc->num_clocks; i++) { |
1605 | if (fimc->clock[i]) | 1605 | if (IS_ERR_OR_NULL(fimc->clock[i])) |
1606 | clk_put(fimc->clock[i]); | 1606 | continue; |
1607 | clk_unprepare(fimc->clock[i]); | ||
1608 | clk_put(fimc->clock[i]); | ||
1609 | fimc->clock[i] = NULL; | ||
1607 | } | 1610 | } |
1608 | } | 1611 | } |
1609 | 1612 | ||
1610 | static int fimc_clk_get(struct fimc_dev *fimc) | 1613 | static int fimc_clk_get(struct fimc_dev *fimc) |
1611 | { | 1614 | { |
1612 | int i; | 1615 | int i, ret; |
1616 | |||
1613 | for (i = 0; i < fimc->num_clocks; i++) { | 1617 | for (i = 0; i < fimc->num_clocks; i++) { |
1614 | fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]); | 1618 | fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]); |
1615 | if (!IS_ERR_OR_NULL(fimc->clock[i])) | 1619 | if (IS_ERR(fimc->clock[i])) |
1616 | continue; | 1620 | goto err; |
1617 | dev_err(&fimc->pdev->dev, "failed to get fimc clock: %s\n", | 1621 | ret = clk_prepare(fimc->clock[i]); |
1618 | fimc_clocks[i]); | 1622 | if (ret < 0) { |
1619 | return -ENXIO; | 1623 | clk_put(fimc->clock[i]); |
1624 | fimc->clock[i] = NULL; | ||
1625 | goto err; | ||
1626 | } | ||
1620 | } | 1627 | } |
1621 | |||
1622 | return 0; | 1628 | return 0; |
1629 | err: | ||
1630 | fimc_clk_put(fimc); | ||
1631 | dev_err(&fimc->pdev->dev, "failed to get clock: %s\n", | ||
1632 | fimc_clocks[i]); | ||
1633 | return -ENXIO; | ||
1623 | } | 1634 | } |
1624 | 1635 | ||
1625 | static int fimc_m2m_suspend(struct fimc_dev *fimc) | 1636 | static int fimc_m2m_suspend(struct fimc_dev *fimc) |
@@ -1667,8 +1678,6 @@ static int fimc_probe(struct platform_device *pdev) | |||
1667 | struct s5p_platform_fimc *pdata; | 1678 | struct s5p_platform_fimc *pdata; |
1668 | int ret = 0; | 1679 | int ret = 0; |
1669 | 1680 | ||
1670 | dev_dbg(&pdev->dev, "%s():\n", __func__); | ||
1671 | |||
1672 | drv_data = (struct samsung_fimc_driverdata *) | 1681 | drv_data = (struct samsung_fimc_driverdata *) |
1673 | platform_get_device_id(pdev)->driver_data; | 1682 | platform_get_device_id(pdev)->driver_data; |
1674 | 1683 | ||
@@ -1678,7 +1687,7 @@ static int fimc_probe(struct platform_device *pdev) | |||
1678 | return -EINVAL; | 1687 | return -EINVAL; |
1679 | } | 1688 | } |
1680 | 1689 | ||
1681 | fimc = kzalloc(sizeof(struct fimc_dev), GFP_KERNEL); | 1690 | fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL); |
1682 | if (!fimc) | 1691 | if (!fimc) |
1683 | return -ENOMEM; | 1692 | return -ENOMEM; |
1684 | 1693 | ||
@@ -1689,51 +1698,35 @@ static int fimc_probe(struct platform_device *pdev) | |||
1689 | pdata = pdev->dev.platform_data; | 1698 | pdata = pdev->dev.platform_data; |
1690 | fimc->pdata = pdata; | 1699 | fimc->pdata = pdata; |
1691 | 1700 | ||
1692 | |||
1693 | init_waitqueue_head(&fimc->irq_queue); | 1701 | init_waitqueue_head(&fimc->irq_queue); |
1694 | spin_lock_init(&fimc->slock); | 1702 | spin_lock_init(&fimc->slock); |
1695 | mutex_init(&fimc->lock); | 1703 | mutex_init(&fimc->lock); |
1696 | 1704 | ||
1697 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1705 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1698 | if (!res) { | 1706 | fimc->regs = devm_request_and_ioremap(&pdev->dev, res); |
1699 | dev_err(&pdev->dev, "failed to find the registers\n"); | 1707 | if (fimc->regs == NULL) { |
1700 | ret = -ENOENT; | 1708 | dev_err(&pdev->dev, "Failed to obtain io memory\n"); |
1701 | goto err_info; | 1709 | return -ENOENT; |
1702 | } | ||
1703 | |||
1704 | fimc->regs_res = request_mem_region(res->start, resource_size(res), | ||
1705 | dev_name(&pdev->dev)); | ||
1706 | if (!fimc->regs_res) { | ||
1707 | dev_err(&pdev->dev, "failed to obtain register region\n"); | ||
1708 | ret = -ENOENT; | ||
1709 | goto err_info; | ||
1710 | } | ||
1711 | |||
1712 | fimc->regs = ioremap(res->start, resource_size(res)); | ||
1713 | if (!fimc->regs) { | ||
1714 | dev_err(&pdev->dev, "failed to map registers\n"); | ||
1715 | ret = -ENXIO; | ||
1716 | goto err_req_region; | ||
1717 | } | 1710 | } |
1718 | 1711 | ||
1719 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 1712 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
1720 | if (!res) { | 1713 | if (res == NULL) { |
1721 | dev_err(&pdev->dev, "failed to get IRQ resource\n"); | 1714 | dev_err(&pdev->dev, "Failed to get IRQ resource\n"); |
1722 | ret = -ENXIO; | 1715 | return -ENXIO; |
1723 | goto err_regs_unmap; | ||
1724 | } | 1716 | } |
1725 | fimc->irq = res->start; | 1717 | fimc->irq = res->start; |
1726 | 1718 | ||
1727 | fimc->num_clocks = MAX_FIMC_CLOCKS; | 1719 | fimc->num_clocks = MAX_FIMC_CLOCKS; |
1728 | ret = fimc_clk_get(fimc); | 1720 | ret = fimc_clk_get(fimc); |
1729 | if (ret) | 1721 | if (ret) |
1730 | goto err_regs_unmap; | 1722 | return ret; |
1731 | clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency); | 1723 | clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency); |
1732 | clk_enable(fimc->clock[CLK_BUS]); | 1724 | clk_enable(fimc->clock[CLK_BUS]); |
1733 | 1725 | ||
1734 | platform_set_drvdata(pdev, fimc); | 1726 | platform_set_drvdata(pdev, fimc); |
1735 | 1727 | ||
1736 | ret = request_irq(fimc->irq, fimc_irq_handler, 0, pdev->name, fimc); | 1728 | ret = devm_request_irq(&pdev->dev, fimc->irq, fimc_irq_handler, |
1729 | 0, pdev->name, fimc); | ||
1737 | if (ret) { | 1730 | if (ret) { |
1738 | dev_err(&pdev->dev, "failed to install irq (%d)\n", ret); | 1731 | dev_err(&pdev->dev, "failed to install irq (%d)\n", ret); |
1739 | goto err_clk; | 1732 | goto err_clk; |
@@ -1742,7 +1735,7 @@ static int fimc_probe(struct platform_device *pdev) | |||
1742 | pm_runtime_enable(&pdev->dev); | 1735 | pm_runtime_enable(&pdev->dev); |
1743 | ret = pm_runtime_get_sync(&pdev->dev); | 1736 | ret = pm_runtime_get_sync(&pdev->dev); |
1744 | if (ret < 0) | 1737 | if (ret < 0) |
1745 | goto err_irq; | 1738 | goto err_clk; |
1746 | /* Initialize contiguous memory allocator */ | 1739 | /* Initialize contiguous memory allocator */ |
1747 | fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | 1740 | fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); |
1748 | if (IS_ERR(fimc->alloc_ctx)) { | 1741 | if (IS_ERR(fimc->alloc_ctx)) { |
@@ -1757,17 +1750,8 @@ static int fimc_probe(struct platform_device *pdev) | |||
1757 | 1750 | ||
1758 | err_pm: | 1751 | err_pm: |
1759 | pm_runtime_put(&pdev->dev); | 1752 | pm_runtime_put(&pdev->dev); |
1760 | err_irq: | ||
1761 | free_irq(fimc->irq, fimc); | ||
1762 | err_clk: | 1753 | err_clk: |
1763 | fimc_clk_put(fimc); | 1754 | fimc_clk_put(fimc); |
1764 | err_regs_unmap: | ||
1765 | iounmap(fimc->regs); | ||
1766 | err_req_region: | ||
1767 | release_resource(fimc->regs_res); | ||
1768 | kfree(fimc->regs_res); | ||
1769 | err_info: | ||
1770 | kfree(fimc); | ||
1771 | return ret; | 1755 | return ret; |
1772 | } | 1756 | } |
1773 | 1757 | ||
@@ -1854,11 +1838,6 @@ static int __devexit fimc_remove(struct platform_device *pdev) | |||
1854 | 1838 | ||
1855 | clk_disable(fimc->clock[CLK_BUS]); | 1839 | clk_disable(fimc->clock[CLK_BUS]); |
1856 | fimc_clk_put(fimc); | 1840 | fimc_clk_put(fimc); |
1857 | free_irq(fimc->irq, fimc); | ||
1858 | iounmap(fimc->regs); | ||
1859 | release_resource(fimc->regs_res); | ||
1860 | kfree(fimc->regs_res); | ||
1861 | kfree(fimc); | ||
1862 | 1841 | ||
1863 | dev_info(&pdev->dev, "driver unloaded\n"); | 1842 | dev_info(&pdev->dev, "driver unloaded\n"); |
1864 | return 0; | 1843 | return 0; |
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 4e20560c73d4..a18291e648e2 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h | |||
@@ -434,7 +434,6 @@ struct fimc_ctx; | |||
434 | * @num_clocks: the number of clocks managed by this device instance | 434 | * @num_clocks: the number of clocks managed by this device instance |
435 | * @clock: clocks required for FIMC operation | 435 | * @clock: clocks required for FIMC operation |
436 | * @regs: the mapped hardware registers | 436 | * @regs: the mapped hardware registers |
437 | * @regs_res: the resource claimed for IO registers | ||
438 | * @irq: FIMC interrupt number | 437 | * @irq: FIMC interrupt number |
439 | * @irq_queue: interrupt handler waitqueue | 438 | * @irq_queue: interrupt handler waitqueue |
440 | * @v4l2_dev: root v4l2_device | 439 | * @v4l2_dev: root v4l2_device |
@@ -454,7 +453,6 @@ struct fimc_dev { | |||
454 | u16 num_clocks; | 453 | u16 num_clocks; |
455 | struct clk *clock[MAX_FIMC_CLOCKS]; | 454 | struct clk *clock[MAX_FIMC_CLOCKS]; |
456 | void __iomem *regs; | 455 | void __iomem *regs; |
457 | struct resource *regs_res; | ||
458 | int irq; | 456 | int irq; |
459 | wait_queue_head_t irq_queue; | 457 | wait_queue_head_t irq_queue; |
460 | struct v4l2_device *v4l2_dev; | 458 | struct v4l2_device *v4l2_dev; |
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c index 63eccb55728f..62ed37e40149 100644 --- a/drivers/media/video/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c | |||
@@ -750,7 +750,7 @@ static int __devinit fimc_md_probe(struct platform_device *pdev) | |||
750 | struct fimc_md *fmd; | 750 | struct fimc_md *fmd; |
751 | int ret; | 751 | int ret; |
752 | 752 | ||
753 | fmd = kzalloc(sizeof(struct fimc_md), GFP_KERNEL); | 753 | fmd = devm_kzalloc(&pdev->dev, sizeof(*fmd), GFP_KERNEL); |
754 | if (!fmd) | 754 | if (!fmd) |
755 | return -ENOMEM; | 755 | return -ENOMEM; |
756 | 756 | ||
@@ -771,7 +771,7 @@ static int __devinit fimc_md_probe(struct platform_device *pdev) | |||
771 | ret = v4l2_device_register(&pdev->dev, &fmd->v4l2_dev); | 771 | ret = v4l2_device_register(&pdev->dev, &fmd->v4l2_dev); |
772 | if (ret < 0) { | 772 | if (ret < 0) { |
773 | v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); | 773 | v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); |
774 | goto err1; | 774 | return ret; |
775 | } | 775 | } |
776 | ret = media_device_register(&fmd->media_dev); | 776 | ret = media_device_register(&fmd->media_dev); |
777 | if (ret < 0) { | 777 | if (ret < 0) { |
@@ -813,8 +813,6 @@ err3: | |||
813 | fimc_md_unregister_entities(fmd); | 813 | fimc_md_unregister_entities(fmd); |
814 | err2: | 814 | err2: |
815 | v4l2_device_unregister(&fmd->v4l2_dev); | 815 | v4l2_device_unregister(&fmd->v4l2_dev); |
816 | err1: | ||
817 | kfree(fmd); | ||
818 | return ret; | 816 | return ret; |
819 | } | 817 | } |
820 | 818 | ||
@@ -828,7 +826,6 @@ static int __devexit fimc_md_remove(struct platform_device *pdev) | |||
828 | fimc_md_unregister_entities(fmd); | 826 | fimc_md_unregister_entities(fmd); |
829 | media_device_unregister(&fmd->media_dev); | 827 | media_device_unregister(&fmd->media_dev); |
830 | fimc_md_put_clocks(fmd); | 828 | fimc_md_put_clocks(fmd); |
831 | kfree(fmd); | ||
832 | return 0; | 829 | return 0; |
833 | } | 830 | } |
834 | 831 | ||
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/video/s5p-fimc/mipi-csis.c index 130335cf62fd..f44f690397f7 100644 --- a/drivers/media/video/s5p-fimc/mipi-csis.c +++ b/drivers/media/video/s5p-fimc/mipi-csis.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver | 2 | * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | 4 | * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. |
5 | * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com> | 5 | * Sylwester Nawrocki, <s.nawrocki@samsung.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
@@ -100,7 +100,6 @@ enum { | |||
100 | * @pads: CSIS pads array | 100 | * @pads: CSIS pads array |
101 | * @sd: v4l2_subdev associated with CSIS device instance | 101 | * @sd: v4l2_subdev associated with CSIS device instance |
102 | * @pdev: CSIS platform device | 102 | * @pdev: CSIS platform device |
103 | * @regs_res: requested I/O register memory resource | ||
104 | * @regs: mmaped I/O registers memory | 103 | * @regs: mmaped I/O registers memory |
105 | * @clock: CSIS clocks | 104 | * @clock: CSIS clocks |
106 | * @irq: requested s5p-mipi-csis irq number | 105 | * @irq: requested s5p-mipi-csis irq number |
@@ -113,7 +112,6 @@ struct csis_state { | |||
113 | struct media_pad pads[CSIS_PADS_NUM]; | 112 | struct media_pad pads[CSIS_PADS_NUM]; |
114 | struct v4l2_subdev sd; | 113 | struct v4l2_subdev sd; |
115 | struct platform_device *pdev; | 114 | struct platform_device *pdev; |
116 | struct resource *regs_res; | ||
117 | void __iomem *regs; | 115 | void __iomem *regs; |
118 | struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES]; | 116 | struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES]; |
119 | struct clk *clock[NUM_CSIS_CLOCKS]; | 117 | struct clk *clock[NUM_CSIS_CLOCKS]; |
@@ -258,26 +256,36 @@ static void s5pcsis_clk_put(struct csis_state *state) | |||
258 | { | 256 | { |
259 | int i; | 257 | int i; |
260 | 258 | ||
261 | for (i = 0; i < NUM_CSIS_CLOCKS; i++) | 259 | for (i = 0; i < NUM_CSIS_CLOCKS; i++) { |
262 | if (!IS_ERR_OR_NULL(state->clock[i])) | 260 | if (IS_ERR_OR_NULL(state->clock[i])) |
263 | clk_put(state->clock[i]); | 261 | continue; |
262 | clk_unprepare(state->clock[i]); | ||
263 | clk_put(state->clock[i]); | ||
264 | state->clock[i] = NULL; | ||
265 | } | ||
264 | } | 266 | } |
265 | 267 | ||
266 | static int s5pcsis_clk_get(struct csis_state *state) | 268 | static int s5pcsis_clk_get(struct csis_state *state) |
267 | { | 269 | { |
268 | struct device *dev = &state->pdev->dev; | 270 | struct device *dev = &state->pdev->dev; |
269 | int i; | 271 | int i, ret; |
270 | 272 | ||
271 | for (i = 0; i < NUM_CSIS_CLOCKS; i++) { | 273 | for (i = 0; i < NUM_CSIS_CLOCKS; i++) { |
272 | state->clock[i] = clk_get(dev, csi_clock_name[i]); | 274 | state->clock[i] = clk_get(dev, csi_clock_name[i]); |
273 | if (IS_ERR(state->clock[i])) { | 275 | if (IS_ERR(state->clock[i])) |
274 | s5pcsis_clk_put(state); | 276 | goto err; |
275 | dev_err(dev, "failed to get clock: %s\n", | 277 | ret = clk_prepare(state->clock[i]); |
276 | csi_clock_name[i]); | 278 | if (ret < 0) { |
277 | return -ENXIO; | 279 | clk_put(state->clock[i]); |
280 | state->clock[i] = NULL; | ||
281 | goto err; | ||
278 | } | 282 | } |
279 | } | 283 | } |
280 | return 0; | 284 | return 0; |
285 | err: | ||
286 | s5pcsis_clk_put(state); | ||
287 | dev_err(dev, "failed to get clock: %s\n", csi_clock_name[i]); | ||
288 | return -ENXIO; | ||
281 | } | 289 | } |
282 | 290 | ||
283 | static int s5pcsis_s_power(struct v4l2_subdev *sd, int on) | 291 | static int s5pcsis_s_power(struct v4l2_subdev *sd, int on) |
@@ -480,12 +488,11 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) | |||
480 | { | 488 | { |
481 | struct s5p_platform_mipi_csis *pdata; | 489 | struct s5p_platform_mipi_csis *pdata; |
482 | struct resource *mem_res; | 490 | struct resource *mem_res; |
483 | struct resource *regs_res; | ||
484 | struct csis_state *state; | 491 | struct csis_state *state; |
485 | int ret = -ENOMEM; | 492 | int ret = -ENOMEM; |
486 | int i; | 493 | int i; |
487 | 494 | ||
488 | state = kzalloc(sizeof(*state), GFP_KERNEL); | 495 | state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL); |
489 | if (!state) | 496 | if (!state) |
490 | return -ENOMEM; | 497 | return -ENOMEM; |
491 | 498 | ||
@@ -495,52 +502,27 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) | |||
495 | pdata = pdev->dev.platform_data; | 502 | pdata = pdev->dev.platform_data; |
496 | if (pdata == NULL || pdata->phy_enable == NULL) { | 503 | if (pdata == NULL || pdata->phy_enable == NULL) { |
497 | dev_err(&pdev->dev, "Platform data not fully specified\n"); | 504 | dev_err(&pdev->dev, "Platform data not fully specified\n"); |
498 | goto e_free; | 505 | return -EINVAL; |
499 | } | 506 | } |
500 | 507 | ||
501 | if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) || | 508 | if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) || |
502 | pdata->lanes > CSIS0_MAX_LANES) { | 509 | pdata->lanes > CSIS0_MAX_LANES) { |
503 | ret = -EINVAL; | ||
504 | dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n", | 510 | dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n", |
505 | pdata->lanes); | 511 | pdata->lanes); |
506 | goto e_free; | 512 | return -EINVAL; |
507 | } | 513 | } |
508 | 514 | ||
509 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 515 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
510 | if (!mem_res) { | 516 | state->regs = devm_request_and_ioremap(&pdev->dev, mem_res); |
511 | dev_err(&pdev->dev, "Failed to get IO memory region\n"); | 517 | if (state->regs == NULL) { |
512 | goto e_free; | 518 | dev_err(&pdev->dev, "Failed to request and remap io memory\n"); |
519 | return -ENXIO; | ||
513 | } | 520 | } |
514 | 521 | ||
515 | regs_res = request_mem_region(mem_res->start, resource_size(mem_res), | ||
516 | pdev->name); | ||
517 | if (!regs_res) { | ||
518 | dev_err(&pdev->dev, "Failed to request IO memory region\n"); | ||
519 | goto e_free; | ||
520 | } | ||
521 | state->regs_res = regs_res; | ||
522 | |||
523 | state->regs = ioremap(mem_res->start, resource_size(mem_res)); | ||
524 | if (!state->regs) { | ||
525 | dev_err(&pdev->dev, "Failed to remap IO region\n"); | ||
526 | goto e_reqmem; | ||
527 | } | ||
528 | |||
529 | ret = s5pcsis_clk_get(state); | ||
530 | if (ret) | ||
531 | goto e_unmap; | ||
532 | |||
533 | clk_enable(state->clock[CSIS_CLK_MUX]); | ||
534 | if (pdata->clk_rate) | ||
535 | clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate); | ||
536 | else | ||
537 | dev_WARN(&pdev->dev, "No clock frequency specified!\n"); | ||
538 | |||
539 | state->irq = platform_get_irq(pdev, 0); | 522 | state->irq = platform_get_irq(pdev, 0); |
540 | if (state->irq < 0) { | 523 | if (state->irq < 0) { |
541 | ret = state->irq; | ||
542 | dev_err(&pdev->dev, "Failed to get irq\n"); | 524 | dev_err(&pdev->dev, "Failed to get irq\n"); |
543 | goto e_clkput; | 525 | return state->irq; |
544 | } | 526 | } |
545 | 527 | ||
546 | for (i = 0; i < CSIS_NUM_SUPPLIES; i++) | 528 | for (i = 0; i < CSIS_NUM_SUPPLIES; i++) |
@@ -549,12 +531,22 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) | |||
549 | ret = regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES, | 531 | ret = regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES, |
550 | state->supplies); | 532 | state->supplies); |
551 | if (ret) | 533 | if (ret) |
534 | return ret; | ||
535 | |||
536 | ret = s5pcsis_clk_get(state); | ||
537 | if (ret) | ||
552 | goto e_clkput; | 538 | goto e_clkput; |
553 | 539 | ||
554 | ret = request_irq(state->irq, s5pcsis_irq_handler, 0, | 540 | clk_enable(state->clock[CSIS_CLK_MUX]); |
555 | dev_name(&pdev->dev), state); | 541 | if (pdata->clk_rate) |
542 | clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate); | ||
543 | else | ||
544 | dev_WARN(&pdev->dev, "No clock frequency specified!\n"); | ||
545 | |||
546 | ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler, | ||
547 | 0, dev_name(&pdev->dev), state); | ||
556 | if (ret) { | 548 | if (ret) { |
557 | dev_err(&pdev->dev, "request_irq failed\n"); | 549 | dev_err(&pdev->dev, "Interrupt request failed\n"); |
558 | goto e_regput; | 550 | goto e_regput; |
559 | } | 551 | } |
560 | 552 | ||
@@ -573,7 +565,7 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) | |||
573 | ret = media_entity_init(&state->sd.entity, | 565 | ret = media_entity_init(&state->sd.entity, |
574 | CSIS_PADS_NUM, state->pads, 0); | 566 | CSIS_PADS_NUM, state->pads, 0); |
575 | if (ret < 0) | 567 | if (ret < 0) |
576 | goto e_irqfree; | 568 | goto e_clkput; |
577 | 569 | ||
578 | /* This allows to retrieve the platform device id by the host driver */ | 570 | /* This allows to retrieve the platform device id by the host driver */ |
579 | v4l2_set_subdevdata(&state->sd, pdev); | 571 | v4l2_set_subdevdata(&state->sd, pdev); |
@@ -582,22 +574,13 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) | |||
582 | platform_set_drvdata(pdev, &state->sd); | 574 | platform_set_drvdata(pdev, &state->sd); |
583 | 575 | ||
584 | pm_runtime_enable(&pdev->dev); | 576 | pm_runtime_enable(&pdev->dev); |
585 | |||
586 | return 0; | 577 | return 0; |
587 | 578 | ||
588 | e_irqfree: | ||
589 | free_irq(state->irq, state); | ||
590 | e_regput: | 579 | e_regput: |
591 | regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); | 580 | regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); |
592 | e_clkput: | 581 | e_clkput: |
593 | clk_disable(state->clock[CSIS_CLK_MUX]); | 582 | clk_disable(state->clock[CSIS_CLK_MUX]); |
594 | s5pcsis_clk_put(state); | 583 | s5pcsis_clk_put(state); |
595 | e_unmap: | ||
596 | iounmap(state->regs); | ||
597 | e_reqmem: | ||
598 | release_mem_region(regs_res->start, resource_size(regs_res)); | ||
599 | e_free: | ||
600 | kfree(state); | ||
601 | return ret; | 584 | return ret; |
602 | } | 585 | } |
603 | 586 | ||
@@ -699,21 +682,15 @@ static int __devexit s5pcsis_remove(struct platform_device *pdev) | |||
699 | { | 682 | { |
700 | struct v4l2_subdev *sd = platform_get_drvdata(pdev); | 683 | struct v4l2_subdev *sd = platform_get_drvdata(pdev); |
701 | struct csis_state *state = sd_to_csis_state(sd); | 684 | struct csis_state *state = sd_to_csis_state(sd); |
702 | struct resource *res = state->regs_res; | ||
703 | 685 | ||
704 | pm_runtime_disable(&pdev->dev); | 686 | pm_runtime_disable(&pdev->dev); |
705 | s5pcsis_suspend(&pdev->dev); | 687 | s5pcsis_pm_suspend(&pdev->dev, false); |
706 | clk_disable(state->clock[CSIS_CLK_MUX]); | 688 | clk_disable(state->clock[CSIS_CLK_MUX]); |
707 | pm_runtime_set_suspended(&pdev->dev); | 689 | pm_runtime_set_suspended(&pdev->dev); |
708 | |||
709 | s5pcsis_clk_put(state); | 690 | s5pcsis_clk_put(state); |
710 | regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); | 691 | regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); |
711 | 692 | ||
712 | media_entity_cleanup(&state->sd.entity); | 693 | media_entity_cleanup(&state->sd.entity); |
713 | free_irq(state->irq, state); | ||
714 | iounmap(state->regs); | ||
715 | release_mem_region(res->start, resource_size(res)); | ||
716 | kfree(state); | ||
717 | 694 | ||
718 | return 0; | 695 | return 0; |
719 | } | 696 | } |