blob: fe5bb8d2d480aac77a8a0dd343591d754d3703b7 [file] [log] [blame]
wangxlee3614a2015-02-03 13:13:11 +08001
2
3
4#include <linux/init.h>
5#include <linux/module.h>
6
7
8#include <linux/miscdevice.h>
9#include <linux/platform_device.h>
10#include <linux/irq.h>
11#include <linux/input.h>
12#include <linux/interrupt.h>
13#include <linux/types.h>
14#include <linux/gpio.h>
15#include <linux/uaccess.h>
16#include <linux/tcmd_driver.h>
17#include <linux/regulator/consumer.h>
18#include <linux/mfd/pm8xxx/pm8921-charger.h>
19#include <linux/mfd/pm8xxx/ccadc.h>
wangxl07c6bc92014-12-31 10:07:44 +080020#include <linux/mfd/pm8xxx/misc.h>
wangxlee3614a2015-02-03 13:13:11 +080021#include <linux/qpnp/qpnp-adc.h>
22#include <linux/reboot.h>
23#include <linux/i2c.h>
24#include <linux/mhl_8334.h>
25#include <linux/mmc/core.h>
26#include <linux/mmc/card.h>
27
28#define NAME "tcmd_driver"
29
30static int gpio_map_size;
31static struct gpio_mapping *gpio_map_table;
32
33//extern int pm8921_disable_source_current_and_charging(bool disable);
34#ifdef CONFIG_TCMD
35extern int qpnp_disable_source_current(bool disable);
36
37extern int qpnp_disable_usb_charging(bool disable);
38
39extern int qpnp_set_max_battery_charge_current(bool enable);
40
41extern int lm3559_flash_set_led_state(int flash_lm3559_state);
42
wangxl07c6bc92014-12-31 10:07:44 +080043extern int qpnp_get_usb_max_current(int* usb_max_current);
44
45extern int qpnp_get_bat_max_current(int* bat_max_current);
46
47extern int qpnp_set_usb_max_current(int usb_max_current);
48
49extern int qpnp_set_bat_max_current(int bat_max_current);
50
wangxlbe091422014-12-31 10:08:48 +080051extern int qpnp_chg_priority(int enable);
52
wangxlee3614a2015-02-03 13:13:11 +080053extern struct qpnp_vadc_chip *vchip;
54#endif
55
56
57void __init gpio_mapping_init(struct gpio_mapping *table, int size)
58{
59 gpio_map_size = size;
60 gpio_map_table = table;
61}
62
63int get_gpio_by_name(char *name)
64{
65 int i;
66
67 for (i = 0; i < gpio_map_size; i++) {
68 if (gpio_map_table[i].used == 0)
69 continue;
70
71 if (strncmp(name, gpio_map_table[i].name, GPIO_MAP_NAME_SIZE)
72 == 0)
73 return gpio_map_table[i].pin_num;
74 }
75
76 printk(KERN_ERR "Unable to get gpio pin num for %s\n", name);
77 return -EINVAL;
78}
79
80
81static int tcmd_misc_open(struct inode *inode, struct file *file)
82{
83 int err = nonseekable_open(inode, file);
84 if (err < 0)
85 return err;
86
87 return 0;
88}
89
90static long tcmd_misc_ioctl( struct file *file,
91 unsigned int cmd, unsigned long arg)
92{
93#ifdef CONFIG_TCMD
94 void __user *argp = (void __user *)arg;
wangxl07c6bc92014-12-31 10:07:44 +080095 int gpio_enum = -1, irq = -1, gpio_state = -1, rc = 0;
wangxlee3614a2015-02-03 13:13:11 +080096
97 pr_info("tcmd_misc_ioctl is called");
98
99 switch(cmd)
100 {
101 case TCMD_IOCTL_SET_REG:
102 case TCMD_IOCTL_GET_REG:
103 {
104 tcmd_reg_arg reg_arg;
105 struct regulator *reg_p;
106 printk("TCMD_IOCTL_SET_REG or GET");
107 if (copy_from_user(&reg_arg, argp, sizeof(tcmd_reg_arg)))
108 return -EFAULT;
109
110 reg_p = regulator_get(NULL,reg_arg.name );
111
112 if (IS_ERR(reg_p))
113 {
114 printk("%s: VREG reg_p get failed\n", __func__);
115 reg_p = NULL;
116 return -EFAULT;
117 }
118
119
120 if(cmd == TCMD_IOCTL_GET_REG ){
121 printk("cmd == TCMD_IOCTL_GET_REG ");
122 if(TCMD_REG_GET_VOLTAGE == reg_arg.cmd)
123 { printk("cmd == TCMD_REG_GET_VOLTAGE ");
124 reg_arg.param = regulator_get_voltage(reg_p);
125 }else if(TCMD_REG_GET_POWER_MODE == reg_arg.cmd)
126 {
127 reg_arg.param = regulator_get_mode(reg_p);
128 }
129 if(copy_to_user((tcmd_reg_arg *)argp, &reg_arg, sizeof(tcmd_reg_arg )))
130 return -EFAULT;
131
132 }
133 else{
134 switch(reg_arg.cmd)
135 {
136 case TCMD_REG_ENABLE :
wangxl07c6bc92014-12-31 10:07:44 +0800137 printk("TCMD_REGULATOR_ENABLE\n");
wangxlee3614a2015-02-03 13:13:11 +0800138 rc = regulator_enable(reg_p);
139 if (rc) {
140 pr_info( " regulator_enable failed:%d\n", rc);
141 return rc;
142 }
143 break;
144 case TCMD_REG_DISABLE:
wangxl07c6bc92014-12-31 10:07:44 +0800145 printk("TCMD_REGULATOR_DISABLE\n");
wangxlee3614a2015-02-03 13:13:11 +0800146 rc = regulator_disable(reg_p);
147 if (rc) {
148 pr_info( " regulator_disable failed:%d\n", rc);
149 return rc;
150 }
151 break;
152 case TCMD_REG_SET_VOLTAGE :
153 pr_info("TCMD_REG_SET_VOLTAGE, reg_arg.param= %d\n",reg_arg.param);
154 rc = regulator_set_voltage(reg_p, reg_arg.param, reg_arg.param);
155 if (rc) {
156 pr_info( " regulator_set_voltage failed:%d\n", rc);
157 return rc;
158 }
159 break;
160 case TCMD_REG_SET_POWER_MODE :
161 pr_info("TCMD_REG_SET_POWER_MODE, reg_arg.param= %d\n",reg_arg.param);
162 rc = regulator_set_mode(reg_p, reg_arg.param);
163 if (rc) {
164 pr_info( " regulator_set_mode failed:%d\n", rc);
165 return rc;
166 }
167 break;
168 default:
169 return -EINVAL;
170 break;
171 }
172
173 }
174 break;
175 }
176 case TCMD_IOCTL_CHARGER:
177 {
178
179 unsigned char charger_enable;
180 pr_info("cmd == TCMD_IOCTL_CHARGER");
181
182 if (copy_from_user(&charger_enable, argp, sizeof(unsigned char )))
183 return -EFAULT;
184
185 switch(charger_enable)
186 {
187 case 0:
188 rc = qpnp_disable_source_current(true);
189 if (rc)
190 {
191 printk("TCMD :tcmd_driver : qpnp_disable_source_current failed:%d\n", rc);
192 return rc;
193 }
194 break;
195 case 1:
196 rc = qpnp_set_max_battery_charge_current(true);
197 if (rc)
198 {
199 pr_info("TCMD : tcmd_driver : qpnp_set_max_battery_charge_current(true) failed:%d\n", rc);
200 return rc;
201 }
202 rc = qpnp_disable_source_current(false);
203 if (rc)
204 {
205 pr_info("TCMD : tcmd_driver : qpnp_disable_source_current(false) failed:%d\n", rc);
206 return rc;
207 }
208 printk("TCMD : Enable charging with high current successful");
209 break;
210 case 2:
211 rc = qpnp_set_max_battery_charge_current(false);
212 if (rc)
213 {
214 printk("TCMD : tcmd_driver : qpnp_set_max_battery_charge_current(false) failed:%d\n", rc);
215 return rc;
216 }
217 rc = qpnp_disable_source_current(false);
218 if (rc)
219 {
220 pr_info("TCMD : tcmd_driver : qpnp_disable_source_current(false) failed:%d\n", rc);
221 return rc;
222 }
223 printk("TCMD : Enable charging with low current successful");
224 break;
225 break;
226 default:
227 return -EINVAL;
228 break;
229 }
230 break;
231 }
232 case TCMD_IOCTL_USB_CHRGING:
233 {
234 unsigned char usb_charger_enable;
235 pr_info("TCMD: cmd = TCMD_IOCTL_USB_CHRGING");
236 if(copy_from_user(&usb_charger_enable, argp, sizeof(unsigned char)))
237 return -EFAULT;
238
239 switch(usb_charger_enable)
240 {
241 case 0:
242 printk("TCMD: tcmd_driver : Disable USB charging\n");
243 rc = qpnp_disable_usb_charging(!usb_charger_enable);
244 if(rc) {
245 printk("TCMD: qpnp-charger disable usb charging failed:%d\n", rc);
246 return rc;
247 }
248 break;
249 case 1:
250 printk("TCMD: tcmd_driver : Enable USB charging\n");
251 rc = qpnp_disable_usb_charging(!usb_charger_enable);
252 if(rc) {
253 printk("TCMD: qpnp-charger enable usb charging failed:%d\n", rc);
254 return rc;
255 }
256 }
257 break;
258 }
wangxlbe091422014-12-31 10:08:48 +0800259 case TCMD_IOCTL_CHGPTH_PRIORITY:
260 {
261 unsigned char charging_path_priority;
262 pr_info("TCMD: cmd = TCMD_IOCTL_CHGPTH_PRIORITY\n");
263 if(copy_from_user(&charging_path_priority, argp, sizeof(unsigned char)))
264 return -EFAULT;
265
266 switch(charging_path_priority)
267 {
268 case 0:
269 printk("TCMD: tcmd_driver : USB_IN priority \n");
270 rc = qpnp_chg_priority(charging_path_priority);
271 if(rc) {
272 printk("TCMD: qpnp_chg_priority USB_IN failed:%d\n", rc);
273 return rc;
274 }
275 break;
276 case 1:
277 printk("TCMD: tcmd_driver : DC_IN priority \n");
278 rc = qpnp_chg_priority(charging_path_priority);
279 if(rc) {
280 printk("TCMD: qpnp_chg_priority DC_IN failed:%d\n", rc);
281 return rc;
282 }
283 }
284 break;
285 }
wangxlee3614a2015-02-03 13:13:11 +0800286 /*case TCMD_IOCTL_SET_FLASH_LM3559:
287 {
288 int flash_lm3559_state;
289 pr_info("TCMD_IOCTL_SET_FLASH_LM3559\n");
290
291 if(copy_from_user(&flash_lm3559_state, argp, sizeof(int)))
292 return -EFAULT;
293
294 rc = lm3559_flash_set_led_state(flash_lm3559_state);
295
296 if(rc){
297 pr_info("Error on calling set_flash_lm3559\n");
298 return rc;
299 }
300 break;
301 }*/
302 case TCMD_IOCTL_POWER_DOWN:
303 {
304 pr_info("TCMD_IOCTL_POWER_DOWN\n");
305 kernel_power_off();
306 break;
307 }
308 case TCMD_IOCTL_GET_ADC:
309 {
310 TCMD_QPNP_VADC_CHAN_PARAM adc_arg;
311 //struct qpnp_vadc_chip *vadc;
312 int ibat_ua;
313
314 printk("TCMD_IOCTL_GET_ADC");
315 if (copy_from_user(&adc_arg, argp, sizeof(TCMD_QPNP_VADC_CHAN_PARAM)))
316 return -EFAULT;
317 printk("adc_arg.cmd: %d",adc_arg.cmd);
318 if(!vchip)
319 {
320 printk("vchip is NULL\n");
321 }
322 if (adc_arg.cmd == TCMD_PMIC_ADC_BATTERY_CURRENT){
323 printk("adc_arg.cmd == TCMD_PMIC_ADC_BATTERY_CURRENT");
324 rc = tcmd_get_battery_current(&ibat_ua);
325 adc_arg.adc_config.physical = ibat_ua;
326 adc_arg.adc_config.measurement = adc_arg.adc_config.physical;
327 }else{
328 rc = qpnp_vadc_read(vchip, adc_arg.cmd, &adc_arg.adc_config);
329 }
330
331 if (rc) {
332 pr_info("Error on calling qpnp_vadc_read");
333 return rc;
334 }
335
336 if(copy_to_user((TCMD_QPNP_VADC_CHAN_PARAM *)argp, &adc_arg, sizeof(TCMD_QPNP_VADC_CHAN_PARAM)))
337 return -EFAULT;
338
339 break;
340 }
341 case TCMD_IOCTL_SET_GPIO:
342 {
343 TCMD_PM8XXX_GPIO_PARAM gpio_arg;
344
345 printk("TCMD_IOCTL_SET_GPIO");
346 if (copy_from_user(&gpio_arg, argp, sizeof(TCMD_PM8XXX_GPIO_PARAM)))
347 return -EFAULT;
348 printk("gpio_arg.cmd: %d", gpio_arg.cmd);
349
350 rc = pm8xxx_gpio_config(gpio_arg.cmd, &gpio_arg.gpio_config);
351
352 if (rc) {
353 pr_info("Error on calling pm8xxx_gpio_config");
354 return rc;
355 }
356
357 break;
358 }
wangxl07c6bc92014-12-31 10:07:44 +0800359 case TCMD_IOCTL_GET_USB_BAT_CURRENT:
wangxlee3614a2015-02-03 13:13:11 +0800360 {
wangxl07c6bc92014-12-31 10:07:44 +0800361 int rc = -1;
362 TCMD_REG_USB_BAT_CURRENT adc_arg;
363 printk("TCMD_IOCTL_GET_USB_BAT_CURRENT");
364 if (copy_from_user(&adc_arg, argp, sizeof(TCMD_REG_USB_BAT_CURRENT)))
365 {
366 return -EFAULT;
367 }
wangxlee3614a2015-02-03 13:13:11 +0800368
wangxl07c6bc92014-12-31 10:07:44 +0800369 qpnp_get_usb_max_current(&adc_arg.usbPresentCurrent);
370 rc = qpnp_get_bat_max_current(&adc_arg.batPresentCurrent);
371
372 if(rc < 0)
373 {
374 return rc;
375 }
376
377 if(copy_to_user((TCMD_REG_USB_BAT_CURRENT *)argp, &adc_arg, sizeof(TCMD_REG_USB_BAT_CURRENT)))
378 return -EFAULT;
379
380 return rc;
381 }
382 case TCMD_IOCTL_SET_USB_BAT_CURRENT:
383 {
384 int rc = -1;
385 TCMD_REG_USB_BAT_CURRENT adc_arg;
386 printk("TCMD_IOCTL_GET_USB_BAT_CURRENT");
387 if (copy_from_user(&adc_arg, argp, sizeof(TCMD_REG_USB_BAT_CURRENT)))
388 {
389 return -EFAULT;
390 }
391
392 rc = qpnp_set_usb_max_current(adc_arg.usbPresentCurrent);
393 if(rc < 0)
394 {
395 return rc;
396 }
397
398 rc = qpnp_set_bat_max_current(adc_arg.batPresentCurrent);
399 return rc;
400 }
401 case TCMD_IOCTL_COINCELL_ENABLE_DISABLE:
402 {
403 int coincell_state;
404 pr_info("TCMD_IOCTL_COINCELL_ENABLE_DISABLE\n");
405 if(copy_from_user(&coincell_state, argp, sizeof(int)))
406 return -EFAULT;
407 printk("TCMD:Set charger state entering with value : %d",coincell_state);
408 rc = tcmd_qpnp_coincell_set_charger(coincell_state);
409 if(rc){
410 pr_info("Error on calling tcmd_qpnp_coincell_set_charger\n");
411 printk("TCMD:Error on calling tcms_qpnp_coincell_set_charger : %d",rc);
412 return rc;
413 }
414 printk("TCMD:Set charger state out with value : %d",rc);
415 break;
416 }
417 case TCMD_IOCTL_SET_COINCELL:
418 {
419 TCMD_QPNP_CC_CHG_PARAM coincell_arg;
wangxlee3614a2015-02-03 13:13:11 +0800420 printk("TCMD_IOCTL_SET_COINCELL");
wangxl07c6bc92014-12-31 10:07:44 +0800421 if (copy_from_user(&coincell_arg, argp, sizeof(TCMD_QPNP_CC_CHG_PARAM)))
wangxlee3614a2015-02-03 13:13:11 +0800422 return -EFAULT;
423
wangxl07c6bc92014-12-31 10:07:44 +0800424 //rc = pm8xxx_coincell_chg_config(&coincell_arg);
425 printk("\nState - > %d \n Voltage - > %d \n Resistance -> %d \n",coincell_arg.state,coincell_arg.voltage,coincell_arg.resistance);
426 if((rc = tcmd_qpnp_coincell_set_charger(coincell_arg.state))){
427 printk("Error in configuring the state : tcmd_qpnp_coincell_set_charger : rc= %d",rc);
428 return rc;
429 }
430 if((rc = tcmd_qpnp_coincell_set_voltage(coincell_arg.voltage))){
431 printk("Error in configuring Voltage :tcmd_qpnp_coincell_set_voltage: rc= %d",rc);
432 return rc;
433 }
434 if((rc = tcmd_qpnp_coincell_set_resistance(coincell_arg.resistance))) {
435 printk("Error in configuring Resistance :tcmd_qpnp_coincell_set_resistance : rc= %d",rc);
436 return rc;
437 }
wangxlee3614a2015-02-03 13:13:11 +0800438
439 if (rc) {
wangxl07c6bc92014-12-31 10:07:44 +0800440 pr_info("Error on calling pm8xxx_coincell_chg_config ");
441 printk("value of rc = %d",rc);
wangxlee3614a2015-02-03 13:13:11 +0800442 return rc;
443 }
444 break;
445 }
wangxl07c6bc92014-12-31 10:07:44 +0800446/* case TCMD_IOCTL_SET_VIBRATOR:
wangxlee3614a2015-02-03 13:13:11 +0800447 {
448 TCMD_PM8XXX_VIB_PARAM vib_arg;
449
450 printk("TCMD_IOCTL_SET_VIBRATOR");
451 if (copy_from_user(&vib_arg, argp, sizeof(TCMD_PM8XXX_VIB_PARAM)))
452 return -EFAULT;
453
454 rc = pm8xxx_vibrator_config(&vib_arg);
455
456 if (rc) {
457 pr_info("Error on calling pm8xxx_vibrator_config");
458 return rc;
459 }
460
461 break;
462
463 }*/
464
465 default:
466 {
467 struct tcmd_gpio_set_arg gpio_set_arg;
468
469 if (cmd == TCMD_IOCTL_SET_INT) {
470 if (copy_from_user(&gpio_set_arg, argp, 2))
471 return -EFAULT;
472 gpio_enum = gpio_set_arg.gpio;
473 gpio_state = gpio_set_arg.gpio_state;
474 }
475 else if (copy_from_user(&gpio_enum, argp, sizeof(int)))
476 return -EFAULT;
477
478 if (gpio_enum < 0)
479 return -EINVAL;
480
481 switch (cmd) {
482 case TCMD_IOCTL_MASK_INT:
483 case TCMD_IOCTL_UNMASK_INT:
484 irq = gpio_to_irq(gpio_enum);
485 if (irq < 0)
486 return -EINVAL;
487 break;
488 default:
489 break;
490 }
491
492 switch (cmd) {
493 case TCMD_IOCTL_MASK_INT:
494 pr_info("tcmd mask interrupt: gpio = %d, irq = %d.\n",
495 gpio_enum, irq);
496 disable_irq(irq);
497 break;
498 case TCMD_IOCTL_UNMASK_INT:
499 pr_info("tcmd unmask interrupt: gpio = %d, irq = %d.\n",
500 gpio_enum, irq);
501 enable_irq(irq);
502 break;
503 case TCMD_IOCTL_READ_INT:
504 gpio_state = gpio_get_value(gpio_enum);
505 pr_info("tcmd interrupt state: gpio = %d -> %d.\n",
506 gpio_enum, gpio_state);
507 if (copy_to_user(argp, &gpio_state, sizeof(int)))
508 return -EFAULT;
509 break;
510 case TCMD_IOCTL_SET_INT:
511 pr_info("tcmd set interrupt state: gpio = %d -> %d.\n",
512 gpio_enum, gpio_state);
513 gpio_set_value(gpio_enum, gpio_state);
514 break;
515 default:
516 return -EINVAL;
517 }
518 break;
519 }//default
520 }
521#endif
522 return 0;
523}
524
525static const struct file_operations tcmd_misc_fops = {
526 .owner = THIS_MODULE,
527 .open = tcmd_misc_open,
528 .unlocked_ioctl = tcmd_misc_ioctl,
529};
530
531static struct miscdevice tcmd_misc_device = {
532 .minor = MISC_DYNAMIC_MINOR,
533 .name = NAME,
534 .fops = &tcmd_misc_fops,
535};
536
537static int __init tcmd_init(void)
538{
539 int error = misc_register(&tcmd_misc_device);
540 if (error < 0) {
541 pr_err("%s: tcmd misc register failed!\n", __func__);
542 return error;
543 }
544
545 pr_info("tcmd probe\n");
546
547 return 0;
548}
549
550static void __exit tcmd_exit(void)
551{
552 misc_deregister(&tcmd_misc_device);
553}
554
555module_init(tcmd_init);
556module_exit(tcmd_exit);
557
558MODULE_LICENSE("GPL");
559MODULE_DESCRIPTION("tcmd");