Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1/*
2 * OPA362 analog video amplifier with output/power control
3 *
4 * Copyright (C) 2014 Golden Delicious Computers
5 * Author: H. Nikolaus Schaller <hns@goldelico.com>
6 *
7 * based on encoder-tfp410
8 *
9 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
10 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License version 2 as published by
14 * the Free Software Foundation.
15 */
16
17#include <linux/gpio/consumer.h>
18#include <linux/module.h>
19#include <linux/platform_device.h>
20#include <linux/slab.h>
21
22#include "../dss/omapdss.h"
23
24struct panel_drv_data {
25 struct omap_dss_device dssdev;
26
27 struct gpio_desc *enable_gpio;
28};
29
30#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
31
32static int opa362_connect(struct omap_dss_device *src,
33 struct omap_dss_device *dst)
34{
35 return omapdss_device_connect(dst->dss, dst, dst->next);
36}
37
38static void opa362_disconnect(struct omap_dss_device *src,
39 struct omap_dss_device *dst)
40{
41 omapdss_device_disconnect(dst, dst->next);
42}
43
44static int opa362_enable(struct omap_dss_device *dssdev)
45{
46 struct panel_drv_data *ddata = to_panel_data(dssdev);
47 struct omap_dss_device *src = dssdev->src;
48 int r;
49
50 dev_dbg(dssdev->dev, "enable\n");
51
52 if (!omapdss_device_is_connected(dssdev))
53 return -ENODEV;
54
55 if (omapdss_device_is_enabled(dssdev))
56 return 0;
57
58 r = src->ops->enable(src);
59 if (r)
60 return r;
61
62 if (ddata->enable_gpio)
63 gpiod_set_value_cansleep(ddata->enable_gpio, 1);
64
65 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
66
67 return 0;
68}
69
70static void opa362_disable(struct omap_dss_device *dssdev)
71{
72 struct panel_drv_data *ddata = to_panel_data(dssdev);
73 struct omap_dss_device *src = dssdev->src;
74
75 dev_dbg(dssdev->dev, "disable\n");
76
77 if (!omapdss_device_is_enabled(dssdev))
78 return;
79
80 if (ddata->enable_gpio)
81 gpiod_set_value_cansleep(ddata->enable_gpio, 0);
82
83 src->ops->disable(src);
84
85 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
86}
87
88static const struct omap_dss_device_ops opa362_ops = {
89 .connect = opa362_connect,
90 .disconnect = opa362_disconnect,
91 .enable = opa362_enable,
92 .disable = opa362_disable,
93};
94
95static int opa362_probe(struct platform_device *pdev)
96{
97 struct panel_drv_data *ddata;
98 struct omap_dss_device *dssdev;
99 struct gpio_desc *gpio;
100
101 dev_dbg(&pdev->dev, "probe\n");
102
103 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
104 if (!ddata)
105 return -ENOMEM;
106
107 platform_set_drvdata(pdev, ddata);
108
109 gpio = devm_gpiod_get_optional(&pdev->dev, "enable", GPIOD_OUT_LOW);
110 if (IS_ERR(gpio))
111 return PTR_ERR(gpio);
112
113 ddata->enable_gpio = gpio;
114
115 dssdev = &ddata->dssdev;
116 dssdev->ops = &opa362_ops;
117 dssdev->dev = &pdev->dev;
118 dssdev->type = OMAP_DISPLAY_TYPE_VENC;
119 dssdev->output_type = OMAP_DISPLAY_TYPE_VENC;
120 dssdev->owner = THIS_MODULE;
121 dssdev->of_ports = BIT(1) | BIT(0);
122
123 dssdev->next = omapdss_of_find_connected_device(pdev->dev.of_node, 1);
124 if (IS_ERR(dssdev->next)) {
125 if (PTR_ERR(dssdev->next) != -EPROBE_DEFER)
126 dev_err(&pdev->dev, "failed to find video sink\n");
127 return PTR_ERR(dssdev->next);
128 }
129
130 omapdss_device_register(dssdev);
131
132 return 0;
133}
134
135static int __exit opa362_remove(struct platform_device *pdev)
136{
137 struct panel_drv_data *ddata = platform_get_drvdata(pdev);
138 struct omap_dss_device *dssdev = &ddata->dssdev;
139
140 if (dssdev->next)
141 omapdss_device_put(dssdev->next);
142 omapdss_device_unregister(&ddata->dssdev);
143
144 WARN_ON(omapdss_device_is_enabled(dssdev));
145 if (omapdss_device_is_enabled(dssdev))
146 opa362_disable(dssdev);
147
148 WARN_ON(omapdss_device_is_connected(dssdev));
149 if (omapdss_device_is_connected(dssdev))
150 omapdss_device_disconnect(NULL, dssdev);
151
152 return 0;
153}
154
155static const struct of_device_id opa362_of_match[] = {
156 { .compatible = "omapdss,ti,opa362", },
157 {},
158};
159MODULE_DEVICE_TABLE(of, opa362_of_match);
160
161static struct platform_driver opa362_driver = {
162 .probe = opa362_probe,
163 .remove = __exit_p(opa362_remove),
164 .driver = {
165 .name = "amplifier-opa362",
166 .of_match_table = opa362_of_match,
167 .suppress_bind_attrs = true,
168 },
169};
170
171module_platform_driver(opa362_driver);
172
173MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>");
174MODULE_DESCRIPTION("OPA362 analog video amplifier with output/power control");
175MODULE_LICENSE("GPL v2");