usb: dwc3: unregister extcon notify if probe fail
[firefly-linux-kernel-4.4.55.git] / drivers / misc / fm580x.c
1 /*
2  * Copyright (C) 2010 MEMSIC, Inc.
3  *
4  * Initial Code:
5  *      Robbie Cao
6  *      Dale Hou
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21  *
22  */
23
24 #include <linux/kernel.h>
25 #include <linux/init.h>
26 #include <linux/module.h>
27 #include <linux/slab.h>
28 #include <linux/jiffies.h>
29 #include <linux/i2c.h>
30 #include <linux/i2c-dev.h>
31 #include <linux/miscdevice.h>
32 #include <linux/mutex.h>
33 #include <linux/mm.h>
34 #include <linux/device.h>
35 #include <linux/fs.h>
36 #include <linux/delay.h>
37 #include <linux/sysctl.h>
38 #include <asm/uaccess.h>
39 #include <linux/proc_fs.h>
40
41 #include "fm580x.h"
42
43 #if 1
44 #define DBG(x...)       printk(KERN_INFO x)
45 #else
46 #define DBG(x...)
47 #endif
48
49
50 #define FM580X_RETRY_COUNT      3
51
52 #define FM580X_DEV_NAME "fm580x"
53
54 static struct i2c_client *this_client;
55 static uint8_t RDA5807P_REG[8];
56
57 static int fm580x_i2c_rx_data(uint8_t *buf, int len)
58 {
59         uint8_t i;
60         struct i2c_msg msgs[] = {
61                 {
62                         .addr   = this_client->addr,
63                         .flags  = 0,
64                         .len    = 1,
65                         .buf    = buf,
66                         .scl_rate = 200*1000,
67                         .udelay = 100,
68                 },
69                 {
70                         .addr   = this_client->addr,
71                         .flags  = I2C_M_RD,
72                         .len    = len,
73                         .buf    = buf,
74                         .scl_rate = 200*1000,
75                         .udelay = 100,
76                 }
77         };
78
79         for (i = 0; i < FM580X_RETRY_COUNT; i++) {
80         if (i2c_transfer(this_client->adapter, msgs, 2) >= 0) {
81                 break;
82         }
83         mdelay(10);
84         }
85
86         if (i >= FM580X_RETRY_COUNT) {
87                 pr_err("%s: retry over %d\n", __FUNCTION__, FM580X_RETRY_COUNT);
88                 return -EIO;
89         }
90
91         return 0;
92 }
93
94 static int fm580x_i2c_tx_data(uint8_t *buf, int len)
95 {
96         uint8_t i;
97         struct i2c_msg msg[] = {
98                 {
99                         .addr   = this_client->addr,
100                         .flags  = 0,
101                         .len    = len,
102                         .buf    = buf,
103                 }
104         };
105         
106         for (i = 0; i < FM580X_RETRY_COUNT; i++) {
107         if (i2c_transfer(this_client->adapter, msg, 1) >= 0) {
108                 break;
109         }
110         mdelay(10);
111         }
112
113         if (i >= FM580X_RETRY_COUNT) {
114         pr_err("%s: retry over %d\n", __FUNCTION__, FM580X_RETRY_COUNT);
115         return -EIO;
116         }
117         return 0;
118 }
119
120
121 bool fm580x_tuner_init (void)
122 {
123     int error_ind = 0;
124     uint8_t i = 0;
125     uint16_t gChipID;
126
127     RDA5807P_REG[0] = 0x00;
128     RDA5807P_REG[1] = 0x02;
129
130         error_ind = fm580x_i2c_tx_data( (uint8_t *)&RDA5807P_REG[0], 2);
131         mdelay(50);
132     
133     error_ind = fm580x_i2c_rx_data( (uint8_t *)&RDA5807P_REG[0], 8);      
134     gChipID = RDA5807P_REG[6];
135     gChipID = ((gChipID<<8) | RDA5807P_REG[7]);
136
137     if (gChipID == 0x5804)
138     {
139                 for (i=0;i<8;i++)
140                 RDA5807P_REG[i] = RDA5807PE_initialization_reg[i];
141         error_ind = fm580x_i2c_tx_data( (uint8_t *)&RDA5807PE_initialization_reg[0], 2);
142         mdelay(50); 
143             error_ind = fm580x_i2c_tx_data( (uint8_t *)&RDA5807PE_initialization_reg[0],sizeof(RDA5807PE_initialization_reg));
144     }   
145         
146     DBG("%s:RDA5807P_REG[0]=0x%x,RDA5807P_REG[1]=0x%x,ID=0x%x\n",__FUNCTION__,RDA5807P_REG[0],RDA5807P_REG[1],gChipID);
147         
148     return true;
149 }
150
151
152 unsigned short fm580x_tuner_exit (void)
153 {   
154         RDA5807P_REG[1] &= (~1);
155         fm580x_i2c_tx_data( &(RDA5807P_REG[0]), 2);
156 }
157
158 void fm580x_tuner_mute (unsigned short flag)
159 {
160    if(flag)
161      RDA5807P_REG[0] &=  ~(1<<7);
162     else      
163      RDA5807P_REG[0] |=  1<<7;  
164     DBG("fm580x_tuner_mute \n");
165     fm580x_i2c_tx_data( &(RDA5807P_REG[0]), 2);
166 }
167
168 void fm580x_tuner_setStereo(unsigned short flag)
169 {
170     if(flag)
171             RDA5807P_REG[0] &=  ~(1<<6);
172         else
173             RDA5807P_REG[0] |=  1<<6;
174     
175     fm580x_i2c_tx_data( &(RDA5807P_REG[0]), 2);
176     mdelay(50);    
177 }
178
179 bool fm580x_tuner_getStereo()
180 {
181     bool state;
182     if(RDA5807P_REG[0] &(1<<6))
183         state = 1;
184     else
185         state = 0;
186
187      return state;
188 }
189
190 uint16_t fm580x_FreqToChan(uint16_t frequency) 
191 {
192     uint8_t channelSpacing;
193     uint16_t bottomOfBand;
194     uint16_t channel;
195
196     if ((RDA5807P_REG[3] & 0x0c) == 0x00) 
197         bottomOfBand = 870;
198     else if ((RDA5807P_REG[3] & 0x0c) == 0x04)  
199         bottomOfBand = 760;
200     else if ((RDA5807P_REG[3] & 0x0c) == 0x08)  
201         bottomOfBand = 760; 
202         
203     if ((RDA5807P_REG[3] & 0x03) == 0x00) 
204         channelSpacing = 1;
205     else if ((RDA5807P_REG[3] & 0x03) == 0x01) 
206         channelSpacing = 2;
207    
208     channel = (frequency - bottomOfBand) / channelSpacing;
209     DBG("%s: RDA5807P_REG[3]=0x%x,channel=%d,bottomOfBand=%d,channelSpacing=%d\n",__FUNCTION__,RDA5807P_REG[3],channel,bottomOfBand,channelSpacing);
210     return channel;
211 }
212
213
214 void fm580x_set_frequency(unsigned short curFreq)
215 {
216     uint16_t curChan;
217     curChan = fm580x_FreqToChan(curFreq/10);
218
219     //SetNoMute
220     //RDA5807P_REG[0] |=  1<<7;
221     RDA5807P_REG[2]=curChan>>2;
222     RDA5807P_REG[3]=(((curChan&0x0003)<<6)|0x10) | (RDA5807P_REG[3]&0x0f);  //set tune bit
223     DBG("fm580x_set_frequency %x,%x,%x \n",RDA5807P_REG[0],RDA5807P_REG[2],RDA5807P_REG[3]);
224     fm580x_i2c_tx_data( &(RDA5807P_REG[0]), 4);
225     mdelay(10);     //Delay five ms
226     DBG("%s:curchan=0x%x\n",__FUNCTION__,curChan);
227 }
228
229 bool  fm580x_tuner_CheckStation()
230 {
231  
232     uint8_t RDA5807P_reg_data[4]={0};   
233         int i;
234     //fm580x_i2c_rx_data(&(RDA5807P_reg_data[0]), 4);
235
236     do
237         {
238                 i++;
239                 if(i>5) return 0; 
240                 mdelay(30);
241                 fm580x_i2c_rx_data(&(RDA5807P_reg_data[0]), 4); 
242         }while((RDA5807P_reg_data[3]&0x80)==0);
243         DBG("fm580x_tuner_CheckStation %x ,%x\n",RDA5807P_reg_data[2],RDA5807P_reg_data[3]);
244     return  (RDA5807P_reg_data[2]&(1<<0));  
245 }
246
247 static int fm580x_init_device(struct i2c_client *client)    
248 {   
249     fm580x_tuner_init();
250     fm580x_tuner_exit();
251     return 0;
252 }
253
254 static ssize_t fm580x_proc_write(struct file *file, const char __user *buffer,
255                            unsigned long count, void *data)
256 {
257         char c;
258         int rc;
259         unsigned short freq;
260         
261         rc = get_user(c, buffer);
262         if (rc)
263                 return rc; 
264         
265         freq = 10000*(c - '0');
266         
267         fm580x_tuner_init();
268         fm580x_tuner_setStereo(1);
269         fm580x_set_frequency(freq);
270         fm580x_tuner_CheckStation();    
271
272         printk("%s:freq=%d\n",__FUNCTION__,freq);
273                 
274         return count; 
275 }
276
277 static const struct file_operations fm580x_proc_fops = {
278         .owner          = THIS_MODULE, 
279         .write          = fm580x_proc_write,
280 }; 
281
282 static int fm580x_open(struct inode *inode, struct file *file)
283 {
284         return nonseekable_open(inode, file);
285 }
286
287 static int fm580x_release(struct inode *inode, struct file *file)
288 {
289         return 0;
290 }
291
292 static int fm580x_ioctl(struct inode *inode, struct file *file, 
293         unsigned int cmd, unsigned long arg)
294 {
295         bool status;
296         int ret = 0;
297         unsigned short freq;
298         
299         switch (cmd){   
300         case FM_SET_AREA:
301                 DBG("set fm580x area \n");              
302                 break;
303
304         case FM_MUTE://mute fm
305                 DBG("set fm580x mute \n");
306                 fm580x_tuner_mute(arg);
307                 break;  
308                 
309         case FM_SET_ENABLE:
310             DBG("enable fm580x chip \n");
311             fm580x_tuner_init();        
312             //rk1000_codec_all_line_input_open(&rk1000_codec_dai,&codecdata1,&codecdata2);
313                 break;
314                 
315         case FM_SET_DISABLE:
316             DBG("disable fm580x chip \n");
317             //rk1000_codec_all_line_input_close(&rk1000_codec_dai,codecdata1,codecdata2);
318             fm580x_tuner_exit();                
319                 break;  
320                 
321         case FM_SET_STEREO:
322             DBG("set fm580x stereo \n");
323                 fm580x_tuner_setStereo(arg);
324                 break;  
325                 
326         case FM_GET_STEREO:
327             DBG("get fm580x stereo \n");
328             status = fm580x_tuner_getStereo();
329         ret = put_user(status,(int *)arg);
330                 if(ret < 0){
331                     DBG("put_user err!\n");
332                 }
333         break;  
334         
335     case FM_SET_FREQ:    
336         ret=copy_from_user(&freq,(void __user *) arg, sizeof(int));
337                 if(ret < 0){
338                 DBG("put_user err!\n");
339                 return ret;
340                 } 
341                 fm580x_set_frequency(freq);  
342                 break;          
343         
344     case FM_STATION_ISAVAILABLE: 
345         status = fm580x_tuner_CheckStation();
346         ret = put_user(status,(int *)arg);
347                 if(ret < 0){
348                 DBG("put_user err!\n");
349                 }
350                 DBG(" fm580x station's state is %d \n",status);
351         break;
352         
353    case FM_TR_FUN:
354         DBG("set fm580x tr fun \n"); 
355         //musicTran(arg);
356         break;
357                 
358    case FM_TR_FUN_STOP:
359         DBG("stop fm580x tr fun \n");
360         //if(arg)
361         //    musicCloseTran();
362         break;
363                 
364    default:
365                 //E("unknown ioctl cmd!\n");
366                 ret = -EINVAL;
367                 break;
368         }
369
370         return ret;
371 }
372
373 static ssize_t fm580x_show(struct device *dev, struct device_attribute *attr, char *buf)
374 {
375         ssize_t ret = 0;
376         sprintf(buf, "fm580x");
377         ret = strlen(buf) + 1;
378         printk("%s:ret=%d\n",__FUNCTION__,ret);
379         return ret;
380 }
381
382 static DEVICE_ATTR(fm580x, S_IRUGO, fm580x_show, NULL);
383
384 static struct file_operations fm580x_fops = {
385         .owner          = THIS_MODULE,
386         .open           = fm580x_open,
387         .release        = fm580x_release,
388         .ioctl          = fm580x_ioctl,
389 };
390
391 static struct miscdevice fm580x_device = {
392         .minor = MISC_DYNAMIC_MINOR,
393         .name = FM580X_DEV_NAME,
394         .fops = &fm580x_fops,
395 };
396
397 static int fm580x_probe(struct i2c_client *client, const struct i2c_device_id *id)
398 {
399         unsigned char data[16] = {0};
400         int res = 0;
401         struct proc_dir_entry *fm580x_proc_entry;       
402
403         if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 
404         {
405                 pr_err("%s: functionality check failed\n", __FUNCTION__);
406                 res = -ENODEV;
407                 goto out;
408         }
409         
410         this_client = client;
411
412         res = misc_register(&fm580x_device);
413         if (res) {
414         pr_err("%s: fm580x_device register failed\n", __FUNCTION__);
415         goto out;
416         }
417
418         res = device_create_file(&client->dev, &dev_attr_fm580x);
419         if (res) {
420         pr_err("%s: device_create_file failed\n", __FUNCTION__);
421         goto out_deregister;
422         }
423         
424         //fm580x_tuner_init();
425
426         fm580x_proc_entry = proc_create("driver/fm580x", 0777, NULL, &fm580x_proc_fops); 
427         
428         printk("%s:line=%d\n",__FUNCTION__,__LINE__);
429         
430         return 0;
431         
432 out_deregister:
433         misc_deregister(&fm580x_device);
434 out:
435         return res;
436 }
437
438 static int fm580x_remove(struct i2c_client *client)
439 {
440         device_remove_file(&client->dev, &dev_attr_fm580x);
441         misc_deregister(&fm580x_device);
442         return 0;
443 }
444
445 static const struct i2c_device_id fm580x_id[] = {
446         { FM580X_I2C_NAME, 0 },
447         { }
448 };
449
450 static struct i2c_driver fm580x_driver = {
451         .probe          = fm580x_probe,
452         .remove         = fm580x_remove,
453         .id_table       = fm580x_id,
454         .driver         = {
455                 .owner  = THIS_MODULE,
456                 .name   = FM580X_I2C_NAME,
457         },
458 };
459
460
461 static int __init fm580x_init(void)
462 {
463         pr_info("fm580x driver: init\n");
464         return i2c_add_driver(&fm580x_driver);
465 }
466
467 static void __exit fm580x_exit(void)
468 {
469         pr_info("fm580x driver: exit\n");
470         i2c_del_driver(&fm580x_driver);
471 }
472
473 module_init(fm580x_init);
474 module_exit(fm580x_exit);
475
476 MODULE_AUTHOR("luo wei<lw@rock-chips.com>");
477 MODULE_DESCRIPTION("FM rda580x Driver");
478 MODULE_LICENSE("GPL");
479