16851ad3aSJorge Eduardo Candelaria /* 26851ad3aSJorge Eduardo Candelaria * tps65910.c -- TI TPS6591x 36851ad3aSJorge Eduardo Candelaria * 46851ad3aSJorge Eduardo Candelaria * Copyright 2010 Texas Instruments Inc. 56851ad3aSJorge Eduardo Candelaria * 66851ad3aSJorge Eduardo Candelaria * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> 76851ad3aSJorge Eduardo Candelaria * 86851ad3aSJorge Eduardo Candelaria * This program is free software; you can redistribute it and/or modify it 96851ad3aSJorge Eduardo Candelaria * under the terms of the GNU General Public License as published by the 106851ad3aSJorge Eduardo Candelaria * Free Software Foundation; either version 2 of the License, or (at your 116851ad3aSJorge Eduardo Candelaria * option) any later version. 126851ad3aSJorge Eduardo Candelaria * 136851ad3aSJorge Eduardo Candelaria */ 146851ad3aSJorge Eduardo Candelaria 156851ad3aSJorge Eduardo Candelaria #include <linux/kernel.h> 166851ad3aSJorge Eduardo Candelaria #include <linux/module.h> 176851ad3aSJorge Eduardo Candelaria #include <linux/init.h> 186851ad3aSJorge Eduardo Candelaria #include <linux/slab.h> 196851ad3aSJorge Eduardo Candelaria #include <linux/err.h> 206851ad3aSJorge Eduardo Candelaria #include <linux/platform_device.h> 216851ad3aSJorge Eduardo Candelaria #include <linux/debugfs.h> 226851ad3aSJorge Eduardo Candelaria #include <linux/gpio.h> 236851ad3aSJorge Eduardo Candelaria #include <linux/mfd/tps65910.h> 246851ad3aSJorge Eduardo Candelaria 256851ad3aSJorge Eduardo Candelaria #define COMP 0 266851ad3aSJorge Eduardo Candelaria #define COMP1 1 276851ad3aSJorge Eduardo Candelaria #define COMP2 2 286851ad3aSJorge Eduardo Candelaria 2991fe4d50SThomas Weber /* Comparator 1 voltage selection table in millivolts */ 306851ad3aSJorge Eduardo Candelaria static const u16 COMP_VSEL_TABLE[] = { 316851ad3aSJorge Eduardo Candelaria 0, 2500, 2500, 2500, 2500, 2550, 2600, 2650, 326851ad3aSJorge Eduardo Candelaria 2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050, 336851ad3aSJorge Eduardo Candelaria 3100, 3150, 3200, 3250, 3300, 3350, 3400, 3450, 346851ad3aSJorge Eduardo Candelaria 3500, 356851ad3aSJorge Eduardo Candelaria }; 366851ad3aSJorge Eduardo Candelaria 376851ad3aSJorge Eduardo Candelaria struct comparator { 386851ad3aSJorge Eduardo Candelaria const char *name; 396851ad3aSJorge Eduardo Candelaria int reg; 406851ad3aSJorge Eduardo Candelaria int uV_max; 416851ad3aSJorge Eduardo Candelaria const u16 *vsel_table; 426851ad3aSJorge Eduardo Candelaria }; 436851ad3aSJorge Eduardo Candelaria 446851ad3aSJorge Eduardo Candelaria static struct comparator tps_comparators[] = { 456851ad3aSJorge Eduardo Candelaria { 466851ad3aSJorge Eduardo Candelaria .name = "COMP1", 476851ad3aSJorge Eduardo Candelaria .reg = TPS65911_VMBCH, 486851ad3aSJorge Eduardo Candelaria .uV_max = 3500, 496851ad3aSJorge Eduardo Candelaria .vsel_table = COMP_VSEL_TABLE, 506851ad3aSJorge Eduardo Candelaria }, 516851ad3aSJorge Eduardo Candelaria { 526851ad3aSJorge Eduardo Candelaria .name = "COMP2", 536851ad3aSJorge Eduardo Candelaria .reg = TPS65911_VMBCH2, 546851ad3aSJorge Eduardo Candelaria .uV_max = 3500, 556851ad3aSJorge Eduardo Candelaria .vsel_table = COMP_VSEL_TABLE, 566851ad3aSJorge Eduardo Candelaria }, 576851ad3aSJorge Eduardo Candelaria }; 586851ad3aSJorge Eduardo Candelaria 596851ad3aSJorge Eduardo Candelaria static int comp_threshold_set(struct tps65910 *tps65910, int id, int voltage) 606851ad3aSJorge Eduardo Candelaria { 616851ad3aSJorge Eduardo Candelaria struct comparator tps_comp = tps_comparators[id]; 626851ad3aSJorge Eduardo Candelaria int curr_voltage = 0; 636851ad3aSJorge Eduardo Candelaria int ret; 646851ad3aSJorge Eduardo Candelaria u8 index = 0, val; 656851ad3aSJorge Eduardo Candelaria 666851ad3aSJorge Eduardo Candelaria if (id == COMP) 676851ad3aSJorge Eduardo Candelaria return 0; 686851ad3aSJorge Eduardo Candelaria 696851ad3aSJorge Eduardo Candelaria while (curr_voltage < tps_comp.uV_max) { 706851ad3aSJorge Eduardo Candelaria curr_voltage = tps_comp.vsel_table[index]; 716851ad3aSJorge Eduardo Candelaria if (curr_voltage >= voltage) 726851ad3aSJorge Eduardo Candelaria break; 736851ad3aSJorge Eduardo Candelaria else if (curr_voltage < voltage) 746851ad3aSJorge Eduardo Candelaria index ++; 756851ad3aSJorge Eduardo Candelaria } 766851ad3aSJorge Eduardo Candelaria 776851ad3aSJorge Eduardo Candelaria if (curr_voltage > tps_comp.uV_max) 786851ad3aSJorge Eduardo Candelaria return -EINVAL; 796851ad3aSJorge Eduardo Candelaria 806851ad3aSJorge Eduardo Candelaria val = index << 1; 81ac188616SDan Carpenter ret = tps65910_reg_write(tps65910, tps_comp.reg, val); 826851ad3aSJorge Eduardo Candelaria 836851ad3aSJorge Eduardo Candelaria return ret; 846851ad3aSJorge Eduardo Candelaria } 856851ad3aSJorge Eduardo Candelaria 866851ad3aSJorge Eduardo Candelaria static int comp_threshold_get(struct tps65910 *tps65910, int id) 876851ad3aSJorge Eduardo Candelaria { 886851ad3aSJorge Eduardo Candelaria struct comparator tps_comp = tps_comparators[id]; 89ac188616SDan Carpenter unsigned int val; 906851ad3aSJorge Eduardo Candelaria int ret; 916851ad3aSJorge Eduardo Candelaria 926851ad3aSJorge Eduardo Candelaria if (id == COMP) 936851ad3aSJorge Eduardo Candelaria return 0; 946851ad3aSJorge Eduardo Candelaria 95ac188616SDan Carpenter ret = tps65910_reg_read(tps65910, tps_comp.reg, &val); 966851ad3aSJorge Eduardo Candelaria if (ret < 0) 976851ad3aSJorge Eduardo Candelaria return ret; 986851ad3aSJorge Eduardo Candelaria 996851ad3aSJorge Eduardo Candelaria val >>= 1; 1006851ad3aSJorge Eduardo Candelaria return tps_comp.vsel_table[val]; 1016851ad3aSJorge Eduardo Candelaria } 1026851ad3aSJorge Eduardo Candelaria 1036851ad3aSJorge Eduardo Candelaria static ssize_t comp_threshold_show(struct device *dev, 1046851ad3aSJorge Eduardo Candelaria struct device_attribute *attr, char *buf) 1056851ad3aSJorge Eduardo Candelaria { 1066851ad3aSJorge Eduardo Candelaria struct tps65910 *tps65910 = dev_get_drvdata(dev->parent); 1076851ad3aSJorge Eduardo Candelaria struct attribute comp_attr = attr->attr; 1086851ad3aSJorge Eduardo Candelaria int id, uVolt; 1096851ad3aSJorge Eduardo Candelaria 1106851ad3aSJorge Eduardo Candelaria if (!strcmp(comp_attr.name, "comp1_threshold")) 1116851ad3aSJorge Eduardo Candelaria id = COMP1; 1126851ad3aSJorge Eduardo Candelaria else if (!strcmp(comp_attr.name, "comp2_threshold")) 1136851ad3aSJorge Eduardo Candelaria id = COMP2; 1146851ad3aSJorge Eduardo Candelaria else 1156851ad3aSJorge Eduardo Candelaria return -EINVAL; 1166851ad3aSJorge Eduardo Candelaria 1176851ad3aSJorge Eduardo Candelaria uVolt = comp_threshold_get(tps65910, id); 1186851ad3aSJorge Eduardo Candelaria 1196851ad3aSJorge Eduardo Candelaria return sprintf(buf, "%d\n", uVolt); 1206851ad3aSJorge Eduardo Candelaria } 1216851ad3aSJorge Eduardo Candelaria 1226851ad3aSJorge Eduardo Candelaria static DEVICE_ATTR(comp1_threshold, S_IRUGO, comp_threshold_show, NULL); 1236851ad3aSJorge Eduardo Candelaria static DEVICE_ATTR(comp2_threshold, S_IRUGO, comp_threshold_show, NULL); 1246851ad3aSJorge Eduardo Candelaria 125f791be49SBill Pemberton static int tps65911_comparator_probe(struct platform_device *pdev) 1266851ad3aSJorge Eduardo Candelaria { 1276851ad3aSJorge Eduardo Candelaria struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); 1281e8ece5cSAxel Lin struct tps65910_board *pdata = dev_get_platdata(tps65910->dev); 1296851ad3aSJorge Eduardo Candelaria int ret; 1306851ad3aSJorge Eduardo Candelaria 1316851ad3aSJorge Eduardo Candelaria ret = comp_threshold_set(tps65910, COMP1, pdata->vmbch_threshold); 1326851ad3aSJorge Eduardo Candelaria if (ret < 0) { 1336851ad3aSJorge Eduardo Candelaria dev_err(&pdev->dev, "cannot set COMP1 threshold\n"); 1346851ad3aSJorge Eduardo Candelaria return ret; 1356851ad3aSJorge Eduardo Candelaria } 1366851ad3aSJorge Eduardo Candelaria 1376851ad3aSJorge Eduardo Candelaria ret = comp_threshold_set(tps65910, COMP2, pdata->vmbch2_threshold); 1386851ad3aSJorge Eduardo Candelaria if (ret < 0) { 1395a4432b9SMasanari Iida dev_err(&pdev->dev, "cannot set COMP2 threshold\n"); 1406851ad3aSJorge Eduardo Candelaria return ret; 1416851ad3aSJorge Eduardo Candelaria } 1426851ad3aSJorge Eduardo Candelaria 1436851ad3aSJorge Eduardo Candelaria /* Create sysfs entry */ 1446851ad3aSJorge Eduardo Candelaria ret = device_create_file(&pdev->dev, &dev_attr_comp1_threshold); 1456851ad3aSJorge Eduardo Candelaria if (ret < 0) 1466851ad3aSJorge Eduardo Candelaria dev_err(&pdev->dev, "failed to add COMP1 sysfs file\n"); 1476851ad3aSJorge Eduardo Candelaria 1486851ad3aSJorge Eduardo Candelaria ret = device_create_file(&pdev->dev, &dev_attr_comp2_threshold); 1496851ad3aSJorge Eduardo Candelaria if (ret < 0) 1506851ad3aSJorge Eduardo Candelaria dev_err(&pdev->dev, "failed to add COMP2 sysfs file\n"); 1516851ad3aSJorge Eduardo Candelaria 1526851ad3aSJorge Eduardo Candelaria return ret; 1536851ad3aSJorge Eduardo Candelaria } 1546851ad3aSJorge Eduardo Candelaria 1554740f73fSBill Pemberton static int tps65911_comparator_remove(struct platform_device *pdev) 1566851ad3aSJorge Eduardo Candelaria { 1576851ad3aSJorge Eduardo Candelaria struct tps65910 *tps65910; 1586851ad3aSJorge Eduardo Candelaria 1596851ad3aSJorge Eduardo Candelaria tps65910 = dev_get_drvdata(pdev->dev.parent); 1602f223341SAxel Lin device_remove_file(&pdev->dev, &dev_attr_comp2_threshold); 1612f223341SAxel Lin device_remove_file(&pdev->dev, &dev_attr_comp1_threshold); 1626851ad3aSJorge Eduardo Candelaria 1636851ad3aSJorge Eduardo Candelaria return 0; 1646851ad3aSJorge Eduardo Candelaria } 1656851ad3aSJorge Eduardo Candelaria 1666851ad3aSJorge Eduardo Candelaria static struct platform_driver tps65911_comparator_driver = { 1676851ad3aSJorge Eduardo Candelaria .driver = { 1686851ad3aSJorge Eduardo Candelaria .name = "tps65911-comparator", 1696851ad3aSJorge Eduardo Candelaria }, 1706851ad3aSJorge Eduardo Candelaria .probe = tps65911_comparator_probe, 17184449216SBill Pemberton .remove = tps65911_comparator_remove, 1726851ad3aSJorge Eduardo Candelaria }; 1736851ad3aSJorge Eduardo Candelaria 1746851ad3aSJorge Eduardo Candelaria static int __init tps65911_comparator_init(void) 1756851ad3aSJorge Eduardo Candelaria { 1766851ad3aSJorge Eduardo Candelaria return platform_driver_register(&tps65911_comparator_driver); 1776851ad3aSJorge Eduardo Candelaria } 1786851ad3aSJorge Eduardo Candelaria subsys_initcall(tps65911_comparator_init); 1796851ad3aSJorge Eduardo Candelaria 1806851ad3aSJorge Eduardo Candelaria static void __exit tps65911_comparator_exit(void) 1816851ad3aSJorge Eduardo Candelaria { 1826851ad3aSJorge Eduardo Candelaria platform_driver_unregister(&tps65911_comparator_driver); 1836851ad3aSJorge Eduardo Candelaria } 1846851ad3aSJorge Eduardo Candelaria module_exit(tps65911_comparator_exit); 1856851ad3aSJorge Eduardo Candelaria 1866851ad3aSJorge Eduardo Candelaria MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>"); 1876851ad3aSJorge Eduardo Candelaria MODULE_DESCRIPTION("TPS65911 comparator driver"); 1886851ad3aSJorge Eduardo Candelaria MODULE_LICENSE("GPL v2"); 1896851ad3aSJorge Eduardo Candelaria MODULE_ALIAS("platform:tps65911-comparator"); 190