it66121 hdmi: update drivers
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / hdmi / chips / cat66121 / cat66121_hdmi.c
1 #include <linux/kernel.h>
2 #include <linux/delay.h>
3 #include <linux/module.h>
4 #include <linux/platform_device.h>
5 #include <linux/interrupt.h>
6 #include <mach/gpio.h>
7 #include <mach/iomux.h>
8 #include <linux/i2c.h>
9 #include "cat66121_hdmi.h"
10
11 struct cat66121_hdmi_pdata *cat66121_hdmi = NULL;
12 struct hdmi *hdmi=NULL;
13
14 extern struct rk_lcdc_device_driver * rk_get_lcdc_drv(char *name);
15 extern void hdmi_register_display_sysfs(struct hdmi *hdmi, struct device *parent);
16 extern void hdmi_unregister_display_sysfs(struct hdmi *hdmi);
17
18 int cat66121_hdmi_register_hdcp_callbacks(void (*hdcp_cb)(void),
19                                          void (*hdcp_irq_cb)(int status),
20                                          int (*hdcp_power_on_cb)(void),
21                                          void (*hdcp_power_off_cb)(void))
22 {
23         hdmi->hdcp_cb = hdcp_cb;
24         hdmi->hdcp_irq_cb = hdcp_irq_cb;
25         hdmi->hdcp_power_on_cb = hdcp_power_on_cb;
26         hdmi->hdcp_power_off_cb = hdcp_power_off_cb;
27         
28         return HDMI_ERROR_SUCESS;
29 }
30
31 #ifdef CONFIG_HAS_EARLYSUSPEND
32 static void hdmi_early_suspend(struct early_suspend *h)
33 {
34         hdmi_dbg(hdmi->dev, "hdmi enter early suspend pwr %d state %d\n", hdmi->pwr_mode, hdmi->state);
35         flush_delayed_work(&hdmi->delay_work);  
36         mutex_lock(&hdmi->enable_mutex);
37         hdmi->suspend = 1;
38         if(!hdmi->enable) {
39                 mutex_unlock(&hdmi->enable_mutex);
40                 return;
41         }
42         
43         #ifdef HDMI_USE_IRQ
44         if(hdmi->irq)
45                 disable_irq(hdmi->irq);
46         #endif
47         
48         mutex_unlock(&hdmi->enable_mutex);
49         hdmi->command = HDMI_CONFIG_ENABLE;
50         init_completion(&hdmi->complete);
51         hdmi->wait = 1;
52         queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, 0);
53         wait_for_completion_interruptible_timeout(&hdmi->complete,
54                                                         msecs_to_jiffies(5000));
55         flush_delayed_work(&hdmi->delay_work);
56         return;
57 }
58
59 static void hdmi_early_resume(struct early_suspend *h)
60 {
61         hdmi_dbg(hdmi->dev, "hdmi exit early resume\n");
62         mutex_lock(&hdmi->enable_mutex);
63         
64         hdmi->suspend = 0;
65         #ifdef HDMI_USE_IRQ
66         if(hdmi->enable && hdmi->irq) {
67                 enable_irq(hdmi->irq);
68         }
69         #else
70         queue_delayed_work(cat66121_hdmi->workqueue, &cat66121_hdmi->delay_work, 100);
71         #endif
72         queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10));   
73         mutex_unlock(&hdmi->enable_mutex);
74         return;
75 }
76 #endif
77
78 static void cat66121_irq_work_func(struct work_struct *work)
79 {
80         if(hdmi->suspend == 0) {
81                 if(hdmi->enable == 1) {
82                         cat66121_hdmi_interrupt();
83                         if(hdmi->hdcp_irq_cb)
84                                 hdmi->hdcp_irq_cb(0);
85                 }
86                 #ifndef HDMI_USE_IRQ
87                 queue_delayed_work(cat66121_hdmi->workqueue, &cat66121_hdmi->delay_work, 100);
88                 #endif
89         }
90 }
91
92 #ifdef HDMI_USE_IRQ
93 static irqreturn_t cat66121_irq(int irq, void *dev_id)
94 {
95         printk(KERN_INFO "cat66121 irq triggered.\n");
96         schedule_work(&cat66121_hdmi->irq_work);
97     return IRQ_HANDLED;
98 }
99 #endif
100 #ifdef HDMI_DEBUG
101 static int hdmi_read_p0_reg(struct i2c_client *client, char reg, char *val)
102 {
103         return i2c_master_reg8_recv(client, reg, val, 1, 100*1000) > 0? 0: -EINVAL;
104 }
105
106 static int hdmi_write_p0_reg(struct i2c_client *client, char reg, char *val)
107 {
108         return i2c_master_reg8_send(client, reg, val, 1, 100*1000) > 0? 0: -EINVAL;
109 }
110 static ssize_t hdmi_show_reg_attrs(struct device *dev,
111                                               struct device_attribute *attr,
112                                               char *buf)
113 {
114
115         int i,size=0;
116         char val;
117         struct i2c_client *client=cat66121_hdmi->client;
118
119         for(i=0;i<256;i++)
120         {
121                 hdmi_read_p0_reg(client, i,  &val);
122                 if(i%16==0)
123                         size += sprintf(buf+size,"\n>>>hdmi_hdmi %x:",i);
124                 size += sprintf(buf+size," %2x",val);
125         }
126
127         return size;
128 }
129 static ssize_t hdmi_store_reg_attrs(struct device *dev,
130                                                 struct device_attribute *attr,
131                                                 const char *buf, size_t size)
132 {
133         struct i2c_client *client=NULL;
134         static char val=0,reg=0;
135         client = cat66121_hdmi->client;
136         printk("/**********hdmi reg config******/");
137
138         sscanf(buf, "%x%x", &val,&reg);
139         hdmi_write_p0_reg(client, reg,  &val);
140         return size;
141 }
142
143 static struct device_attribute hdmi_attrs[] = {
144         __ATTR(reg_ctl, 0777,hdmi_show_reg_attrs,hdmi_store_reg_attrs),
145 };
146 #endif
147 static int cat66121_hdmi_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id)
148 {
149     int rc = 0;
150         struct rk_hdmi_platform_data *pdata = client->dev.platform_data;
151         
152         cat66121_hdmi = kzalloc(sizeof(struct cat66121_hdmi_pdata), GFP_KERNEL);
153         if(!cat66121_hdmi)
154         {
155         dev_err(&client->dev, "no memory for state\n");
156         return -ENOMEM;
157     }
158         cat66121_hdmi->client = client;
159         i2c_set_clientdata(client, cat66121_hdmi);
160         
161         hdmi = kmalloc(sizeof(struct hdmi), GFP_KERNEL);
162         if(!hdmi)
163         {
164         dev_err(&client->dev, "cat66121 hdmi kmalloc fail!");
165         goto err_kzalloc_hdmi;
166         }
167         memset(hdmi, 0, sizeof(struct hdmi));
168         hdmi->dev = &client->dev;
169         
170         if(HDMI_SOURCE_DEFAULT == HDMI_SOURCE_LCDC0)
171                 hdmi->lcdc = rk_get_lcdc_drv("lcdc0");
172         else
173                 hdmi->lcdc = rk_get_lcdc_drv("lcdc1");
174         if(hdmi->lcdc == NULL)
175         {
176                 dev_err(hdmi->dev, "can not connect to video source lcdc\n");
177                 rc = -ENXIO;
178                 goto err_request_lcdc;
179         }
180         if(cat66121_detect_device()!=1){
181                 dev_err(hdmi->dev, "can't find it6610 device \n");
182                 rc = -ENXIO;
183                 goto err_request_lcdc;
184         }
185
186         hdmi->xscale = 100;
187         hdmi->yscale = 100;
188         hdmi->insert = cat66121_hdmi_sys_insert;
189         hdmi->remove = cat66121_hdmi_sys_remove;
190         hdmi->control_output = cat66121_hdmi_sys_enalbe_output;
191         hdmi->config_video = cat66121_hdmi_sys_config_video;
192         hdmi->config_audio = cat66121_hdmi_sys_config_audio;
193         hdmi->detect_hotplug = cat66121_hdmi_sys_detect_hpd;
194         hdmi->read_edid = cat66121_hdmi_sys_read_edid;
195         hdmi_sys_init();
196         
197         hdmi->workqueue = create_singlethread_workqueue("hdmi");
198         INIT_DELAYED_WORK(&(hdmi->delay_work), hdmi_work);
199         
200         #ifdef CONFIG_HAS_EARLYSUSPEND
201         hdmi->early_suspend.suspend = hdmi_early_suspend;
202         hdmi->early_suspend.resume = hdmi_early_resume;
203         hdmi->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 10;
204         register_early_suspend(&hdmi->early_suspend);
205         #endif
206         
207         hdmi_register_display_sysfs(hdmi, NULL);
208         #ifdef CONFIG_SWITCH
209         hdmi->switch_hdmi.name="hdmi";
210         switch_dev_register(&(hdmi->switch_hdmi));
211         #endif
212                 
213         spin_lock_init(&hdmi->irq_lock);
214         mutex_init(&hdmi->enable_mutex);
215         
216         if(pdata->io_init){
217                 if(pdata->io_init()<0){
218                         dev_err(&client->dev, "fail to rst chip\n");
219                         goto err_request_lcdc;
220                 }
221         }
222         cat66121_hdmi_sys_init();
223 #ifdef HDMI_USE_IRQ
224         if(client->irq != INVALID_GPIO) {
225                 INIT_WORK(&cat66121_hdmi->irq_work, cat66121_irq_work_func);
226                 schedule_work(&cat66121_hdmi->irq_work);
227                 if((rc = gpio_request(client->irq, "hdmi gpio")) < 0)
228             {
229                 dev_err(&client->dev, "fail to request gpio %d\n", client->irq);
230                 goto err_request_lcdc;
231             }
232             hdmi->irq = gpio_to_irq(client->irq);
233                 cat66121_hdmi->gpio = client->irq;
234             gpio_pull_updown(client->irq, GPIOPullUp);
235             gpio_direction_input(client->irq);
236             if((rc = request_irq(hdmi->irq, cat66121_irq, IRQF_TRIGGER_RISING, NULL, hdmi)) < 0)
237             {
238                 dev_err(&client->dev, "fail to request hdmi irq\n");
239                 goto err_request_irq;
240             }
241         }
242         else
243 #else
244         {
245                 cat66121_hdmi->workqueue = create_singlethread_workqueue("cat66121 irq");
246                 INIT_DELAYED_WORK(&(cat66121_hdmi->delay_work), cat66121_irq_work_func);
247                 cat66121_irq_work_func(NULL);
248         }
249 #endif
250
251 #ifdef HDMI_DEBUG
252         device_create_file(&(client->dev), &hdmi_attrs[0]);
253 #endif
254         dev_info(&client->dev, "cat66121 hdmi i2c probe ok\n");
255         
256     return 0;
257         
258 err_request_irq:
259         gpio_free(client->irq);
260 err_request_lcdc:
261         kfree(hdmi);
262         hdmi = NULL;
263 err_kzalloc_hdmi:
264         kfree(cat66121_hdmi);
265         cat66121_hdmi = NULL;
266         dev_err(&client->dev, "cat66121 hdmi probe error\n");
267         return rc;
268
269 }
270
271 static int __devexit cat66121_hdmi_i2c_remove(struct i2c_client *client)
272 {       
273         hdmi_dbg(hdmi->dev, "%s\n", __func__);
274         if(hdmi) {
275                 mutex_lock(&hdmi->enable_mutex);
276                 if(!hdmi->suspend && hdmi->enable && hdmi->irq)
277                         disable_irq(hdmi->irq);
278                 mutex_unlock(&hdmi->enable_mutex);
279                 if(hdmi->irq)
280                         free_irq(hdmi->irq, NULL);
281                 flush_workqueue(hdmi->workqueue);
282                 destroy_workqueue(hdmi->workqueue);
283                 #ifdef CONFIG_SWITCH
284                 switch_dev_unregister(&(hdmi->switch_hdmi));
285                 #endif
286                 hdmi_unregister_display_sysfs(hdmi);
287                 #ifdef CONFIG_HAS_EARLYSUSPEND
288                 unregister_early_suspend(&hdmi->early_suspend);
289                 #endif
290                 fb_destroy_modelist(&hdmi->edid.modelist);
291                 if(hdmi->edid.audio)
292                         kfree(hdmi->edid.audio);
293                 if(hdmi->edid.specs)
294                 {
295                         if(hdmi->edid.specs->modedb)
296                                 kfree(hdmi->edid.specs->modedb);
297                         kfree(hdmi->edid.specs);
298                 }
299                 kfree(hdmi);
300                 hdmi = NULL;
301         }
302     return 0;
303 }
304
305 static void cat66121_hdmi_i2c_shutdown(struct i2c_client *client)
306 {
307         if(hdmi) {
308                 #ifdef CONFIG_HAS_EARLYSUSPEND
309                 unregister_early_suspend(&hdmi->early_suspend);
310                 #endif
311         }
312         printk(KERN_INFO "cat66121 hdmi shut down.\n");
313 }
314
315 static const struct i2c_device_id cat66121_hdmi_id[] = {
316         { "cat66121_hdmi", 0 },
317         { }
318 };
319
320 static struct i2c_driver cat66121_hdmi_i2c_driver = {
321     .driver = {
322         .name  = "cat66121_hdmi",
323         .owner = THIS_MODULE,
324     },
325     .probe      = cat66121_hdmi_i2c_probe,
326     .remove     = cat66121_hdmi_i2c_remove,
327     .shutdown   = cat66121_hdmi_i2c_shutdown,
328     .id_table   = cat66121_hdmi_id,
329 };
330
331 static int __init cat66121_hdmi_init(void)
332 {
333     return i2c_add_driver(&cat66121_hdmi_i2c_driver);
334 }
335
336 static void __exit cat66121_hdmi_exit(void)
337 {
338     i2c_del_driver(&cat66121_hdmi_i2c_driver);
339 }
340
341 //module_init(cat66121_hdmi_init);
342 device_initcall_sync(cat66121_hdmi_init);
343 module_exit(cat66121_hdmi_exit);