aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i2c/dummy_drm_i2c_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i2c/dummy_drm_i2c_drv.c')
-rw-r--r--drivers/gpu/drm/i2c/dummy_drm_i2c_drv.c454
1 files changed, 454 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i2c/dummy_drm_i2c_drv.c b/drivers/gpu/drm/i2c/dummy_drm_i2c_drv.c
new file mode 100644
index 000000000000..7817c802a6e3
--- /dev/null
+++ b/drivers/gpu/drm/i2c/dummy_drm_i2c_drv.c
@@ -0,0 +1,454 @@
+/*
+ * This file was originally based on tda998x_drv.c which has the following
+ * copyright and licence...
+ *
+ * Copyright (C) 2012 Texas Instruments
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/component.h>
+#include <linux/module.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_of.h>
+
+struct dummy_priv {
+ struct drm_encoder *encoder;
+};
+
+struct dummy_encoder_params {
+};
+
+#define to_dummy_priv(x) ((struct dummy_priv *)to_encoder_slave(x)->slave_priv)
+
+/* DRM encoder functions */
+
+static void dummy_encoder_set_config(struct dummy_priv *priv,
+ const struct dummy_encoder_params *p)
+{
+}
+
+static void dummy_encoder_dpms(struct dummy_priv *priv, int mode)
+{
+}
+
+static void
+dummy_encoder_save(struct drm_encoder *encoder)
+{
+}
+
+static void
+dummy_encoder_restore(struct drm_encoder *encoder)
+{
+}
+
+static bool
+dummy_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static int dummy_encoder_mode_valid(struct dummy_priv *priv,
+ struct drm_display_mode *mode)
+{
+ return MODE_OK;
+}
+
+static void
+dummy_encoder_mode_set(struct dummy_priv *priv,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+
+static enum drm_connector_status
+dummy_encoder_detect(struct dummy_priv *priv)
+{
+ return connector_status_connected;
+}
+
+
+static const u8 edid_1024x768[] = {
+ /*
+ * These values are a copy of Documentation/EDID/1024x768.c
+ * produced by executing "make -C Documentation/EDID"
+ */
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
+ 0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
+ 0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
+ 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
+ 0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
+ 0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
+ 0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
+ 0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
+ 0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55
+};
+
+static int
+dummy_encoder_get_modes(struct dummy_priv *priv,
+ struct drm_connector *connector)
+{
+ struct edid *edid = (struct edid *)edid_1024x768;
+ int n;
+
+ drm_mode_connector_update_edid_property(connector, edid);
+ n = drm_add_edid_modes(connector, edid);
+
+ return n;
+}
+
+static int
+dummy_encoder_set_property(struct drm_encoder *encoder,
+ struct drm_connector *connector,
+ struct drm_property *property,
+ uint64_t val)
+{
+ return 0;
+}
+
+static void dummy_destroy(struct dummy_priv *priv)
+{
+}
+
+/* Slave encoder support */
+
+static void
+dummy_encoder_slave_set_config(struct drm_encoder *encoder, void *params)
+{
+ dummy_encoder_set_config(to_dummy_priv(encoder), params);
+}
+
+static void dummy_encoder_slave_destroy(struct drm_encoder *encoder)
+{
+ struct dummy_priv *priv = to_dummy_priv(encoder);
+
+ dummy_destroy(priv);
+ drm_i2c_encoder_destroy(encoder);
+ kfree(priv);
+}
+
+static void dummy_encoder_slave_dpms(struct drm_encoder *encoder, int mode)
+{
+ dummy_encoder_dpms(to_dummy_priv(encoder), mode);
+}
+
+static int dummy_encoder_slave_mode_valid(struct drm_encoder *encoder,
+ struct drm_display_mode *mode)
+{
+ return dummy_encoder_mode_valid(to_dummy_priv(encoder), mode);
+}
+
+static void
+dummy_encoder_slave_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ dummy_encoder_mode_set(to_dummy_priv(encoder), mode, adjusted_mode);
+}
+
+static enum drm_connector_status
+dummy_encoder_slave_detect(struct drm_encoder *encoder,
+ struct drm_connector *connector)
+{
+ return dummy_encoder_detect(to_dummy_priv(encoder));
+}
+
+static int dummy_encoder_slave_get_modes(struct drm_encoder *encoder,
+ struct drm_connector *connector)
+{
+ return dummy_encoder_get_modes(to_dummy_priv(encoder), connector);
+}
+
+static int
+dummy_encoder_slave_create_resources(struct drm_encoder *encoder,
+ struct drm_connector *connector)
+{
+ return 0;
+}
+
+static struct drm_encoder_slave_funcs dummy_encoder_slave_funcs = {
+ .set_config = dummy_encoder_slave_set_config,
+ .destroy = dummy_encoder_slave_destroy,
+ .dpms = dummy_encoder_slave_dpms,
+ .save = dummy_encoder_save,
+ .restore = dummy_encoder_restore,
+ .mode_fixup = dummy_encoder_mode_fixup,
+ .mode_valid = dummy_encoder_slave_mode_valid,
+ .mode_set = dummy_encoder_slave_mode_set,
+ .detect = dummy_encoder_slave_detect,
+ .get_modes = dummy_encoder_slave_get_modes,
+ .create_resources = dummy_encoder_slave_create_resources,
+ .set_property = dummy_encoder_set_property,
+};
+
+/* I2C driver functions */
+
+static int dummy_encoder_init(struct i2c_client *client,
+ struct drm_device *dev,
+ struct drm_encoder_slave *encoder_slave)
+{
+ struct dummy_priv *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->encoder = &encoder_slave->base;
+
+ encoder_slave->slave_priv = priv;
+ encoder_slave->slave_funcs = &dummy_encoder_slave_funcs;
+
+ return 0;
+}
+
+struct dummy_priv2 {
+ struct dummy_priv base;
+ struct drm_encoder encoder;
+ struct drm_connector connector;
+};
+
+#define conn_to_dummy_priv2(x) \
+ container_of(x, struct dummy_priv2, connector);
+
+#define enc_to_dummy_priv2(x) \
+ container_of(x, struct dummy_priv2, encoder);
+
+static void dummy_encoder2_dpms(struct drm_encoder *encoder, int mode)
+{
+ struct dummy_priv2 *priv = enc_to_dummy_priv2(encoder);
+
+ dummy_encoder_dpms(&priv->base, mode);
+}
+
+static void dummy_encoder_prepare(struct drm_encoder *encoder)
+{
+ dummy_encoder2_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void dummy_encoder_commit(struct drm_encoder *encoder)
+{
+ dummy_encoder2_dpms(encoder, DRM_MODE_DPMS_ON);
+}
+
+static void dummy_encoder2_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct dummy_priv2 *priv = enc_to_dummy_priv2(encoder);
+
+ dummy_encoder_mode_set(&priv->base, mode, adjusted_mode);
+}
+
+static const struct drm_encoder_helper_funcs dummy_encoder_helper_funcs = {
+ .dpms = dummy_encoder2_dpms,
+ .save = dummy_encoder_save,
+ .restore = dummy_encoder_restore,
+ .mode_fixup = dummy_encoder_mode_fixup,
+ .prepare = dummy_encoder_prepare,
+ .commit = dummy_encoder_commit,
+ .mode_set = dummy_encoder2_mode_set,
+};
+
+static void dummy_encoder_destroy(struct drm_encoder *encoder)
+{
+ struct dummy_priv2 *priv = enc_to_dummy_priv2(encoder);
+
+ dummy_destroy(&priv->base);
+ drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs dummy_encoder_funcs = {
+ .destroy = dummy_encoder_destroy,
+};
+
+static int dummy_connector_get_modes(struct drm_connector *connector)
+{
+ struct dummy_priv2 *priv = conn_to_dummy_priv2(connector);
+
+ return dummy_encoder_get_modes(&priv->base, connector);
+}
+
+static int dummy_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct dummy_priv2 *priv = conn_to_dummy_priv2(connector);
+
+ return dummy_encoder_mode_valid(&priv->base, mode);
+}
+
+static struct drm_encoder *
+dummy_connector_best_encoder(struct drm_connector *connector)
+{
+ struct dummy_priv2 *priv = conn_to_dummy_priv2(connector);
+
+ return &priv->encoder;
+}
+
+static
+const struct drm_connector_helper_funcs dummy_connector_helper_funcs = {
+ .get_modes = dummy_connector_get_modes,
+ .mode_valid = dummy_connector_mode_valid,
+ .best_encoder = dummy_connector_best_encoder,
+};
+
+static enum drm_connector_status
+dummy_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct dummy_priv2 *priv = conn_to_dummy_priv2(connector);
+
+ return dummy_encoder_detect(&priv->base);
+}
+
+static void dummy_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs dummy_connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = dummy_connector_detect,
+ .destroy = dummy_connector_destroy,
+};
+
+static int dummy_bind(struct device *dev, struct device *master, void *data)
+{
+ struct drm_device *drm = data;
+ struct dummy_priv2 *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+
+ priv->base.encoder = &priv->encoder;
+ priv->encoder.possible_crtcs = 1 << 0;
+
+ drm_encoder_helper_add(&priv->encoder, &dummy_encoder_helper_funcs);
+ ret = drm_encoder_init(drm, &priv->encoder, &dummy_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
+ if (ret)
+ goto err_encoder;
+
+ drm_connector_helper_add(&priv->connector,
+ &dummy_connector_helper_funcs);
+ ret = drm_connector_init(drm, &priv->connector,
+ &dummy_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+ if (ret)
+ goto err_connector;
+
+ ret = drm_connector_register(&priv->connector);
+ if (ret)
+ goto err_sysfs;
+
+ priv->connector.encoder = &priv->encoder;
+ drm_mode_connector_attach_encoder(&priv->connector, &priv->encoder);
+
+ return 0;
+
+err_sysfs:
+ drm_connector_cleanup(&priv->connector);
+err_connector:
+ drm_encoder_cleanup(&priv->encoder);
+err_encoder:
+ dummy_destroy(&priv->base);
+ return ret;
+}
+
+static void dummy_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct dummy_priv2 *priv = dev_get_drvdata(dev);
+
+ drm_connector_cleanup(&priv->connector);
+ drm_encoder_cleanup(&priv->encoder);
+ dummy_destroy(&priv->base);
+}
+
+static const struct component_ops dummy_ops = {
+ .bind = dummy_bind,
+ .unbind = dummy_unbind,
+};
+
+static int
+dummy_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ return component_add(&client->dev, &dummy_ops);
+}
+
+static int dummy_remove(struct i2c_client *client)
+{
+ component_del(&client->dev, &dummy_ops);
+ return 0;
+}
+
+static const struct of_device_id dummy_of_ids[] = {
+ { .compatible = "sil,sii9022-tpi", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, dummy_of_ids);
+
+static struct i2c_device_id dummy_ids[] = {
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, dummy_ids);
+
+static struct drm_i2c_encoder_driver dummy_driver = {
+ .i2c_driver = {
+ .probe = dummy_probe,
+ .remove = dummy_remove,
+ .driver = {
+ .name = "dummy_drm_i2c",
+ .of_match_table = dummy_of_ids
+ },
+ .id_table = dummy_ids,
+ },
+ .encoder_init = dummy_encoder_init,
+};
+
+/* Module initialization */
+
+static int __init
+dummy_init(void)
+{
+ return drm_i2c_encoder_register(THIS_MODULE, &dummy_driver);
+}
+
+static void __exit
+dummy_exit(void)
+{
+ drm_i2c_encoder_unregister(&dummy_driver);
+}
+
+MODULE_LICENSE("GPL");
+
+module_init(dummy_init);
+module_exit(dummy_exit);