mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
drm/rockchip: add RGB support for rk618
Change-Id: Ieddeeb842ee9db11b8c56cb4171bd630b6b63acb Signed-off-by: Shunqing Chen <csq@rock-chips.com>
This commit is contained in:
@@ -114,3 +114,75 @@ Example:
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
RGB Encoder
|
||||
------------
|
||||
|
||||
Required properties:
|
||||
- compatible: value should be one of the following:
|
||||
"rockchip,rk618-rgb"
|
||||
- clocks: must include clock specifiers corresponding to entries in the
|
||||
clock-names property.
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
- clock-names: list of clock names sorted in the same order as the clocks
|
||||
property. Must contain "rgb", "dither", "vif", "scaler".
|
||||
|
||||
Required nodes:
|
||||
|
||||
The connections to the video ports are modeled using the OF graph
|
||||
bindings specified in Documentation/devicetree/bindings/graph.txt.
|
||||
|
||||
Example:
|
||||
|
||||
&rk618 {
|
||||
status = "okay";
|
||||
|
||||
rgb {
|
||||
compatible = "rockchip,rk618-rgb";
|
||||
clocks = <&CRU RGB_CLK>, <&CRU DITHER_CLK>,
|
||||
<&CRU VIF0_CLK>, <&CRU SCALER_CLK>;
|
||||
clock-names = "rgb", "dither", "vif", "scaler";
|
||||
status = "okay";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
rgb_input_vop: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&vop_output_rgb>;
|
||||
};
|
||||
|
||||
rgb_input_vif: endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&vif_output_rgb>;
|
||||
};
|
||||
|
||||
rgb_input_hdmi: endpoint@2 {
|
||||
reg = <2>;
|
||||
remote-endpoint = <&hdmi_output_rgb>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
rgb_lcdc1_out_tve: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&tve_in_rgb_lcdc1>;
|
||||
};
|
||||
rgb_out_tve: endpoint@1 {
|
||||
status = "disabled";
|
||||
reg = <1>;
|
||||
remote-endpoint = <&tve_in_rgb>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -8,3 +8,4 @@ obj-$(CONFIG_DRM_ROCKCHIP_RK618) += rk618_output.o \
|
||||
rk618_vif.o \
|
||||
rk618_dither.o \
|
||||
rk618_lvds.o \
|
||||
rk618_rgb.o \
|
||||
|
||||
@@ -14,37 +14,6 @@
|
||||
|
||||
#include "rk618_output.h"
|
||||
|
||||
#define RK618_LVDS_CON 0x0084
|
||||
#define LVDS_CON_START_PHASE(x) HIWORD_UPDATE(x, 14, 14)
|
||||
#define LVDS_DCLK_INV HIWORD_UPDATE(1, 13, 13)
|
||||
#define LVDS_CON_CHADS_10PF HIWORD_UPDATE(3, 12, 11)
|
||||
#define LVDS_CON_CHADS_5PF HIWORD_UPDATE(2, 12, 11)
|
||||
#define LVDS_CON_CHADS_7PF HIWORD_UPDATE(1, 12, 11)
|
||||
#define LVDS_CON_CHADS_3PF HIWORD_UPDATE(0, 12, 11)
|
||||
#define LVDS_CON_CHA1TTL_ENABLE HIWORD_UPDATE(1, 10, 10)
|
||||
#define LVDS_CON_CHA1TTL_DISABLE HIWORD_UPDATE(0, 10, 10)
|
||||
#define LVDS_CON_CHA0TTL_ENABLE HIWORD_UPDATE(1, 9, 9)
|
||||
#define LVDS_CON_CHA0TTL_DISABLE HIWORD_UPDATE(0, 9, 9)
|
||||
#define LVDS_CON_CHA1_POWER_UP HIWORD_UPDATE(1, 8, 8)
|
||||
#define LVDS_CON_CHA1_POWER_DOWN HIWORD_UPDATE(0, 8, 8)
|
||||
#define LVDS_CON_CHA0_POWER_UP HIWORD_UPDATE(1, 7, 7)
|
||||
#define LVDS_CON_CHA0_POWER_DOWN HIWORD_UPDATE(0, 7, 7)
|
||||
#define LVDS_CON_CBG_POWER_UP HIWORD_UPDATE(1, 6, 6)
|
||||
#define LVDS_CON_CBG_POWER_DOWN HIWORD_UPDATE(0, 6, 6)
|
||||
#define LVDS_CON_PLL_POWER_DOWN HIWORD_UPDATE(1, 5, 5)
|
||||
#define LVDS_CON_PLL_POWER_UP HIWORD_UPDATE(0, 5, 5)
|
||||
#define LVDS_CON_START_SEL_EVEN_PIXEL HIWORD_UPDATE(1, 4, 4)
|
||||
#define LVDS_CON_START_SEL_ODD_PIXEL HIWORD_UPDATE(0, 4, 4)
|
||||
#define LVDS_CON_CHASEL_DOUBLE_CHANNEL HIWORD_UPDATE(1, 3, 3)
|
||||
#define LVDS_CON_CHASEL_SINGLE_CHANNEL HIWORD_UPDATE(0, 3, 3)
|
||||
#define LVDS_CON_MSBSEL_D7 HIWORD_UPDATE(1, 2, 2)
|
||||
#define LVDS_CON_MSBSEL_D0 HIWORD_UPDATE(0, 2, 2)
|
||||
#define LVDS_CON_SELECT(x) HIWORD_UPDATE(x, 1, 0)
|
||||
#define LVDS_CON_SELECT_6BIT_MODE HIWORD_UPDATE(3, 1, 0)
|
||||
#define LVDS_CON_SELECT_8BIT_MODE_3 HIWORD_UPDATE(2, 1, 0)
|
||||
#define LVDS_CON_SELECT_8BIT_MODE_2 HIWORD_UPDATE(1, 1, 0)
|
||||
#define LVDS_CON_SELECT_8BIT_MODE_1 HIWORD_UPDATE(0, 1, 0)
|
||||
|
||||
#define IS_DOUBLE_CHANNEL(lvds) ((lvds)->channels == 2)
|
||||
|
||||
enum {
|
||||
|
||||
@@ -99,24 +99,28 @@ static void rk618_output_encoder_enable(struct drm_encoder *encoder)
|
||||
if (output->funcs->pre_enable)
|
||||
output->funcs->pre_enable(output);
|
||||
|
||||
drm_panel_prepare(output->panel);
|
||||
if (output->panel)
|
||||
drm_panel_prepare(output->panel);
|
||||
|
||||
if (output->funcs->enable)
|
||||
output->funcs->enable(output);
|
||||
|
||||
drm_panel_enable(output->panel);
|
||||
if (output->panel)
|
||||
drm_panel_enable(output->panel);
|
||||
}
|
||||
|
||||
static void rk618_output_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct rk618_output *output = encoder_to_output(encoder);
|
||||
|
||||
drm_panel_disable(output->panel);
|
||||
if (output->panel)
|
||||
drm_panel_disable(output->panel);
|
||||
|
||||
if (output->funcs->disable)
|
||||
output->funcs->disable(output);
|
||||
|
||||
drm_panel_unprepare(output->panel);
|
||||
if (output->panel)
|
||||
drm_panel_unprepare(output->panel);
|
||||
|
||||
if (output->funcs->post_disable)
|
||||
output->funcs->post_disable(output);
|
||||
@@ -187,7 +191,8 @@ static void rk618_output_bridge_pre_enable(struct drm_bridge *bridge)
|
||||
if (output->funcs->pre_enable)
|
||||
output->funcs->pre_enable(output);
|
||||
|
||||
drm_panel_prepare(output->panel);
|
||||
if (output->panel)
|
||||
drm_panel_prepare(output->panel);
|
||||
}
|
||||
|
||||
static void rk618_output_bridge_enable(struct drm_bridge *bridge)
|
||||
@@ -197,14 +202,16 @@ static void rk618_output_bridge_enable(struct drm_bridge *bridge)
|
||||
if (output->funcs->enable)
|
||||
output->funcs->enable(output);
|
||||
|
||||
drm_panel_enable(output->panel);
|
||||
if (output->panel)
|
||||
drm_panel_enable(output->panel);
|
||||
}
|
||||
|
||||
static void rk618_output_bridge_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct rk618_output *output = bridge_to_output(bridge);
|
||||
|
||||
drm_panel_disable(output->panel);
|
||||
if (output->panel)
|
||||
drm_panel_disable(output->panel);
|
||||
|
||||
if (output->funcs->disable)
|
||||
output->funcs->disable(output);
|
||||
@@ -214,7 +221,8 @@ static void rk618_output_bridge_post_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct rk618_output *output = bridge_to_output(bridge);
|
||||
|
||||
drm_panel_unprepare(output->panel);
|
||||
if (output->panel)
|
||||
drm_panel_unprepare(output->panel);
|
||||
|
||||
if (output->funcs->post_disable)
|
||||
output->funcs->post_disable(output);
|
||||
@@ -246,7 +254,7 @@ static const struct drm_bridge_funcs rk618_output_bridge_funcs = {
|
||||
int rk618_output_register(struct rk618_output *output)
|
||||
{
|
||||
struct device *dev = output->dev;
|
||||
struct device_node *endpoint, *remote;
|
||||
struct device_node *endpoint, *remote = NULL, *port;
|
||||
int ret;
|
||||
|
||||
output->dither_clk = devm_clk_get(dev, "dither");
|
||||
@@ -270,14 +278,26 @@ int rk618_output_register(struct rk618_output *output)
|
||||
return ret;
|
||||
}
|
||||
|
||||
endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1);
|
||||
if (!endpoint) {
|
||||
dev_err(dev, "no valid endpoint\n");
|
||||
return -ENODEV;
|
||||
port = of_graph_get_port_by_id(dev->of_node, 1);
|
||||
if (!port) {
|
||||
dev_err(dev, "can't found port point.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for_each_child_of_node(port, endpoint) {
|
||||
remote = of_graph_get_remote_port_parent(endpoint);
|
||||
if (!remote) {
|
||||
dev_err(dev, "can't found panel node, please init!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!of_device_is_available(remote)) {
|
||||
of_node_put(remote);
|
||||
remote = NULL;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
remote = of_graph_get_remote_port_parent(endpoint);
|
||||
of_node_put(endpoint);
|
||||
if (!remote) {
|
||||
dev_err(dev, "no valid remote node\n");
|
||||
return -ENODEV;
|
||||
@@ -300,7 +320,12 @@ int rk618_output_bind(struct rk618_output *output, struct drm_device *drm,
|
||||
|
||||
output->panel = of_drm_find_panel(output->panel_node);
|
||||
if (!output->panel)
|
||||
output->ext_bridge = of_drm_find_bridge(output->panel_node);
|
||||
|
||||
if (!output->panel && !output->ext_bridge) {
|
||||
dev_info(dev, "Waiting for panel or bridge driver\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm,
|
||||
dev->of_node);
|
||||
@@ -308,15 +333,36 @@ int rk618_output_bind(struct rk618_output *output, struct drm_device *drm,
|
||||
encoder_type, NULL);
|
||||
drm_encoder_helper_add(encoder, &rk618_output_encoder_helper_funcs);
|
||||
|
||||
connector->port = dev->of_node;
|
||||
drm_connector_init(drm, connector, &rk618_output_connector_funcs,
|
||||
connector_type);
|
||||
drm_connector_helper_add(connector,
|
||||
&rk618_output_connector_helper_funcs);
|
||||
if (output->ext_bridge) {
|
||||
output->ext_bridge->encoder = encoder;
|
||||
ret = drm_bridge_attach(drm, output->ext_bridge);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to attach bridge\n");
|
||||
return ret;
|
||||
}
|
||||
encoder->bridge = output->ext_bridge;
|
||||
} else {
|
||||
connector->port = dev->of_node;
|
||||
ret = drm_connector_init(drm, connector,
|
||||
&rk618_output_connector_funcs,
|
||||
connector_type);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to init connector with drm\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
drm_mode_connector_attach_encoder(connector, encoder);
|
||||
drm_connector_helper_add(connector,
|
||||
&rk618_output_connector_helper_funcs);
|
||||
|
||||
drm_panel_attach(output->panel, connector);
|
||||
drm_mode_connector_attach_encoder(connector,
|
||||
output->bridge.encoder);
|
||||
|
||||
ret = drm_panel_attach(output->panel, connector);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to attach panel\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
bridge->funcs = &rk618_output_bridge_funcs;
|
||||
bridge->of_node = dev->of_node;
|
||||
|
||||
@@ -40,6 +40,36 @@
|
||||
#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l)))
|
||||
#define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK((h), (l)) << 16))
|
||||
|
||||
#define RK618_LVDS_CON 0x0084
|
||||
#define LVDS_CON_START_PHASE(x) HIWORD_UPDATE(x, 14, 14)
|
||||
#define LVDS_DCLK_INV HIWORD_UPDATE(1, 13, 13)
|
||||
#define LVDS_CON_CHADS_10PF HIWORD_UPDATE(3, 12, 11)
|
||||
#define LVDS_CON_CHADS_5PF HIWORD_UPDATE(2, 12, 11)
|
||||
#define LVDS_CON_CHADS_7PF HIWORD_UPDATE(1, 12, 11)
|
||||
#define LVDS_CON_CHADS_3PF HIWORD_UPDATE(0, 12, 11)
|
||||
#define LVDS_CON_CHA1TTL_ENABLE HIWORD_UPDATE(1, 10, 10)
|
||||
#define LVDS_CON_CHA1TTL_DISABLE HIWORD_UPDATE(0, 10, 10)
|
||||
#define LVDS_CON_CHA0TTL_ENABLE HIWORD_UPDATE(1, 9, 9)
|
||||
#define LVDS_CON_CHA0TTL_DISABLE HIWORD_UPDATE(0, 9, 9)
|
||||
#define LVDS_CON_CHA1_POWER_UP HIWORD_UPDATE(1, 8, 8)
|
||||
#define LVDS_CON_CHA1_POWER_DOWN HIWORD_UPDATE(0, 8, 8)
|
||||
#define LVDS_CON_CHA0_POWER_UP HIWORD_UPDATE(1, 7, 7)
|
||||
#define LVDS_CON_CHA0_POWER_DOWN HIWORD_UPDATE(0, 7, 7)
|
||||
#define LVDS_CON_CBG_POWER_UP HIWORD_UPDATE(1, 6, 6)
|
||||
#define LVDS_CON_CBG_POWER_DOWN HIWORD_UPDATE(0, 6, 6)
|
||||
#define LVDS_CON_PLL_POWER_DOWN HIWORD_UPDATE(1, 5, 5)
|
||||
#define LVDS_CON_PLL_POWER_UP HIWORD_UPDATE(0, 5, 5)
|
||||
#define LVDS_CON_START_SEL_EVEN_PIXEL HIWORD_UPDATE(1, 4, 4)
|
||||
#define LVDS_CON_START_SEL_ODD_PIXEL HIWORD_UPDATE(0, 4, 4)
|
||||
#define LVDS_CON_CHASEL_DOUBLE_CHANNEL HIWORD_UPDATE(1, 3, 3)
|
||||
#define LVDS_CON_CHASEL_SINGLE_CHANNEL HIWORD_UPDATE(0, 3, 3)
|
||||
#define LVDS_CON_MSBSEL_D7 HIWORD_UPDATE(1, 2, 2)
|
||||
#define LVDS_CON_MSBSEL_D0 HIWORD_UPDATE(0, 2, 2)
|
||||
#define LVDS_CON_SELECT(x) HIWORD_UPDATE(x, 1, 0)
|
||||
#define LVDS_CON_SELECT_6BIT_MODE HIWORD_UPDATE(3, 1, 0)
|
||||
#define LVDS_CON_SELECT_8BIT_MODE_3 HIWORD_UPDATE(2, 1, 0)
|
||||
#define LVDS_CON_SELECT_8BIT_MODE_2 HIWORD_UPDATE(1, 1, 0)
|
||||
#define LVDS_CON_SELECT_8BIT_MODE_1 HIWORD_UPDATE(0, 1, 0)
|
||||
#define RK618_IO_CON0 0x0088
|
||||
#define VIF1_SYNC_MODE_ENABLE HIWORD_UPDATE(1, 15, 15)
|
||||
#define VIF1_SYNC_MODE_DISABLE HIWORD_UPDATE(0, 15, 15)
|
||||
@@ -118,6 +148,7 @@ struct rk618_output {
|
||||
struct drm_display_mode panel_mode;
|
||||
struct drm_display_mode scale_mode;
|
||||
u32 bus_format;
|
||||
struct drm_bridge *ext_bridge;
|
||||
|
||||
struct device *dev;
|
||||
struct device_node *panel_node;
|
||||
|
||||
153
drivers/gpu/drm/rockchip/rk618/rk618_rgb.c
Normal file
153
drivers/gpu/drm/rockchip/rk618/rk618_rgb.c
Normal file
@@ -0,0 +1,153 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2018 Rockchip Electronics Co. Ltd.
|
||||
*/
|
||||
|
||||
#include "rk618_output.h"
|
||||
|
||||
struct rk618_rgb {
|
||||
struct rk618_output base;
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct clk *clock;
|
||||
};
|
||||
|
||||
static inline struct rk618_rgb *to_rgb(struct rk618_output *output)
|
||||
{
|
||||
return container_of(output, struct rk618_rgb, base);
|
||||
}
|
||||
|
||||
static void rk618_rgb_enable(struct rk618_output *output)
|
||||
{
|
||||
struct rk618_rgb *rgb = to_rgb(output);
|
||||
u32 value;
|
||||
struct device_node *endpoint;
|
||||
int lcdc1_output_rgb = 0;
|
||||
|
||||
endpoint = of_graph_get_endpoint_by_regs(output->dev->of_node, 1, 0);
|
||||
if (endpoint && of_device_is_available(endpoint))
|
||||
lcdc1_output_rgb = 1;
|
||||
|
||||
clk_prepare_enable(rgb->clock);
|
||||
|
||||
if (lcdc1_output_rgb) {
|
||||
value = LVDS_CON_CHA1TTL_DISABLE | LVDS_CON_CHA0TTL_DISABLE |
|
||||
LVDS_CON_CHA1_POWER_DOWN | LVDS_CON_CHA0_POWER_DOWN |
|
||||
LVDS_CON_CBG_POWER_DOWN | LVDS_CON_PLL_POWER_DOWN;
|
||||
regmap_write(rgb->regmap, RK618_LVDS_CON, value);
|
||||
|
||||
regmap_write(rgb->regmap, RK618_IO_CON0,
|
||||
PORT1_OUTPUT_TTL_ENABLE);
|
||||
} else {
|
||||
value = LVDS_CON_CBG_POWER_DOWN | LVDS_CON_CHA1_POWER_DOWN |
|
||||
LVDS_CON_CHA0_POWER_DOWN;
|
||||
value |= LVDS_CON_CHA0TTL_ENABLE | LVDS_CON_CHA1TTL_ENABLE |
|
||||
LVDS_CON_PLL_POWER_DOWN;
|
||||
regmap_write(rgb->regmap, RK618_LVDS_CON, value);
|
||||
|
||||
regmap_write(rgb->regmap, RK618_IO_CON0, PORT2_OUTPUT_TTL);
|
||||
}
|
||||
}
|
||||
|
||||
static void rk618_rgb_disable(struct rk618_output *output)
|
||||
{
|
||||
struct rk618_rgb *rgb = to_rgb(output);
|
||||
|
||||
regmap_write(rgb->regmap, RK618_LVDS_CON,
|
||||
LVDS_CON_CHA0_POWER_DOWN | LVDS_CON_CHA1_POWER_DOWN |
|
||||
LVDS_CON_CBG_POWER_DOWN | LVDS_CON_PLL_POWER_DOWN);
|
||||
|
||||
clk_disable_unprepare(rgb->clock);
|
||||
}
|
||||
|
||||
static const struct rk618_output_funcs rk618_rgb_funcs = {
|
||||
.enable = rk618_rgb_enable,
|
||||
.disable = rk618_rgb_disable,
|
||||
};
|
||||
|
||||
static int rk618_rgb_bind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct drm_device *drm = data;
|
||||
struct rk618_rgb *rgb = dev_get_drvdata(dev);
|
||||
|
||||
return rk618_output_bind(&rgb->base, drm, DRM_MODE_ENCODER_LVDS,
|
||||
DRM_MODE_CONNECTOR_LVDS);
|
||||
}
|
||||
|
||||
static void rk618_rgb_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct rk618_rgb *rgb = dev_get_drvdata(dev);
|
||||
|
||||
rk618_output_unbind(&rgb->base);
|
||||
}
|
||||
|
||||
static const struct component_ops rk618_rgb_component_ops = {
|
||||
.bind = rk618_rgb_bind,
|
||||
.unbind = rk618_rgb_unbind,
|
||||
};
|
||||
|
||||
static const struct of_device_id rk618_rgb_of_match[] = {
|
||||
{ .compatible = "rockchip,rk618-rgb", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rk618_rgb_of_match);
|
||||
|
||||
static int rk618_rgb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rk618 *rk618 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rk618_rgb *rgb;
|
||||
int ret;
|
||||
|
||||
if (!of_device_is_available(dev->of_node))
|
||||
return -ENODEV;
|
||||
|
||||
rgb = devm_kzalloc(dev, sizeof(*rgb), GFP_KERNEL);
|
||||
if (!rgb)
|
||||
return -ENOMEM;
|
||||
|
||||
rgb->dev = dev;
|
||||
rgb->regmap = rk618->regmap;
|
||||
platform_set_drvdata(pdev, rgb);
|
||||
|
||||
rgb->clock = devm_clk_get(dev, "rgb");
|
||||
if (IS_ERR(rgb->clock)) {
|
||||
ret = PTR_ERR(rgb->clock);
|
||||
dev_err(dev, "failed to get rgb clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rgb->base.parent = rk618;
|
||||
rgb->base.dev = dev;
|
||||
rgb->base.funcs = &rk618_rgb_funcs;
|
||||
ret = rk618_output_register(&rgb->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return component_add(dev, &rk618_rgb_component_ops);
|
||||
}
|
||||
|
||||
static int rk618_rgb_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rk618_rgb *rgb = platform_get_drvdata(pdev);
|
||||
|
||||
component_del(rgb->dev, &rk618_rgb_component_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver rk618_rgb_driver = {
|
||||
.driver = {
|
||||
.name = "rk618-rgb",
|
||||
.of_match_table = of_match_ptr(rk618_rgb_of_match),
|
||||
},
|
||||
.probe = rk618_rgb_probe,
|
||||
.remove = rk618_rgb_remove,
|
||||
};
|
||||
module_platform_driver(rk618_rgb_driver);
|
||||
|
||||
MODULE_AUTHOR("Chen Shunqing <csq@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("Rockchip RK618 RGB driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
Reference in New Issue
Block a user