1 /* 2 * Copyright (C) 2012 Texas Instruments Ltd 3 * Author: Archit Taneja <archit@ti.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include <linux/kernel.h> 19 #include <linux/module.h> 20 #include <linux/platform_device.h> 21 #include <linux/slab.h> 22 #include <linux/of.h> 23 24 #include <video/omapfb_dss.h> 25 26 #include "dss.h" 27 28 static LIST_HEAD(output_list); 29 static DEFINE_MUTEX(output_lock); 30 31 int omapdss_output_set_device(struct omap_dss_device *out, 32 struct omap_dss_device *dssdev) 33 { 34 int r; 35 36 mutex_lock(&output_lock); 37 38 if (out->dst) { 39 DSSERR("output already has device %s connected to it\n", 40 out->dst->name); 41 r = -EINVAL; 42 goto err; 43 } 44 45 if (out->output_type != dssdev->type) { 46 DSSERR("output type and display type don't match\n"); 47 r = -EINVAL; 48 goto err; 49 } 50 51 out->dst = dssdev; 52 dssdev->src = out; 53 54 mutex_unlock(&output_lock); 55 56 return 0; 57 err: 58 mutex_unlock(&output_lock); 59 60 return r; 61 } 62 EXPORT_SYMBOL(omapdss_output_set_device); 63 64 int omapdss_output_unset_device(struct omap_dss_device *out) 65 { 66 int r; 67 68 mutex_lock(&output_lock); 69 70 if (!out->dst) { 71 DSSERR("output doesn't have a device connected to it\n"); 72 r = -EINVAL; 73 goto err; 74 } 75 76 if (out->dst->state != OMAP_DSS_DISPLAY_DISABLED) { 77 DSSERR("device %s is not disabled, cannot unset device\n", 78 out->dst->name); 79 r = -EINVAL; 80 goto err; 81 } 82 83 out->dst->src = NULL; 84 out->dst = NULL; 85 86 mutex_unlock(&output_lock); 87 88 return 0; 89 err: 90 mutex_unlock(&output_lock); 91 92 return r; 93 } 94 EXPORT_SYMBOL(omapdss_output_unset_device); 95 96 int omapdss_register_output(struct omap_dss_device *out) 97 { 98 list_add_tail(&out->list, &output_list); 99 return 0; 100 } 101 EXPORT_SYMBOL(omapdss_register_output); 102 103 void omapdss_unregister_output(struct omap_dss_device *out) 104 { 105 list_del(&out->list); 106 } 107 EXPORT_SYMBOL(omapdss_unregister_output); 108 109 struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id) 110 { 111 struct omap_dss_device *out; 112 113 list_for_each_entry(out, &output_list, list) { 114 if (out->id == id) 115 return out; 116 } 117 118 return NULL; 119 } 120 EXPORT_SYMBOL(omap_dss_get_output); 121 122 struct omap_dss_device *omap_dss_find_output(const char *name) 123 { 124 struct omap_dss_device *out; 125 126 list_for_each_entry(out, &output_list, list) { 127 if (strcmp(out->name, name) == 0) 128 return omap_dss_get_device(out); 129 } 130 131 return NULL; 132 } 133 EXPORT_SYMBOL(omap_dss_find_output); 134 135 struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port) 136 { 137 struct device_node *src_node; 138 struct omap_dss_device *out; 139 u32 reg; 140 141 src_node = dss_of_port_get_parent_device(port); 142 if (!src_node) 143 return NULL; 144 145 reg = dss_of_port_get_port_number(port); 146 147 list_for_each_entry(out, &output_list, list) { 148 if (out->dev->of_node == src_node && out->port_num == reg) { 149 of_node_put(src_node); 150 return omap_dss_get_device(out); 151 } 152 } 153 154 of_node_put(src_node); 155 156 return NULL; 157 } 158 EXPORT_SYMBOL(omap_dss_find_output_by_port_node); 159 160 struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev) 161 { 162 while (dssdev->src) 163 dssdev = dssdev->src; 164 165 if (dssdev->id != 0) 166 return omap_dss_get_device(dssdev); 167 168 return NULL; 169 } 170 EXPORT_SYMBOL(omapdss_find_output_from_display); 171 172 struct omap_overlay_manager *omapdss_find_mgr_from_display(struct omap_dss_device *dssdev) 173 { 174 struct omap_dss_device *out; 175 struct omap_overlay_manager *mgr; 176 177 out = omapdss_find_output_from_display(dssdev); 178 179 if (out == NULL) 180 return NULL; 181 182 mgr = out->manager; 183 184 omap_dss_put_device(out); 185 186 return mgr; 187 } 188 EXPORT_SYMBOL(omapdss_find_mgr_from_display); 189 190 static const struct dss_mgr_ops *dss_mgr_ops; 191 192 int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops) 193 { 194 if (dss_mgr_ops) 195 return -EBUSY; 196 197 dss_mgr_ops = mgr_ops; 198 199 return 0; 200 } 201 EXPORT_SYMBOL(dss_install_mgr_ops); 202 203 void dss_uninstall_mgr_ops(void) 204 { 205 dss_mgr_ops = NULL; 206 } 207 EXPORT_SYMBOL(dss_uninstall_mgr_ops); 208 209 int dss_mgr_connect(struct omap_overlay_manager *mgr, 210 struct omap_dss_device *dst) 211 { 212 return dss_mgr_ops->connect(mgr, dst); 213 } 214 EXPORT_SYMBOL(dss_mgr_connect); 215 216 void dss_mgr_disconnect(struct omap_overlay_manager *mgr, 217 struct omap_dss_device *dst) 218 { 219 dss_mgr_ops->disconnect(mgr, dst); 220 } 221 EXPORT_SYMBOL(dss_mgr_disconnect); 222 223 void dss_mgr_set_timings(struct omap_overlay_manager *mgr, 224 const struct omap_video_timings *timings) 225 { 226 dss_mgr_ops->set_timings(mgr, timings); 227 } 228 EXPORT_SYMBOL(dss_mgr_set_timings); 229 230 void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, 231 const struct dss_lcd_mgr_config *config) 232 { 233 dss_mgr_ops->set_lcd_config(mgr, config); 234 } 235 EXPORT_SYMBOL(dss_mgr_set_lcd_config); 236 237 int dss_mgr_enable(struct omap_overlay_manager *mgr) 238 { 239 return dss_mgr_ops->enable(mgr); 240 } 241 EXPORT_SYMBOL(dss_mgr_enable); 242 243 void dss_mgr_disable(struct omap_overlay_manager *mgr) 244 { 245 dss_mgr_ops->disable(mgr); 246 } 247 EXPORT_SYMBOL(dss_mgr_disable); 248 249 void dss_mgr_start_update(struct omap_overlay_manager *mgr) 250 { 251 dss_mgr_ops->start_update(mgr); 252 } 253 EXPORT_SYMBOL(dss_mgr_start_update); 254 255 int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr, 256 void (*handler)(void *), void *data) 257 { 258 return dss_mgr_ops->register_framedone_handler(mgr, handler, data); 259 } 260 EXPORT_SYMBOL(dss_mgr_register_framedone_handler); 261 262 void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr, 263 void (*handler)(void *), void *data) 264 { 265 dss_mgr_ops->unregister_framedone_handler(mgr, handler, data); 266 } 267 EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler); 268