diff options
| -rw-r--r-- | Documentation/devicetree/bindings/media/atmel-isi.txt | 51 | ||||
| -rw-r--r-- | drivers/media/platform/soc_camera/atmel-isi.c | 65 |
2 files changed, 114 insertions, 2 deletions
diff --git a/Documentation/devicetree/bindings/media/atmel-isi.txt b/Documentation/devicetree/bindings/media/atmel-isi.txt new file mode 100644 index 000000000000..17e71b7b44c6 --- /dev/null +++ b/Documentation/devicetree/bindings/media/atmel-isi.txt | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | Atmel Image Sensor Interface (ISI) SoC Camera Subsystem | ||
| 2 | ---------------------------------------------- | ||
| 3 | |||
| 4 | Required properties: | ||
| 5 | - compatible: must be "atmel,at91sam9g45-isi" | ||
| 6 | - reg: physical base address and length of the registers set for the device; | ||
| 7 | - interrupts: should contain IRQ line for the ISI; | ||
| 8 | - clocks: list of clock specifiers, corresponding to entries in | ||
| 9 | the clock-names property; | ||
| 10 | - clock-names: must contain "isi_clk", which is the isi peripherial clock. | ||
| 11 | |||
| 12 | ISI supports a single port node with parallel bus. It should contain one | ||
| 13 | 'port' child node with child 'endpoint' node. Please refer to the bindings | ||
| 14 | defined in Documentation/devicetree/bindings/media/video-interfaces.txt. | ||
| 15 | |||
| 16 | Example: | ||
| 17 | isi: isi@f0034000 { | ||
| 18 | compatible = "atmel,at91sam9g45-isi"; | ||
| 19 | reg = <0xf0034000 0x4000>; | ||
| 20 | interrupts = <37 IRQ_TYPE_LEVEL_HIGH 5>; | ||
| 21 | |||
| 22 | clocks = <&isi_clk>; | ||
| 23 | clock-names = "isi_clk"; | ||
| 24 | |||
| 25 | pinctrl-names = "default"; | ||
| 26 | pinctrl-0 = <&pinctrl_isi>; | ||
| 27 | |||
| 28 | port { | ||
| 29 | #address-cells = <1>; | ||
| 30 | #size-cells = <0>; | ||
| 31 | |||
| 32 | isi_0: endpoint { | ||
| 33 | remote-endpoint = <&ov2640_0>; | ||
| 34 | bus-width = <8>; | ||
| 35 | }; | ||
| 36 | }; | ||
| 37 | }; | ||
| 38 | |||
| 39 | i2c1: i2c@f0018000 { | ||
| 40 | ov2640: camera@0x30 { | ||
| 41 | compatible = "omnivision,ov2640"; | ||
| 42 | reg = <0x30>; | ||
| 43 | |||
| 44 | port { | ||
| 45 | ov2640_0: endpoint { | ||
| 46 | remote-endpoint = <&isi_0>; | ||
| 47 | bus-width = <8>; | ||
| 48 | }; | ||
| 49 | }; | ||
| 50 | }; | ||
| 51 | }; | ||
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index d32c53383565..3408b045b3f1 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <media/atmel-isi.h> | 25 | #include <media/atmel-isi.h> |
| 26 | #include <media/soc_camera.h> | 26 | #include <media/soc_camera.h> |
| 27 | #include <media/soc_mediabus.h> | 27 | #include <media/soc_mediabus.h> |
| 28 | #include <media/v4l2-of.h> | ||
| 28 | #include <media/videobuf2-dma-contig.h> | 29 | #include <media/videobuf2-dma-contig.h> |
| 29 | 30 | ||
| 30 | #define MAX_BUFFER_NUM 32 | 31 | #define MAX_BUFFER_NUM 32 |
| @@ -33,6 +34,7 @@ | |||
| 33 | #define VID_LIMIT_BYTES (16 * 1024 * 1024) | 34 | #define VID_LIMIT_BYTES (16 * 1024 * 1024) |
| 34 | #define MIN_FRAME_RATE 15 | 35 | #define MIN_FRAME_RATE 15 |
| 35 | #define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE) | 36 | #define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE) |
| 37 | #define ISI_DEFAULT_MCLK_FREQ 25000000 | ||
| 36 | 38 | ||
| 37 | /* Frame buffer descriptor */ | 39 | /* Frame buffer descriptor */ |
| 38 | struct fbd { | 40 | struct fbd { |
| @@ -876,6 +878,51 @@ static int atmel_isi_remove(struct platform_device *pdev) | |||
| 876 | return 0; | 878 | return 0; |
| 877 | } | 879 | } |
| 878 | 880 | ||
| 881 | static int atmel_isi_probe_dt(struct atmel_isi *isi, | ||
| 882 | struct platform_device *pdev) | ||
| 883 | { | ||
| 884 | struct device_node *np= pdev->dev.of_node; | ||
| 885 | struct v4l2_of_endpoint ep; | ||
| 886 | int err; | ||
| 887 | |||
| 888 | /* Default settings for ISI */ | ||
| 889 | isi->pdata.full_mode = 1; | ||
| 890 | isi->pdata.mck_hz = ISI_DEFAULT_MCLK_FREQ; | ||
| 891 | isi->pdata.frate = ISI_CFG1_FRATE_CAPTURE_ALL; | ||
| 892 | |||
| 893 | np = of_graph_get_next_endpoint(np, NULL); | ||
| 894 | if (!np) { | ||
| 895 | dev_err(&pdev->dev, "Could not find the endpoint\n"); | ||
| 896 | return -EINVAL; | ||
| 897 | } | ||
| 898 | |||
| 899 | err = v4l2_of_parse_endpoint(np, &ep); | ||
| 900 | if (err) { | ||
| 901 | dev_err(&pdev->dev, "Could not parse the endpoint\n"); | ||
| 902 | goto err_probe_dt; | ||
| 903 | } | ||
| 904 | |||
| 905 | switch (ep.bus.parallel.bus_width) { | ||
| 906 | case 8: | ||
| 907 | isi->pdata.data_width_flags = ISI_DATAWIDTH_8; | ||
| 908 | break; | ||
| 909 | case 10: | ||
| 910 | isi->pdata.data_width_flags = | ||
| 911 | ISI_DATAWIDTH_8 | ISI_DATAWIDTH_10; | ||
| 912 | break; | ||
| 913 | default: | ||
| 914 | dev_err(&pdev->dev, "Unsupported bus width: %d\n", | ||
| 915 | ep.bus.parallel.bus_width); | ||
| 916 | err = -EINVAL; | ||
| 917 | goto err_probe_dt; | ||
| 918 | } | ||
| 919 | |||
| 920 | err_probe_dt: | ||
| 921 | of_node_put(np); | ||
| 922 | |||
| 923 | return err; | ||
| 924 | } | ||
| 925 | |||
| 879 | static int atmel_isi_probe(struct platform_device *pdev) | 926 | static int atmel_isi_probe(struct platform_device *pdev) |
| 880 | { | 927 | { |
| 881 | unsigned int irq; | 928 | unsigned int irq; |
| @@ -887,7 +934,7 @@ static int atmel_isi_probe(struct platform_device *pdev) | |||
| 887 | struct isi_platform_data *pdata; | 934 | struct isi_platform_data *pdata; |
| 888 | 935 | ||
| 889 | pdata = dev->platform_data; | 936 | pdata = dev->platform_data; |
| 890 | if (!pdata || !pdata->data_width_flags) { | 937 | if ((!pdata || !pdata->data_width_flags) && !pdev->dev.of_node) { |
| 891 | dev_err(&pdev->dev, | 938 | dev_err(&pdev->dev, |
| 892 | "No config available for Atmel ISI\n"); | 939 | "No config available for Atmel ISI\n"); |
| 893 | return -EINVAL; | 940 | return -EINVAL; |
| @@ -903,7 +950,14 @@ static int atmel_isi_probe(struct platform_device *pdev) | |||
| 903 | if (IS_ERR(isi->pclk)) | 950 | if (IS_ERR(isi->pclk)) |
| 904 | return PTR_ERR(isi->pclk); | 951 | return PTR_ERR(isi->pclk); |
| 905 | 952 | ||
| 906 | memcpy(&isi->pdata, pdata, sizeof(isi->pdata)); | 953 | if (pdata) { |
| 954 | memcpy(&isi->pdata, pdata, sizeof(isi->pdata)); | ||
| 955 | } else { | ||
| 956 | ret = atmel_isi_probe_dt(isi, pdev); | ||
| 957 | if (ret) | ||
| 958 | return ret; | ||
| 959 | } | ||
| 960 | |||
| 907 | isi->active = NULL; | 961 | isi->active = NULL; |
| 908 | spin_lock_init(&isi->lock); | 962 | spin_lock_init(&isi->lock); |
| 909 | INIT_LIST_HEAD(&isi->video_buffer_list); | 963 | INIT_LIST_HEAD(&isi->video_buffer_list); |
| @@ -1005,11 +1059,18 @@ err_alloc_ctx: | |||
| 1005 | return ret; | 1059 | return ret; |
| 1006 | } | 1060 | } |
| 1007 | 1061 | ||
| 1062 | static const struct of_device_id atmel_isi_of_match[] = { | ||
| 1063 | { .compatible = "atmel,at91sam9g45-isi" }, | ||
| 1064 | { } | ||
| 1065 | }; | ||
| 1066 | MODULE_DEVICE_TABLE(of, atmel_isi_of_match); | ||
| 1067 | |||
| 1008 | static struct platform_driver atmel_isi_driver = { | 1068 | static struct platform_driver atmel_isi_driver = { |
| 1009 | .remove = atmel_isi_remove, | 1069 | .remove = atmel_isi_remove, |
| 1010 | .driver = { | 1070 | .driver = { |
| 1011 | .name = "atmel_isi", | 1071 | .name = "atmel_isi", |
| 1012 | .owner = THIS_MODULE, | 1072 | .owner = THIS_MODULE, |
| 1073 | .of_match_table = of_match_ptr(atmel_isi_of_match), | ||
| 1013 | }, | 1074 | }, |
| 1014 | }; | 1075 | }; |
| 1015 | 1076 | ||
