@@ -6,7 +6,9 @@
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
+#include <linux/component.h>
#include <linux/module.h>
+#include <linux/platform_data/armada_drm.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include "armada_crtc.h"
@@ -53,6 +55,11 @@ static const struct armada_drm_slave_config tda19988_config = {
};
#endif
+static bool is_componentized(struct device *dev)
+{
+ return dev->of_node || dev->platform_data;
+}
+
static void armada_drm_unref_work(struct work_struct *work)
{
struct armada_private *priv =
@@ -171,16 +178,22 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags)
goto err_kms;
}
+ if (is_componentized(dev->dev)) {
+ ret = component_bind_all(dev->dev, dev);
+ if (ret)
+ goto err_kms;
+ } else {
#ifdef CONFIG_DRM_ARMADA_TDA1998X
- ret = armada_drm_connector_slave_create(dev, &tda19988_config);
- if (ret)
- goto err_kms;
+ ret = armada_drm_connector_slave_create(dev, &tda19988_config);
+ if (ret)
+ goto err_kms;
#endif
#ifdef CONFIG_DRM_ARMADA_TDA1998X_NXP
- ret = armada_drm_tda19988_nxp_create(dev);
- if (ret)
- goto err_kms;
+ ret = armada_drm_tda19988_nxp_create(dev);
+ if (ret)
+ goto err_kms;
#endif
+ }
ret = drm_vblank_init(dev, n);
if (ret)
@@ -204,6 +217,10 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags)
drm_irq_uninstall(dev);
err_kms:
drm_mode_config_cleanup(dev);
+
+ if (is_componentized(dev->dev))
+ component_unbind_all(dev->dev, dev);
+
drm_mm_takedown(&priv->linear);
flush_work(&priv->fb_unref_work);
@@ -218,6 +235,10 @@ static int armada_drm_unload(struct drm_device *dev)
armada_fbdev_fini(dev);
drm_irq_uninstall(dev);
drm_mode_config_cleanup(dev);
+
+ if (is_componentized(dev->dev))
+ component_unbind_all(dev->dev, dev);
+
drm_mm_takedown(&priv->linear);
flush_work(&priv->fb_unref_work);
dev->dev_private = NULL;
@@ -380,14 +401,82 @@ static struct drm_driver armada_drm_driver = {
.fops = &armada_drm_fops,
};
+static int armada_drm_bind(struct device *dev)
+{
+ return drm_platform_init(&armada_drm_driver, to_platform_device(dev));
+}
+
+static void armada_drm_unbind(struct device *dev)
+{
+ drm_platform_exit(&armada_drm_driver, to_platform_device(dev));
+}
+
+static int compare_of(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+static int armada_drm_compare_name(struct device *dev, void *data)
+{
+ const char *name = data;
+ return !strcmp(dev_name(dev), name);
+}
+
+static int armada_drm_add_components(struct device *dev, struct master *master)
+{
+ int i, ret = -ENXIO;
+
+ if (dev->of_node) {
+ struct device_node *np = dev->of_node;
+
+ for (i = 0; ; i++) {
+ struct device_node *node;
+
+ node = of_parse_phandle(np, "connectors", i);
+ if (!node)
+ break;
+
+ ret = component_master_add_child(master, compare_of,
+ node);
+ of_node_put(node);
+ if (ret)
+ break;
+ }
+ } else if (dev->platform_data) {
+ struct armada_drm_platform_data *data = dev->platform_data;
+
+ for (i = 0; i < data->num_devices; i++) {
+ ret = component_master_add_child(master,
+ armada_drm_compare_name,
+ (void *)data->devices[i]);
+ if (ret)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static const struct component_master_ops armada_master_ops = {
+ .add_components = armada_drm_add_components,
+ .bind = armada_drm_bind,
+ .unbind = armada_drm_unbind,
+};
+
static int armada_drm_probe(struct platform_device *pdev)
{
- return drm_platform_init(&armada_drm_driver, pdev);
+ if (is_componentized(&pdev->dev))
+ return component_master_add(&pdev->dev, &armada_master_ops);
+ else
+ return drm_platform_init(&armada_drm_driver, pdev);
}
static int armada_drm_remove(struct platform_device *pdev)
{
- drm_platform_exit(&armada_drm_driver, pdev);
+ if (is_componentized(&pdev->dev))
+ component_master_del(&pdev->dev, &armada_master_ops);
+ else
+ drm_platform_exit(&armada_drm_driver, pdev);
return 0;
}