--- /dev/null
+/*
+ * Driver for the IMAGEON-FMC board
+ *
+ * Copyright 2012-2013 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * based on cobalt-driver.c
+ *
+ * Licensed under the GPL-2.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of_i2c.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+#include <linux/v4l2-dv-timings.h>
+
+#include <media/adv7604.h>
+#include <media/v4l2-event.h>
+
+#include "imageon-rx-driver.h"
+
+MODULE_LICENSE("Dual BSD/GPL");
+
+/* EDID for ADV7611 HDMI receiver */
+#define EDID_SIZE 256
+static u8 edid_data[EDID_SIZE] = {
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x06, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x16, 0x01, 0x03, 0x81, 0x46, 0x27, 0x78,
+ 0x0A, 0x32, 0x30, 0xA1, 0x54, 0x52, 0x9E, 0x26,
+ 0x0A, 0x49, 0x4B, 0xA3, 0x08, 0x00, 0x81, 0xC0,
+ 0x81, 0x00, 0x81, 0x0F, 0x81, 0x40, 0x81, 0x80,
+ 0x95, 0x00, 0xB3, 0x00, 0x01, 0x01, 0x02, 0x3A,
+ 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C,
+ 0x45, 0x00, 0xC4, 0x8E, 0x21, 0x00, 0x00, 0x1E,
+ 0xA9, 0x1A, 0x00, 0xA0, 0x50, 0x00, 0x16, 0x30,
+ 0x30, 0x20, 0x37, 0x00, 0xC4, 0x8E, 0x21, 0x00,
+ 0x00, 0x1A, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x46,
+ 0x4D, 0x43, 0x2D, 0x49, 0x4D, 0x41, 0x47, 0x45,
+ 0x4F, 0x4E, 0x0A, 0x20, 0x00, 0x00, 0x00, 0xFD,
+ 0x00, 0x38, 0x4B, 0x20, 0x44, 0x11, 0x00, 0x0A,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x54,
+ 0x02, 0x03, 0x1F, 0x71, 0x4B, 0x90, 0x03, 0x04,
+ 0x05, 0x12, 0x13, 0x14, 0x1F, 0x20, 0x07, 0x16,
+ 0x26, 0x15, 0x07, 0x50, 0x09, 0x07, 0x01, 0x67,
+ 0x03, 0x0C, 0x00, 0x10, 0x00, 0x00, 0x1E, 0x01,
+ 0x1D, 0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20, 0x6E,
+ 0x28, 0x55, 0x00, 0xC4, 0x8E, 0x21, 0x00, 0x00,
+ 0x1E, 0x01, 0x1D, 0x80, 0x18, 0x71, 0x1C, 0x16,
+ 0x20, 0x58, 0x2C, 0x25, 0x00, 0xC4, 0x8E, 0x21,
+ 0x00, 0x00, 0x9E, 0x8C, 0x0A, 0xD0, 0x8A, 0x20,
+ 0xE0, 0x2D, 0x10, 0x10, 0x3E, 0x96, 0x00, 0xC4,
+ 0x8E, 0x21, 0x00, 0x00, 0x18, 0x01, 0x1D, 0x80,
+ 0x3E, 0x73, 0x38, 0x2D, 0x40, 0x7E, 0x2C, 0x45,
+ 0x80, 0xC4, 0x8E, 0x21, 0x00, 0x00, 0x1E, 0x1A,
+ 0x36, 0x80, 0xA0, 0x70, 0x38, 0x1F, 0x40, 0x30,
+ 0x20, 0x25, 0x00, 0xC4, 0x8E, 0x21, 0x00, 0x00,
+ 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
+};
+
+static void imageon_rx_notify(struct v4l2_subdev *sd, unsigned int notification,
+ void *arg)
+{
+ /* pr_err("%s\n",__func__); */
+
+ struct imageon_rx *imageon_rx = to_imageon_rx(sd->v4l2_dev);
+ long hotplug = (long)arg;
+
+ switch (notification) {
+ case ADV7604_HOTPLUG:
+ gpio_set_value_cansleep(imageon_rx->hotplug_gpio, hotplug);
+ break;
+ default:
+ break;
+ }
+}
+
+static int imageon_rx_subdevs_init(struct imageon_rx *imageon_rx)
+{
+ static struct adv7604_platform_data adv7611_pdata = {
+ .disable_pwrdnb = 1,
+ .op_ch_sel = ADV7604_OP_CH_SEL_RGB,
+ .blank_data = 1,
+ .op_656_range = 1,
+ .rgb_out = 0,
+ .alt_data_sat = 1,
+ .op_format_sel = ADV7604_OP_FORMAT_SEL_SDR_ITU656_16,
+ .int1_config = ADV7604_INT1_CONFIG_OPEN_DRAIN,
+ .connector_hdmi = 1,
+ .insert_av_codes = 1,
+ .i2c_cec = 0x40,
+ .i2c_infoframe = 0x3e,
+ .i2c_afe = 0x26,
+ .i2c_repeater = 0x32,
+ .i2c_edid = 0x36,
+ .i2c_hdmi = 0x34,
+ .i2c_cp = 0x22,
+ };
+ static struct i2c_board_info adv7611_info = {
+ .type = "adv7611",
+ .addr = 0x4c,
+ .platform_data = &adv7611_pdata,
+ };
+ struct v4l2_subdev_edid edid = {
+ .pad = 0,
+ .start_block = 0,
+ .blocks = 2,
+ .edid = imageon_rx->edid_data,
+ };
+
+ struct imageon_rx_stream *s = &imageon_rx->stream;
+
+ s->sd_adv7611 = v4l2_i2c_new_subdev_board(&imageon_rx->v4l2_dev,
+ s->i2c_adap, &adv7611_info, NULL);
+ if (!s->sd_adv7611)
+ return -ENODEV;
+
+ v4l2_subdev_call(s->sd_adv7611, pad, set_edid, &edid);
+ return v4l2_subdev_call(s->sd_adv7611, video,
+ s_routing, ADV7604_MODE_HDMI, 0, 0);
+}
+
+static int imageon_rx_load_edid(struct platform_device *pdev,
+ struct imageon_rx *imageon_rx)
+{
+ const struct firmware *fw;
+ int ret;
+
+ ret = request_firmware(&fw, "adv7611_edid.bin", &pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to load firmware: %d\n", ret);
+ /*Using default EDID setting in case of failure */
+ dev_err(&pdev->dev, "Loading default EDID setting\n");
+ /*Copy EDID data */
+ memcpy(imageon_rx->edid_data, edid_data, EDID_SIZE);
+ } else {
+
+ if (fw->size > 256) {
+ dev_err(&pdev->dev, "EDID firmware data too large.\n");
+ release_firmware(fw);
+ return -EINVAL;
+ }
+
+ memcpy(imageon_rx->edid_data, fw->data, fw->size);
+
+ release_firmware(fw);
+ }
+
+ return 0;
+}
+
+static int imageon_rx_probe(struct platform_device *pdev)
+{
+ struct device_node *of_node;
+ struct i2c_adapter *adap;
+ struct imageon_rx *imageon_rx;
+ int ret;
+
+ of_node = of_parse_phandle(pdev->dev.of_node, "slave_adapter", 0);
+ if (!of_node)
+ return -ENXIO;
+
+ adap = of_find_i2c_adapter_by_node(of_node);
+ of_node_put(of_node);
+ if (!adap)
+ return -EPROBE_DEFER;
+
+ imageon_rx =
+ devm_kzalloc(&pdev->dev, sizeof(struct imageon_rx), GFP_KERNEL);
+ if (imageon_rx == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate device\n");
+ ret = -ENOMEM;
+ goto err_i2c_put_adapter;
+ }
+
+ imageon_rx->hotplug_gpio =
+ of_get_named_gpio(pdev->dev.of_node, "hpd-gpio", 0);
+ if (!gpio_is_valid(imageon_rx->hotplug_gpio))
+ return imageon_rx->hotplug_gpio;
+
+
+ ret = devm_gpio_request_one(&pdev->dev,
+ imageon_rx->hotplug_gpio, GPIOF_OUT_INIT_LOW, "HPD");
+ if (ret < 0)
+ return ret;
+ imageon_rx->stream.i2c_adap = adap;
+
+
+ ret = imageon_rx_load_edid(pdev, imageon_rx);
+ if (ret)
+ goto err_i2c_put_adapter;
+
+ ret = v4l2_device_register(&pdev->dev, &imageon_rx->v4l2_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register card: %d\n", ret);
+ goto err_device_unregister;
+ }
+ snprintf(imageon_rx->v4l2_dev.name, sizeof(imageon_rx->v4l2_dev.name),
+ "imageon_rx");
+
+ imageon_rx->v4l2_dev.notify = imageon_rx_notify;
+
+ ret = imageon_rx_subdevs_init(imageon_rx);
+ if (ret)
+ goto err_device_unregister;
+
+ ret = v4l2_device_register_subdev_nodes(&imageon_rx->v4l2_dev);
+ if (ret)
+ goto err_device_unregister;
+
+ video_set_drvdata(&imageon_rx->stream.vdev, imageon_rx);
+
+ return 0;
+
+err_device_unregister:
+ v4l2_device_unregister(&imageon_rx->v4l2_dev);
+err_i2c_put_adapter:
+ i2c_put_adapter(adap);
+ return ret;
+}
+
+static int imageon_rx_remove(struct platform_device *pdev)
+{
+ struct imageon_rx *imageon_rx = platform_get_drvdata(pdev);
+
+ v4l2_device_unregister(&imageon_rx->v4l2_dev);
+ i2c_put_adapter(imageon_rx->stream.i2c_adap);
+
+ return 0;
+}
+
+static const struct of_device_id imageon_rx_of_match[] = {
+ { .compatible = "xlnx,imageon-rx", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, imageon_rx_of_match);
+
+static struct platform_driver imageon_rx_driver = {
+ .driver = {
+ .name = "imageon-rx",
+ .owner = THIS_MODULE,
+ .of_match_table = imageon_rx_of_match,
+ },
+ .probe = imageon_rx_probe,
+ .remove = imageon_rx_remove,
+};
+module_platform_driver(imageon_rx_driver);
--- /dev/null
+/*
+ * imageon_rx driver internal defines and structures
+ *
+ * Derived from cx18-driver.h
+ *
+ * Copyright 2011 Tandberg Telecom AS. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef IMAGEON_RX_DRIVER_H
+#define IMAGEON_RX_DRIVER_H
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/amba/xilinx_dma.h>
+#include <linux/debugfs.h>
+
+#include <linux/i2c.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-dma-sg.h>
+
+struct imageon_rx_stream {
+ struct video_device vdev;
+ struct media_pad pad;
+ struct vb2_queue q;
+ struct i2c_adapter *i2c_adap;
+ struct v4l2_subdev *sd_adv7611;
+ struct mutex lock;
+ spinlock_t spinlock;
+ u32 input;
+ u32 width, height, bpp, pack_fmt;
+ u32 stride;
+
+ struct dma_chan *chan;
+ struct xilinx_vdma_config dma_config;
+
+ struct list_head queued_buffers;
+};
+
+/* Struct to hold info about imageon_rx cards */
+struct imageon_rx {
+ struct v4l2_device v4l2_dev;
+ struct vb2_alloc_ctx *alloc_ctx;
+
+ /* device nodes */
+ struct media_device mdev;
+ struct imageon_rx_stream stream;
+
+ int hotplug_gpio;
+
+ void __iomem *base;
+
+ u8 edid_data[256];
+};
+
+static inline struct imageon_rx *to_imageon_rx(struct v4l2_device *v4l2_dev)
+{
+ return container_of(v4l2_dev, struct imageon_rx, v4l2_dev);
+}
+
+static inline struct imageon_rx_stream
+ *imageon_rx_file_to_stream(struct file *file)
+{
+ struct imageon_rx *imageon_rx = video_drvdata(file);
+ return &imageon_rx->stream;
+}
+
+static inline struct imageon_rx *imageon_rx_stream_to_imageon_rx(
+ struct imageon_rx_stream *s)
+{
+ return container_of(s, struct imageon_rx, stream);
+}
+
+int imageon_rx_nodes_register(struct imageon_rx *imageon_rx);
+
+#define IMAGEON_RX_BYTES_PER_PIXEL_YUYV 4
+#define IMAGEON_RX_BYTES_PER_PIXEL_RGB32 4
+
+enum {
+ IMAGEON_RX_VID_PACK_FMT_RGB32,
+/*
+ IMAGEON_RX_VID_PACK_FMT_YUYV,*/
+};
+
+#endif