aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSylwester Nawrocki <s.nawrocki@samsung.com>2013-03-26 07:20:30 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-03-31 09:42:58 -0400
commit02399e35e6bb716ce9636eba006b792362270034 (patch)
tree24ec7af43a7ee0c310bf6dd64457396875f7d268
parentee12b049104118a58ac13da207a84c867191b17a (diff)
[media] s5p-csis: Add device tree support
This patch support for binding the driver to the MIPI-CSIS devices instantiated from device tree and parsing the SoC and board specific properties. The MIPI CSI-2 channel is determined by the value of reg property placed in csis' port subnode. Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--Documentation/devicetree/bindings/media/samsung-mipi-csis.txt81
-rw-r--r--drivers/media/platform/s5p-fimc/mipi-csis.c155
-rw-r--r--drivers/media/platform/s5p-fimc/mipi-csis.h1
-rw-r--r--include/media/s5p_fimc.h13
4 files changed, 215 insertions, 35 deletions
diff --git a/Documentation/devicetree/bindings/media/samsung-mipi-csis.txt b/Documentation/devicetree/bindings/media/samsung-mipi-csis.txt
new file mode 100644
index 000000000000..5f8e28e2484f
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/samsung-mipi-csis.txt
@@ -0,0 +1,81 @@
1Samsung S5P/EXYNOS SoC series MIPI CSI-2 receiver (MIPI CSIS)
2-------------------------------------------------------------
3
4Required properties:
5
6- compatible : "samsung,s5pv210-csis" for S5PV210 (S5PC110),
7 "samsung,exynos4210-csis" for Exynos4210 (S5PC210),
8 "samsung,exynos4212-csis" for Exynos4212/Exynos4412
9 SoC series;
10- reg : offset and length of the register set for the device;
11- interrupts : should contain MIPI CSIS interrupt; the format of the
12 interrupt specifier depends on the interrupt controller;
13- bus-width : maximum number of data lanes supported (SoC specific);
14- vddio-supply : MIPI CSIS I/O and PLL voltage supply (e.g. 1.8V);
15- vddcore-supply : MIPI CSIS Core voltage supply (e.g. 1.1V);
16- clocks : list of clock specifiers, corresponding to entries in
17 clock-names property;
18- clock-names : must contain "csis", "sclk_csis" entries, matching entries
19 in the clocks property.
20
21Optional properties:
22
23- clock-frequency : The IP's main (system bus) clock frequency in Hz, default
24 value when this property is not specified is 166 MHz;
25- samsung,csis-wclk : CSI-2 wrapper clock selection. If this property is present
26 external clock from CMU will be used, or the bus clock if
27 if it's not specified.
28
29The device node should contain one 'port' child node with one child 'endpoint'
30node, according to the bindings defined in Documentation/devicetree/bindings/
31media/video-interfaces.txt. The following are properties specific to those nodes.
32
33port node
34---------
35
36- reg : (required) must be 3 for camera C input (CSIS0) or 4 for
37 camera D input (CSIS1);
38
39endpoint node
40-------------
41
42- data-lanes : (required) an array specifying active physical MIPI-CSI2
43 data input lanes and their mapping to logical lanes; the
44 array's content is unused, only its length is meaningful;
45
46- samsung,csis-hs-settle : (optional) differential receiver (HS-RX) settle time;
47
48
49Example:
50
51 reg0: regulator@0 {
52 };
53
54 reg1: regulator@1 {
55 };
56
57/* SoC properties */
58
59 csis_0: csis@11880000 {
60 compatible = "samsung,exynos4210-csis";
61 reg = <0x11880000 0x1000>;
62 interrupts = <0 78 0>;
63 #address-cells = <1>;
64 #size-cells = <0>;
65 };
66
67/* Board properties */
68
69 csis_0: csis@11880000 {
70 clock-frequency = <166000000>;
71 vddio-supply = <&reg0>;
72 vddcore-supply = <&reg1>;
73 port {
74 reg = <3>; /* 3 - CSIS0, 4 - CSIS1 */
75 csis0_ep: endpoint {
76 remote-endpoint = <...>;
77 data-lanes = <1>, <2>;
78 samsung,csis-hs-settle = <12>;
79 };
80 };
81 };
diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c
index 981863d05aaa..8636bcddde1b 100644
--- a/drivers/media/platform/s5p-fimc/mipi-csis.c
+++ b/drivers/media/platform/s5p-fimc/mipi-csis.c
@@ -19,14 +19,18 @@
19#include <linux/kernel.h> 19#include <linux/kernel.h>
20#include <linux/memory.h> 20#include <linux/memory.h>
21#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/of.h>
23#include <linux/platform_data/mipi-csis.h>
22#include <linux/platform_device.h> 24#include <linux/platform_device.h>
23#include <linux/pm_runtime.h> 25#include <linux/pm_runtime.h>
24#include <linux/regulator/consumer.h> 26#include <linux/regulator/consumer.h>
25#include <linux/slab.h> 27#include <linux/slab.h>
26#include <linux/spinlock.h> 28#include <linux/spinlock.h>
27#include <linux/videodev2.h> 29#include <linux/videodev2.h>
30#include <media/s5p_fimc.h>
31#include <media/v4l2-of.h>
28#include <media/v4l2-subdev.h> 32#include <media/v4l2-subdev.h>
29#include <linux/platform_data/mipi-csis.h> 33
30#include "mipi-csis.h" 34#include "mipi-csis.h"
31 35
32static int debug; 36static int debug;
@@ -113,6 +117,7 @@ static char *csi_clock_name[] = {
113 [CSIS_CLK_GATE] = "csis", 117 [CSIS_CLK_GATE] = "csis",
114}; 118};
115#define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name) 119#define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name)
120#define DEFAULT_SCLK_CSIS_FREQ 166000000UL
116 121
117static const char * const csis_supply_name[] = { 122static const char * const csis_supply_name[] = {
118 "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) suppply */ 123 "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) suppply */
@@ -167,6 +172,11 @@ struct csis_pktbuf {
167 * @clock: CSIS clocks 172 * @clock: CSIS clocks
168 * @irq: requested s5p-mipi-csis irq number 173 * @irq: requested s5p-mipi-csis irq number
169 * @flags: the state variable for power and streaming control 174 * @flags: the state variable for power and streaming control
175 * @clock_frequency: device bus clock frequency
176 * @hs_settle: HS-RX settle time
177 * @num_lanes: number of MIPI-CSI data lanes used
178 * @max_num_lanes: maximum number of MIPI-CSI data lanes supported
179 * @wclk_ext: CSI wrapper clock: 0 - bus clock, 1 - external SCLK_CAM
170 * @csis_fmt: current CSIS pixel format 180 * @csis_fmt: current CSIS pixel format
171 * @format: common media bus format for the source and sink pad 181 * @format: common media bus format for the source and sink pad
172 * @slock: spinlock protecting structure members below 182 * @slock: spinlock protecting structure members below
@@ -184,6 +194,13 @@ struct csis_state {
184 struct clk *clock[NUM_CSIS_CLOCKS]; 194 struct clk *clock[NUM_CSIS_CLOCKS];
185 int irq; 195 int irq;
186 u32 flags; 196 u32 flags;
197
198 u32 clk_frequency;
199 u32 hs_settle;
200 u32 num_lanes;
201 u32 max_num_lanes;
202 u8 wclk_ext;
203
187 const struct csis_pix_format *csis_fmt; 204 const struct csis_pix_format *csis_fmt;
188 struct v4l2_mbus_framefmt format; 205 struct v4l2_mbus_framefmt format;
189 206
@@ -273,7 +290,6 @@ static void s5pcsis_reset(struct csis_state *state)
273 290
274static void s5pcsis_system_enable(struct csis_state *state, int on) 291static void s5pcsis_system_enable(struct csis_state *state, int on)
275{ 292{
276 struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data;
277 u32 val, mask; 293 u32 val, mask;
278 294
279 val = s5pcsis_read(state, S5PCSIS_CTRL); 295 val = s5pcsis_read(state, S5PCSIS_CTRL);
@@ -286,7 +302,7 @@ static void s5pcsis_system_enable(struct csis_state *state, int on)
286 val = s5pcsis_read(state, S5PCSIS_DPHYCTRL); 302 val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
287 val &= ~S5PCSIS_DPHYCTRL_ENABLE; 303 val &= ~S5PCSIS_DPHYCTRL_ENABLE;
288 if (on) { 304 if (on) {
289 mask = (1 << (pdata->lanes + 1)) - 1; 305 mask = (1 << (state->num_lanes + 1)) - 1;
290 val |= (mask & S5PCSIS_DPHYCTRL_ENABLE); 306 val |= (mask & S5PCSIS_DPHYCTRL_ENABLE);
291 } 307 }
292 s5pcsis_write(state, S5PCSIS_DPHYCTRL, val); 308 s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
@@ -321,15 +337,14 @@ static void s5pcsis_set_hsync_settle(struct csis_state *state, int settle)
321 337
322static void s5pcsis_set_params(struct csis_state *state) 338static void s5pcsis_set_params(struct csis_state *state)
323{ 339{
324 struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data;
325 u32 val; 340 u32 val;
326 341
327 val = s5pcsis_read(state, S5PCSIS_CONFIG); 342 val = s5pcsis_read(state, S5PCSIS_CONFIG);
328 val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (pdata->lanes - 1); 343 val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (state->num_lanes - 1);
329 s5pcsis_write(state, S5PCSIS_CONFIG, val); 344 s5pcsis_write(state, S5PCSIS_CONFIG, val);
330 345
331 __s5pcsis_set_format(state); 346 __s5pcsis_set_format(state);
332 s5pcsis_set_hsync_settle(state, pdata->hs_settle); 347 s5pcsis_set_hsync_settle(state, state->hs_settle);
333 348
334 val = s5pcsis_read(state, S5PCSIS_CTRL); 349 val = s5pcsis_read(state, S5PCSIS_CTRL);
335 if (state->csis_fmt->data_alignment == 32) 350 if (state->csis_fmt->data_alignment == 32)
@@ -338,7 +353,7 @@ static void s5pcsis_set_params(struct csis_state *state)
338 val &= ~S5PCSIS_CTRL_ALIGN_32BIT; 353 val &= ~S5PCSIS_CTRL_ALIGN_32BIT;
339 354
340 val &= ~S5PCSIS_CTRL_WCLK_EXTCLK; 355 val &= ~S5PCSIS_CTRL_WCLK_EXTCLK;
341 if (pdata->wclk_source) 356 if (state->wclk_ext)
342 val |= S5PCSIS_CTRL_WCLK_EXTCLK; 357 val |= S5PCSIS_CTRL_WCLK_EXTCLK;
343 s5pcsis_write(state, S5PCSIS_CTRL, val); 358 s5pcsis_write(state, S5PCSIS_CTRL, val);
344 359
@@ -701,52 +716,111 @@ static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id)
701 return IRQ_HANDLED; 716 return IRQ_HANDLED;
702} 717}
703 718
719static int s5pcsis_get_platform_data(struct platform_device *pdev,
720 struct csis_state *state)
721{
722 struct s5p_platform_mipi_csis *pdata = pdev->dev.platform_data;
723
724 if (pdata == NULL) {
725 dev_err(&pdev->dev, "Platform data not specified\n");
726 return -EINVAL;
727 }
728
729 state->clk_frequency = pdata->clk_rate;
730 state->num_lanes = pdata->lanes;
731 state->hs_settle = pdata->hs_settle;
732 state->index = max(0, pdev->id);
733 state->max_num_lanes = state->index ? CSIS1_MAX_LANES :
734 CSIS0_MAX_LANES;
735 return 0;
736}
737
738#ifdef CONFIG_OF
739static int s5pcsis_parse_dt(struct platform_device *pdev,
740 struct csis_state *state)
741{
742 struct device_node *node = pdev->dev.of_node;
743 struct v4l2_of_endpoint endpoint;
744
745 if (of_property_read_u32(node, "clock-frequency",
746 &state->clk_frequency))
747 state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ;
748 if (of_property_read_u32(node, "bus-width",
749 &state->max_num_lanes))
750 return -EINVAL;
751
752 node = v4l2_of_get_next_endpoint(node, NULL);
753 if (!node) {
754 dev_err(&pdev->dev, "No port node at %s\n",
755 node->full_name);
756 return -EINVAL;
757 }
758 /* Get port node and validate MIPI-CSI channel id. */
759 v4l2_of_parse_endpoint(node, &endpoint);
760
761 state->index = endpoint.port - FIMC_INPUT_MIPI_CSI2_0;
762 if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES)
763 return -ENXIO;
764
765 /* Get MIPI CSI-2 bus configration from the endpoint node. */
766 of_property_read_u32(node, "samsung,csis-hs-settle",
767 &state->hs_settle);
768 state->wclk_ext = of_property_read_bool(node,
769 "samsung,csis-wclk");
770
771 state->num_lanes = endpoint.bus.mipi_csi2.num_data_lanes;
772
773 of_node_put(node);
774 return 0;
775}
776#else
777#define s5pcsis_parse_dt(pdev, state) (-ENOSYS)
778#endif
779
704static int s5pcsis_probe(struct platform_device *pdev) 780static int s5pcsis_probe(struct platform_device *pdev)
705{ 781{
706 struct s5p_platform_mipi_csis *pdata; 782 struct device *dev = &pdev->dev;
707 struct resource *mem_res; 783 struct resource *mem_res;
708 struct csis_state *state; 784 struct csis_state *state;
709 int ret = -ENOMEM; 785 int ret = -ENOMEM;
710 int i; 786 int i;
711 787
712 state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL); 788 state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
713 if (!state) 789 if (!state)
714 return -ENOMEM; 790 return -ENOMEM;
715 791
716 mutex_init(&state->lock); 792 mutex_init(&state->lock);
717 spin_lock_init(&state->slock); 793 spin_lock_init(&state->slock);
718
719 state->pdev = pdev; 794 state->pdev = pdev;
720 state->index = max(0, pdev->id);
721 795
722 pdata = pdev->dev.platform_data; 796 if (dev->of_node)
723 if (pdata == NULL) { 797 ret = s5pcsis_parse_dt(pdev, state);
724 dev_err(&pdev->dev, "Platform data not fully specified\n"); 798 else
725 return -EINVAL; 799 ret = s5pcsis_get_platform_data(pdev, state);
726 } 800 if (ret < 0)
801 return ret;
727 802
728 if ((state->index == 1 && pdata->lanes > CSIS1_MAX_LANES) || 803 if (state->num_lanes == 0 || state->num_lanes > state->max_num_lanes) {
729 pdata->lanes > CSIS0_MAX_LANES) { 804 dev_err(dev, "Unsupported number of data lanes: %d (max. %d)\n",
730 dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n", 805 state->num_lanes, state->max_num_lanes);
731 pdata->lanes);
732 return -EINVAL; 806 return -EINVAL;
733 } 807 }
734 808
735 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 809 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
736 state->regs = devm_ioremap_resource(&pdev->dev, mem_res); 810 state->regs = devm_ioremap_resource(dev, mem_res);
737 if (IS_ERR(state->regs)) 811 if (IS_ERR(state->regs))
738 return PTR_ERR(state->regs); 812 return PTR_ERR(state->regs);
739 813
740 state->irq = platform_get_irq(pdev, 0); 814 state->irq = platform_get_irq(pdev, 0);
741 if (state->irq < 0) { 815 if (state->irq < 0) {
742 dev_err(&pdev->dev, "Failed to get irq\n"); 816 dev_err(dev, "Failed to get irq\n");
743 return state->irq; 817 return state->irq;
744 } 818 }
745 819
746 for (i = 0; i < CSIS_NUM_SUPPLIES; i++) 820 for (i = 0; i < CSIS_NUM_SUPPLIES; i++)
747 state->supplies[i].supply = csis_supply_name[i]; 821 state->supplies[i].supply = csis_supply_name[i];
748 822
749 ret = devm_regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES, 823 ret = devm_regulator_bulk_get(dev, CSIS_NUM_SUPPLIES,
750 state->supplies); 824 state->supplies);
751 if (ret) 825 if (ret)
752 return ret; 826 return ret;
@@ -755,11 +829,11 @@ static int s5pcsis_probe(struct platform_device *pdev)
755 if (ret < 0) 829 if (ret < 0)
756 return ret; 830 return ret;
757 831
758 if (pdata->clk_rate) 832 if (state->clk_frequency)
759 ret = clk_set_rate(state->clock[CSIS_CLK_MUX], 833 ret = clk_set_rate(state->clock[CSIS_CLK_MUX],
760 pdata->clk_rate); 834 state->clk_frequency);
761 else 835 else
762 dev_WARN(&pdev->dev, "No clock frequency specified!\n"); 836 dev_WARN(dev, "No clock frequency specified!\n");
763 if (ret < 0) 837 if (ret < 0)
764 goto e_clkput; 838 goto e_clkput;
765 839
@@ -767,16 +841,17 @@ static int s5pcsis_probe(struct platform_device *pdev)
767 if (ret < 0) 841 if (ret < 0)
768 goto e_clkput; 842 goto e_clkput;
769 843
770 ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler, 844 ret = devm_request_irq(dev, state->irq, s5pcsis_irq_handler,
771 0, dev_name(&pdev->dev), state); 845 0, dev_name(dev), state);
772 if (ret) { 846 if (ret) {
773 dev_err(&pdev->dev, "Interrupt request failed\n"); 847 dev_err(dev, "Interrupt request failed\n");
774 goto e_clkdis; 848 goto e_clkdis;
775 } 849 }
776 850
777 v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops); 851 v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops);
778 state->sd.owner = THIS_MODULE; 852 state->sd.owner = THIS_MODULE;
779 strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name)); 853 snprintf(state->sd.name, sizeof(state->sd.name), "%s.%d",
854 CSIS_SUBDEV_NAME, state->index);
780 state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 855 state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
781 state->csis_fmt = &s5pcsis_formats[0]; 856 state->csis_fmt = &s5pcsis_formats[0];
782 857
@@ -796,10 +871,12 @@ static int s5pcsis_probe(struct platform_device *pdev)
796 871
797 /* .. and a pointer to the subdev. */ 872 /* .. and a pointer to the subdev. */
798 platform_set_drvdata(pdev, &state->sd); 873 platform_set_drvdata(pdev, &state->sd);
799
800 memcpy(state->events, s5pcsis_events, sizeof(state->events)); 874 memcpy(state->events, s5pcsis_events, sizeof(state->events));
875 pm_runtime_enable(dev);
801 876
802 pm_runtime_enable(&pdev->dev); 877 dev_info(&pdev->dev, "lanes: %d, hs_settle: %d, wclk: %d, freq: %u\n",
878 state->num_lanes, state->hs_settle, state->wclk_ext,
879 state->clk_frequency);
803 return 0; 880 return 0;
804 881
805e_clkdis: 882e_clkdis:
@@ -923,13 +1000,21 @@ static const struct dev_pm_ops s5pcsis_pm_ops = {
923 SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_suspend, s5pcsis_resume) 1000 SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_suspend, s5pcsis_resume)
924}; 1001};
925 1002
1003static const struct of_device_id s5pcsis_of_match[] = {
1004 { .compatible = "samsung,s5pv210-csis" },
1005 { .compatible = "samsung,exynos4210-csis" },
1006 { /* sentinel */ },
1007};
1008MODULE_DEVICE_TABLE(of, s5pcsis_of_match);
1009
926static struct platform_driver s5pcsis_driver = { 1010static struct platform_driver s5pcsis_driver = {
927 .probe = s5pcsis_probe, 1011 .probe = s5pcsis_probe,
928 .remove = s5pcsis_remove, 1012 .remove = s5pcsis_remove,
929 .driver = { 1013 .driver = {
930 .name = CSIS_DRIVER_NAME, 1014 .of_match_table = s5pcsis_of_match,
931 .owner = THIS_MODULE, 1015 .name = CSIS_DRIVER_NAME,
932 .pm = &s5pcsis_pm_ops, 1016 .owner = THIS_MODULE,
1017 .pm = &s5pcsis_pm_ops,
933 }, 1018 },
934}; 1019};
935 1020
diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.h b/drivers/media/platform/s5p-fimc/mipi-csis.h
index 2709286396e1..28c11c4085d8 100644
--- a/drivers/media/platform/s5p-fimc/mipi-csis.h
+++ b/drivers/media/platform/s5p-fimc/mipi-csis.h
@@ -11,6 +11,7 @@
11#define S5P_MIPI_CSIS_H_ 11#define S5P_MIPI_CSIS_H_
12 12
13#define CSIS_DRIVER_NAME "s5p-mipi-csis" 13#define CSIS_DRIVER_NAME "s5p-mipi-csis"
14#define CSIS_SUBDEV_NAME CSIS_DRIVER_NAME
14#define CSIS_MAX_ENTITIES 2 15#define CSIS_MAX_ENTITIES 2
15#define CSIS0_MAX_LANES 4 16#define CSIS0_MAX_LANES 4
16#define CSIS1_MAX_LANES 2 17#define CSIS1_MAX_LANES 2
diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h
index 28f3590aa031..d6dbb791f423 100644
--- a/include/media/s5p_fimc.h
+++ b/include/media/s5p_fimc.h
@@ -15,6 +15,19 @@
15#include <media/media-entity.h> 15#include <media/media-entity.h>
16 16
17/* 17/*
18 * Enumeration of data inputs to the camera subsystem.
19 */
20enum fimc_input {
21 FIMC_INPUT_PARALLEL_0 = 1,
22 FIMC_INPUT_PARALLEL_1,
23 FIMC_INPUT_MIPI_CSI2_0 = 3,
24 FIMC_INPUT_MIPI_CSI2_1,
25 FIMC_INPUT_WRITEBACK_A = 5,
26 FIMC_INPUT_WRITEBACK_B,
27 FIMC_INPUT_WRITEBACK_ISP = 5,
28};
29
30/*
18 * Enumeration of the FIMC data bus types. 31 * Enumeration of the FIMC data bus types.
19 */ 32 */
20enum fimc_bus_type { 33enum fimc_bus_type {