add hdmi chips's(anx7150) vdd control
[firefly-linux-kernel-4.4.55.git] / drivers / video / hdmi / hdmi-core.c
1 #include <linux/kernel.h>\r
2 #include <linux/delay.h>\r
3 #include <linux/module.h>\r
4 #include <linux/err.h>\r
5 \r
6 #include <linux/hdmi.h>\r
7 #include <linux/input.h>\r
8 \r
9 \r
10 struct class *hdmi_class;\r
11 struct hdmi_id_ref_info {\r
12         struct hdmi *hdmi;\r
13         int id;\r
14         int ref;\r
15 }ref_info[HDMI_MAX_ID];\r
16 #ifdef CONFIG_SYSFS\r
17 \r
18 extern int hdmi_create_attrs(struct hdmi *hdmi);\r
19 extern void hdmi_remove_attrs(struct hdmi *hdmi);\r
20 \r
21 #else\r
22 \r
23 static inline int hdmi_create_attrs(struct hdmi *hdmi)\r
24 { return 0; }\r
25 static inline void hdmi_remove_attrs(struct hdmi *hdmi) {}\r
26 \r
27 #endif /* CONFIG_SYSFS */\r
28 static void __hdmi_changed(struct hdmi *hdmi)\r
29 {\r
30         int precent;\r
31         \r
32         mutex_lock(&hdmi->lock);\r
33         precent = hdmi->ops->hdmi_precent(hdmi);\r
34 \r
35         if(precent && hdmi->mode == DISP_ON_LCD && hdmi->display_on){\r
36                 if(hdmi->ops->insert(hdmi) == 0){\r
37                         hdmi->mode = DISP_ON_HDMI;\r
38                         kobject_uevent(&hdmi->dev->kobj, KOBJ_CHANGE);\r
39                 }\r
40                 else\r
41                         hdmi_dbg(hdmi->dev, "insert error\n");\r
42         }\r
43         else if((!precent || !hdmi->display_on) && hdmi->mode == DISP_ON_HDMI){\r
44                 if(hdmi->ops->remove(hdmi) == 0){\r
45                         hdmi->mode = DISP_ON_LCD;\r
46                         kobject_uevent(&hdmi->dev->kobj, KOBJ_CHANGE);\r
47                 }\r
48                 else\r
49                         hdmi_dbg(hdmi->dev, "remove error\n");\r
50         }\r
51         mutex_unlock(&hdmi->lock);\r
52         return;\r
53 }\r
54 \r
55 void hdmi_changed(struct hdmi *hdmi, int msec)\r
56 {       \r
57         schedule_delayed_work(&hdmi->work, msecs_to_jiffies(msec));\r
58         return;\r
59 }\r
60 void hdmi_suspend(struct hdmi *hdmi)\r
61 {\r
62         del_timer(&hdmi->timer);\r
63         flush_delayed_work(&hdmi->work);\r
64         if(hdmi->mode == DISP_ON_HDMI){\r
65                 hdmi->ops->remove(hdmi);\r
66                 hdmi->mode = DISP_ON_LCD;\r
67         }\r
68         return;\r
69 }\r
70 void hdmi_resume(struct hdmi *hdmi)\r
71 {\r
72         mod_timer(&hdmi->timer, jiffies + msecs_to_jiffies(10));\r
73         return;\r
74 }\r
75 \r
76 static void hdmi_changed_work(struct work_struct *work)\r
77 {\r
78         struct hdmi *hdmi = container_of(work, struct hdmi,\r
79                                                 work.work);\r
80         \r
81         __hdmi_changed(hdmi);\r
82         return;\r
83 }\r
84 \r
85 void *hdmi_priv(struct hdmi *hdmi)\r
86 {\r
87         return (void *)hdmi->priv;\r
88 }\r
89 static void hdmi_detect_timer(unsigned long data)\r
90 {\r
91         struct hdmi *hdmi = (struct hdmi*)data;\r
92         \r
93         int precent =  hdmi->ops->hdmi_precent(hdmi);\r
94 \r
95         if((precent && hdmi->mode == DISP_ON_LCD) ||\r
96                         (!precent && hdmi->mode == DISP_ON_HDMI))\r
97                 hdmi_changed(hdmi, 100);\r
98         mod_timer(&hdmi->timer, jiffies + msecs_to_jiffies(200));\r
99 }\r
100 struct hdmi *hdmi_register(int extra, struct device *parent)\r
101 {\r
102         int rc = 0, i;\r
103         char name[8];\r
104         struct hdmi *hdmi = kzalloc(sizeof(struct hdmi)+ extra, GFP_KERNEL);\r
105 \r
106         if(!hdmi)\r
107                 return NULL;\r
108         for(i = 0; i < HDMI_MAX_ID; i++) \r
109         {\r
110                 if(ref_info[i].ref == 0)\r
111                 {\r
112                         ref_info[i].ref = 1;\r
113                         hdmi->id = i;\r
114                         break;\r
115                 }\r
116         }\r
117         if(i == HDMI_MAX_ID)\r
118         {\r
119                 kfree(hdmi);\r
120                 return NULL;\r
121         }\r
122         sprintf(name, "hdmi-%d", hdmi->id);\r
123         \r
124         hdmi->dev = device_create(hdmi_class, parent, 0,\r
125                                  "%s", name);\r
126         if (IS_ERR(hdmi->dev)) {\r
127                 rc = PTR_ERR(hdmi->dev);\r
128                 goto dev_create_failed;\r
129         }\r
130 \r
131         dev_set_drvdata(hdmi->dev, hdmi);\r
132         ref_info[i].hdmi = hdmi;\r
133 \r
134         INIT_DELAYED_WORK(&hdmi->work, hdmi_changed_work);\r
135 \r
136         rc = hdmi_create_attrs(hdmi);\r
137         if (rc)\r
138                 goto create_attrs_failed;\r
139 \r
140         goto success;\r
141 \r
142 create_attrs_failed:\r
143         device_unregister(hdmi->dev);\r
144 dev_create_failed:\r
145         hdmi_remove_attrs(hdmi);\r
146         kfree(hdmi);\r
147         return NULL;\r
148 success:\r
149         mutex_init(&hdmi->lock);\r
150         setup_timer(&hdmi->timer, hdmi_detect_timer,(unsigned long)hdmi);\r
151         mod_timer(&hdmi->timer, jiffies + msecs_to_jiffies(200));\r
152         return hdmi;\r
153 }\r
154 void hdmi_unregister(struct hdmi *hdmi)\r
155 {\r
156         int id;\r
157 \r
158         if(!hdmi)\r
159                 return;\r
160         id = hdmi->id;\r
161         del_timer(&hdmi->timer);\r
162         flush_scheduled_work();\r
163         hdmi_remove_attrs(hdmi);\r
164         device_unregister(hdmi->dev);\r
165 \r
166         kfree(hdmi);\r
167         hdmi = NULL;\r
168         ref_info[id].ref = 0;\r
169         ref_info[id].hdmi = NULL;\r
170 }\r
171 struct hdmi *get_hdmi_struct(int nr)\r
172 {\r
173         if(ref_info[nr].ref == 0)\r
174                 return NULL;\r
175         else\r
176                 return ref_info[nr].hdmi;\r
177 }\r
178 int hdmi_is_insert(void)\r
179 {\r
180         struct hdmi *hdmi = get_hdmi_struct(0);\r
181 \r
182         if(hdmi && hdmi->ops && hdmi->ops->hdmi_precent)\r
183                 return hdmi->ops->hdmi_precent(hdmi);\r
184         else\r
185                 return 0;\r
186 }\r
187 int hdmi_get_scale(void)\r
188 {\r
189         struct hdmi* hdmi = get_hdmi_struct(0);\r
190         if(!hdmi)\r
191                 return 100;\r
192         else\r
193                 return hdmi->scale;\r
194 }\r
195 \r
196 int hdmi_set_scale(int event, char *data, int len)\r
197 {\r
198         int result;\r
199         struct hdmi* hdmi = get_hdmi_struct(0);\r
200 \r
201         if(!hdmi)\r
202                 return -1;\r
203         if(len != 4)\r
204                 return -1;\r
205         if(fb_get_video_mode() || hdmi->mode == DISP_ON_LCD)\r
206                 return -1;\r
207 \r
208         result = data[0] | data[1]<<1 | data[2]<<2;\r
209         if(event != MOUSE_NONE && (result & event) != event)\r
210                 return -1;\r
211 \r
212         hdmi->scale += data[3];\r
213         \r
214         hdmi->scale = (hdmi->scale>100)?100:hdmi->scale;\r
215         hdmi->scale = (hdmi->scale<MIN_SCALE)?MIN_SCALE:hdmi->scale;\r
216         return 0;       \r
217 }\r
218 \r
219 static int __init hdmi_class_init(void)\r
220 {\r
221         int i;\r
222         \r
223         hdmi_class = class_create(THIS_MODULE, "hdmi");\r
224 \r
225         if (IS_ERR(hdmi_class))\r
226                 return PTR_ERR(hdmi_class);\r
227         for(i = 0; i < HDMI_MAX_ID; i++) {\r
228                 ref_info[i].id = i;\r
229                 ref_info[i].ref = 0;\r
230                 ref_info[i].hdmi = NULL;\r
231         }\r
232         return 0;\r
233 }\r
234 \r
235 static void __exit hdmi_class_exit(void)\r
236 {\r
237         class_destroy(hdmi_class);\r
238 }\r
239 EXPORT_SYMBOL(hdmi_changed);\r
240 EXPORT_SYMBOL(hdmi_register);\r
241 EXPORT_SYMBOL(hdmi_unregister);\r
242 EXPORT_SYMBOL(get_hdmi_struct);\r
243 \r
244 subsys_initcall(hdmi_class_init);\r
245 module_exit(hdmi_class_exit);\r
246 \r