72b29189e941d97f2378cfdec12b015a616b4973
[firefly-linux-kernel-4.4.55.git] / drivers / video / hdmi / chips / rk610 / rk610_hdmi.c
1 #include <linux/kernel.h>\r
2 #include <linux/delay.h>\r
3 #include <linux/module.h>\r
4 #include <linux/platform_device.h>\r
5 #include <linux/hdmi.h>\r
6 #include <linux/i2c.h>\r
7 #include <linux/interrupt.h>\r
8 #include <mach/gpio.h>\r
9 #include <mach/iomux.h>\r
10 #include <mach/board.h>\r
11 #include <linux/irq.h>\r
12 \r
13 #include <linux/mfd/rk610_core.h>\r
14 #include "rk610_hdmi.h"\r
15 #include "rk610_hdmi_hw.h"\r
16 \r
17 \r
18 struct i2c_client *rk610_g_hdmi_client=NULL;\r
19 static bool hpd=0;\r
20 \r
21 static void rk610_handler(struct work_struct *work)\r
22 {\r
23         struct i2c_client *client = rk610_g_hdmi_client;\r
24         if(client==NULL){\r
25         printk(">>> %s client==NULL\n",__func__);\r
26         }\r
27         Rk610_hdmi_event_work(client,&hpd);\r
28 }\r
29 \r
30 static DECLARE_DELAYED_WORK(rk610_irq_work, rk610_handler);\r
31 static int rk610_hdmi_precent(struct hdmi *hdmi)\r
32 {\r
33     //struct rk610_hdmi_inf *rk610_hdmi = hdmi_priv(hdmi);\r
34     schedule_delayed_work(&rk610_irq_work, msecs_to_jiffies(30));\r
35     return hpd;\r
36 }\r
37 \r
38 static int rk610_hdmi_param_chg(struct rk610_hdmi_inf *rk610_hdmi)\r
39 {\r
40     int resolution_real;\r
41     RK610_DBG(&rk610_hdmi->client->dev,"%s \n",__FUNCTION__);\r
42     resolution_real = Rk610_Get_Optimal_resolution(rk610_hdmi->hdmi->resolution);\r
43     rk610_hdmi->hdmi->resolution = resolution_real;\r
44         hdmi_switch_fb(rk610_hdmi->hdmi, rk610_hdmi->hdmi->display_on);\r
45         Rk610_hdmi_Set_Video(rk610_hdmi->hdmi->resolution);\r
46     Rk610_hdmi_Set_Audio(rk610_hdmi->hdmi->audio_fs);\r
47     Rk610_hdmi_Config_Done(rk610_hdmi->client);\r
48         return 0;\r
49 }\r
50 \r
51 static int rk610_hdmi_set_param(struct hdmi *hdmi)\r
52 {\r
53         struct rk610_hdmi_inf *rk610_hdmi = hdmi_priv(hdmi);\r
54         RK610_DBG(&rk610_hdmi->client->dev,"%s \n",__FUNCTION__);\r
55         if(rk610_hdmi->init == 1)\r
56                 return 0;\r
57 \r
58         rk610_hdmi_param_chg(rk610_hdmi);\r
59         return 0;\r
60 }\r
61 static int rk610_hdmi_insert(struct hdmi *hdmi)\r
62 {\r
63         struct rk610_hdmi_inf *rk610_hdmi = hdmi_priv(hdmi);\r
64     RK610_DBG(&rk610_hdmi->client->dev,"%s \n",__FUNCTION__);\r
65         if(rk610_hdmi->init == 1)\r
66                 return -1;\r
67         rk610_hdmi_param_chg(rk610_hdmi);\r
68     hdmi_set_spk(HDMI_DISABLE);\r
69     printk("rk610_hdmi_insert hdmi->display_on=%d\n",hdmi->display_on);\r
70         hdmi->scale = hdmi->scale_set;\r
71         return 0;\r
72 }\r
73 static int rk610_hdmi_remove(struct hdmi *hdmi)\r
74 {\r
75         struct rk610_hdmi_inf *rk610_hdmi = hdmi_priv(hdmi);\r
76     RK610_DBG(&rk610_hdmi->client->dev,"%s \n",__FUNCTION__);\r
77         if(rk610_hdmi->init == 1)\r
78                 return -1;\r
79         hdmi_set_spk(HDMI_ENABLE);\r
80         hdmi_switch_fb(hdmi, HDMI_DISABLE);\r
81         printk("rk610_hdmi_remove hdmi->display_on=%d\n",hdmi->display_on);\r
82         return 0;\r
83 }\r
84 #ifdef CONFIG_HAS_EARLYSUSPEND\r
85 static void rk610_hdmi_early_suspend(struct early_suspend *h)\r
86 {\r
87         struct rk610_hdmi_inf *rk610_hdmi = container_of(h,\r
88                                                         struct rk610_hdmi_inf,\r
89                                                         early_suspend);\r
90         printk( "rk610_hdmi enter early suspend\n");\r
91         hdmi_suspend(rk610_hdmi->hdmi);\r
92         Rk610_hdmi_suspend(rk610_hdmi->client);\r
93         return;\r
94 }\r
95 \r
96 static void rk610_hdmi_early_resume(struct early_suspend *h)\r
97 {\r
98         struct rk610_hdmi_inf *rk610_hdmi = container_of(h,\r
99                                                         struct rk610_hdmi_inf,\r
100                                                         early_suspend);\r
101         printk("rk610_hdmi exit early suspend\n");\r
102         hdmi_resume(rk610_hdmi->hdmi);\r
103         Rk610_hdmi_resume(rk610_hdmi->client);\r
104         return;\r
105 }\r
106 #endif\r
107  \r
108 static int rk610_hdmi_init(struct hdmi *hdmi)\r
109 {\r
110         struct rk610_hdmi_inf *rk610_hdmi = hdmi_priv(hdmi);\r
111 #ifdef CONFIG_HDMI_SAVE_DATA\r
112     int hdmi_data = hdmi_get_data();\r
113     if(hdmi_data<0){\r
114     hdmi_set_data((hdmi->resolution&0x7)|((hdmi->scale&0x1f)<<3));\r
115     }\r
116     else{\r
117     hdmi->resolution = hdmi_data&0x7;\r
118     hdmi->scale_set= ((hdmi_data>>3)&0x1f) + MIN_SCALE;\r
119     hdmi->scale = hdmi->scale_set;\r
120     }\r
121 #endif  \r
122         RK610_DBG(&rk610_hdmi->client->dev,"%s \n",__FUNCTION__);\r
123         rk610_hdmi->init =0;\r
124         Rk610_hdmi_init(rk610_hdmi->client);\r
125     hdmi_changed(hdmi,1);\r
126         Rk610_hdmi_Set_Video(hdmi->resolution);\r
127         Rk610_hdmi_Set_Audio(hdmi->audio_fs);\r
128     Rk610_hdmi_Config_Done(rk610_hdmi->client);\r
129         return 0;\r
130 }\r
131 static struct hdmi_ops rk610_hdmi_ops = {\r
132         .set_param = rk610_hdmi_set_param,\r
133         .hdmi_precent = rk610_hdmi_precent,\r
134         .insert = rk610_hdmi_insert,\r
135         .remove = rk610_hdmi_remove,\r
136         .init = rk610_hdmi_init,\r
137 };\r
138 #ifdef RK610_DEBUG\r
139 static int rk610_read_p0_reg(struct i2c_client *client, char reg, char *val)
140 {
141         return i2c_master_reg8_recv(client, reg, val, 1, 100*1000) > 0? 0: -EINVAL;
142 }
143
144 static int rk610_write_p0_reg(struct i2c_client *client, char reg, char *val)
145 {
146         return i2c_master_reg8_send(client, reg, val, 1, 100*1000) > 0? 0: -EINVAL;
147 }
148 static ssize_t rk610_show_reg_attrs(struct device *dev,
149                                               struct device_attribute *attr,
150                                               char *buf)
151 {
152
153         int i,size=0;
154         char val;
155         struct i2c_client *client=rk610_g_hdmi_client;\r
156
157         for(i=0;i<256;i++)
158         {
159                 rk610_read_p0_reg(client, i,  &val);
160                 if(i%16==0)
161                         size += sprintf(buf+size,"\n>>>rk610_hdmi %x:",i);
162                 size += sprintf(buf+size," %2x",val);
163         }
164
165         return size;
166 }
167 static ssize_t rk610_store_reg_attrs(struct device *dev,
168                                                 struct device_attribute *attr,
169                                                 const char *buf, size_t size)
170 {
171         struct i2c_client *client=NULL;
172         static char val=0,reg=0;
173         client = rk610_g_hdmi_client;\r
174         RK610_DBG(&client->dev,"/**********rk610 reg config******/");\r
175
176         sscanf(buf, "%x%x", &val,&reg);
177         RK610_DBG(&client->dev,"reg=%x val=%x\n",reg,val);\r
178         rk610_write_p0_reg(client, reg,  &val);
179         RK610_DBG(&client->dev,"val=%x\n",val);\r
180         return size;
181 }
182
183 static struct device_attribute rk610_attrs[] = {
184         __ATTR(reg_ctl, 0777,rk610_show_reg_attrs,rk610_store_reg_attrs),
185 };
186 #endif\r
187 #if 0\r
188 static irqreturn_t rk610_hdmi_interrupt(int irq, void *dev_id)\r
189 {\r
190     struct hdmi *hdmi = (struct hdmi *)dev_id;\r
191         unsigned long lock_flags = 0;\r
192         printk("The rk610_hdmi interrupt handeler is working..\n");\r
193         return IRQ_HANDLED;\r
194 }\r
195 #endif\r
196 \r
197 static int      rk610_hdmi_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id)\r
198 {\r
199     int ret = 0;\r
200         struct hdmi *hdmi = NULL;\r
201         struct rk610_hdmi_inf *rk610_hdmi = NULL;\r
202 \r
203         struct hdmi_platform_data *pdata = client->dev.platform_data;\r
204         rk610_g_hdmi_client = client;\r
205         if(pdata && pdata->io_init)\r
206         {\r
207                 printk("rk610_hdmi_i2c_probe io_init \n");\r
208                 pdata->io_init();\r
209         }\r
210         hdmi = hdmi_register(sizeof(struct rk610_hdmi_inf), &client->dev);\r
211     if (!hdmi)\r
212     {\r
213         dev_err(&client->dev, "fail to register hdmi\n");\r
214         return -ENOMEM;\r
215     }\r
216         hdmi->ops = &rk610_hdmi_ops;\r
217         hdmi->display_on = HDMI_DEFAULT_MODE;\r
218         hdmi->hdcp_on = HDMI_DISABLE;\r
219         hdmi->audio_fs = HDMI_I2S_DEFAULT_Fs;\r
220         hdmi->resolution = HDMI_DEFAULT_RESOLUTION;\r
221         hdmi->dual_disp = DUAL_DISP_CAP;\r
222         hdmi->mode = DISP_ON_LCD;\r
223         hdmi->scale = 100;\r
224         hdmi->scale_set = 100;\r
225 \r
226         rk610_hdmi = hdmi_priv(hdmi);\r
227         rk610_hdmi->init = 1;\r
228         rk610_hdmi->hdmi = hdmi;\r
229         i2c_set_clientdata(client, rk610_hdmi);\r
230         rk610_hdmi->client = client;\r
231         if((gpio_request(client->irq, "hdmi gpio")) < 0)\r
232             {\r
233                 dev_err(&client->dev, "fail to request gpio %d\n", client->irq);\r
234                 goto err_gpio_free;\r
235             }\r
236     rk610_hdmi->irq = gpio_to_irq(client->irq);\r
237         rk610_hdmi->gpio = client->irq;\r
238 \r
239         gpio_direction_input(client->irq);\r
240         #if 0\r
241         if((ret = request_irq(rk610_hdmi->irq, rk610_hdmi_interrupt, IRQ_TYPE_EDGE_RISING,client->name, hdmi))<0){\r
242         RK610_ERR(&client->dev, "fail to request gpio %d\n", client->irq);\r
243         goto err_gpio_free;\r
244         }\r
245         #endif\r
246 #ifdef CONFIG_HAS_EARLYSUSPEND\r
247         rk610_hdmi->early_suspend.suspend = rk610_hdmi_early_suspend;\r
248         rk610_hdmi->early_suspend.resume = rk610_hdmi_early_resume;\r
249         rk610_hdmi->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 1;\r
250         register_early_suspend(&rk610_hdmi->early_suspend);\r
251 #endif\r
252 #ifdef RK610_DEBUG\r
253         device_create_file(&(client->dev), &rk610_attrs[0]);\r
254 #endif\r
255         rk610_hdmi_init(rk610_hdmi->hdmi);\r
256     dev_info(&client->dev, "rk610_hdmi i2c probe ok\n");\r
257     return 0;\r
258 err_gpio_free:\r
259         gpio_free(client->irq);\r
260 err_hdmi_unregister:\r
261         hdmi_unregister(hdmi);\r
262         rk610_hdmi = NULL;\r
263         return ret;\r
264 }\r
265 \r
266 static int __devexit rk610_hdmi_i2c_remove(struct i2c_client *client)\r
267 {\r
268         struct rk610_hdmi_inf *rk610_hdmi = (struct rk610_hdmi_inf *)i2c_get_clientdata(client);\r
269         struct hdmi *hdmi = rk610_hdmi->hdmi;\r
270 \r
271         gpio_free(client->irq);\r
272         hdmi_unregister(hdmi);\r
273         rk610_hdmi = NULL;\r
274     return 0;\r
275 }\r
276 static const struct i2c_device_id rk610_hdmi_id[] = {\r
277         { "rk610_hdmi", 0 },\r
278         { }\r
279 };\r
280 \r
281 static struct i2c_driver rk610_hdmi_i2c_driver  = {\r
282     .driver = {\r
283         .name  = "rk610_hdmi",\r
284     },\r
285     .probe      = &rk610_hdmi_i2c_probe,\r
286     .remove     = &rk610_hdmi_i2c_remove,\r
287     .id_table   = rk610_hdmi_id,\r
288 };\r
289 \r
290 static int __init rk610_hdmi_module_init(void)\r
291 {\r
292     return i2c_add_driver(&rk610_hdmi_i2c_driver);\r
293 }\r
294 \r
295 static void __exit rk610_hdmi_module_exit(void)\r
296 {\r
297     i2c_del_driver(&rk610_hdmi_i2c_driver);\r
298 }\r
299 \r
300 module_init(rk610_hdmi_module_init);\r
301 //module_init(rk610_hdmi_module_init);\r
302 module_exit(rk610_hdmi_module_exit);\r