12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
26851ad3aSJorge Eduardo Candelaria /*
36851ad3aSJorge Eduardo Candelaria * tps65910.c -- TI TPS6591x
46851ad3aSJorge Eduardo Candelaria *
56851ad3aSJorge Eduardo Candelaria * Copyright 2010 Texas Instruments Inc.
66851ad3aSJorge Eduardo Candelaria *
76851ad3aSJorge Eduardo Candelaria * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
86851ad3aSJorge Eduardo Candelaria */
96851ad3aSJorge Eduardo Candelaria
106851ad3aSJorge Eduardo Candelaria #include <linux/kernel.h>
116851ad3aSJorge Eduardo Candelaria #include <linux/module.h>
126851ad3aSJorge Eduardo Candelaria #include <linux/init.h>
136851ad3aSJorge Eduardo Candelaria #include <linux/slab.h>
146851ad3aSJorge Eduardo Candelaria #include <linux/err.h>
156851ad3aSJorge Eduardo Candelaria #include <linux/platform_device.h>
166851ad3aSJorge Eduardo Candelaria #include <linux/debugfs.h>
176851ad3aSJorge Eduardo Candelaria #include <linux/gpio.h>
186851ad3aSJorge Eduardo Candelaria #include <linux/mfd/tps65910.h>
196851ad3aSJorge Eduardo Candelaria
201768391cSLee Jones #define COMP1 0
211768391cSLee Jones #define COMP2 1
226851ad3aSJorge Eduardo Candelaria
2391fe4d50SThomas Weber /* Comparator 1 voltage selection table in millivolts */
246851ad3aSJorge Eduardo Candelaria static const u16 COMP_VSEL_TABLE[] = {
256851ad3aSJorge Eduardo Candelaria 0, 2500, 2500, 2500, 2500, 2550, 2600, 2650,
266851ad3aSJorge Eduardo Candelaria 2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050,
276851ad3aSJorge Eduardo Candelaria 3100, 3150, 3200, 3250, 3300, 3350, 3400, 3450,
286851ad3aSJorge Eduardo Candelaria 3500,
296851ad3aSJorge Eduardo Candelaria };
306851ad3aSJorge Eduardo Candelaria
316851ad3aSJorge Eduardo Candelaria struct comparator {
326851ad3aSJorge Eduardo Candelaria const char *name;
336851ad3aSJorge Eduardo Candelaria int reg;
346851ad3aSJorge Eduardo Candelaria int uV_max;
356851ad3aSJorge Eduardo Candelaria const u16 *vsel_table;
366851ad3aSJorge Eduardo Candelaria };
376851ad3aSJorge Eduardo Candelaria
386851ad3aSJorge Eduardo Candelaria static struct comparator tps_comparators[] = {
396851ad3aSJorge Eduardo Candelaria {
406851ad3aSJorge Eduardo Candelaria .name = "COMP1",
416851ad3aSJorge Eduardo Candelaria .reg = TPS65911_VMBCH,
426851ad3aSJorge Eduardo Candelaria .uV_max = 3500,
436851ad3aSJorge Eduardo Candelaria .vsel_table = COMP_VSEL_TABLE,
446851ad3aSJorge Eduardo Candelaria },
456851ad3aSJorge Eduardo Candelaria {
466851ad3aSJorge Eduardo Candelaria .name = "COMP2",
476851ad3aSJorge Eduardo Candelaria .reg = TPS65911_VMBCH2,
486851ad3aSJorge Eduardo Candelaria .uV_max = 3500,
496851ad3aSJorge Eduardo Candelaria .vsel_table = COMP_VSEL_TABLE,
506851ad3aSJorge Eduardo Candelaria },
516851ad3aSJorge Eduardo Candelaria };
526851ad3aSJorge Eduardo Candelaria
comp_threshold_set(struct tps65910 * tps65910,int id,int voltage)536851ad3aSJorge Eduardo Candelaria static int comp_threshold_set(struct tps65910 *tps65910, int id, int voltage)
546851ad3aSJorge Eduardo Candelaria {
556851ad3aSJorge Eduardo Candelaria struct comparator tps_comp = tps_comparators[id];
566851ad3aSJorge Eduardo Candelaria int curr_voltage = 0;
576851ad3aSJorge Eduardo Candelaria int ret;
586851ad3aSJorge Eduardo Candelaria u8 index = 0, val;
596851ad3aSJorge Eduardo Candelaria
606851ad3aSJorge Eduardo Candelaria while (curr_voltage < tps_comp.uV_max) {
616851ad3aSJorge Eduardo Candelaria curr_voltage = tps_comp.vsel_table[index];
626851ad3aSJorge Eduardo Candelaria if (curr_voltage >= voltage)
636851ad3aSJorge Eduardo Candelaria break;
646851ad3aSJorge Eduardo Candelaria else if (curr_voltage < voltage)
656851ad3aSJorge Eduardo Candelaria index ++;
666851ad3aSJorge Eduardo Candelaria }
676851ad3aSJorge Eduardo Candelaria
686851ad3aSJorge Eduardo Candelaria if (curr_voltage > tps_comp.uV_max)
696851ad3aSJorge Eduardo Candelaria return -EINVAL;
706851ad3aSJorge Eduardo Candelaria
716851ad3aSJorge Eduardo Candelaria val = index << 1;
72*da7d203fSMichał Mirosław ret = regmap_write(tps65910->regmap, tps_comp.reg, val);
736851ad3aSJorge Eduardo Candelaria
746851ad3aSJorge Eduardo Candelaria return ret;
756851ad3aSJorge Eduardo Candelaria }
766851ad3aSJorge Eduardo Candelaria
comp_threshold_get(struct tps65910 * tps65910,int id)776851ad3aSJorge Eduardo Candelaria static int comp_threshold_get(struct tps65910 *tps65910, int id)
786851ad3aSJorge Eduardo Candelaria {
796851ad3aSJorge Eduardo Candelaria struct comparator tps_comp = tps_comparators[id];
80ac188616SDan Carpenter unsigned int val;
816851ad3aSJorge Eduardo Candelaria int ret;
826851ad3aSJorge Eduardo Candelaria
83*da7d203fSMichał Mirosław ret = regmap_read(tps65910->regmap, tps_comp.reg, &val);
846851ad3aSJorge Eduardo Candelaria if (ret < 0)
856851ad3aSJorge Eduardo Candelaria return ret;
866851ad3aSJorge Eduardo Candelaria
876851ad3aSJorge Eduardo Candelaria val >>= 1;
886851ad3aSJorge Eduardo Candelaria return tps_comp.vsel_table[val];
896851ad3aSJorge Eduardo Candelaria }
906851ad3aSJorge Eduardo Candelaria
comp_threshold_show(struct device * dev,struct device_attribute * attr,char * buf)916851ad3aSJorge Eduardo Candelaria static ssize_t comp_threshold_show(struct device *dev,
926851ad3aSJorge Eduardo Candelaria struct device_attribute *attr, char *buf)
936851ad3aSJorge Eduardo Candelaria {
946851ad3aSJorge Eduardo Candelaria struct tps65910 *tps65910 = dev_get_drvdata(dev->parent);
956851ad3aSJorge Eduardo Candelaria struct attribute comp_attr = attr->attr;
966851ad3aSJorge Eduardo Candelaria int id, uVolt;
976851ad3aSJorge Eduardo Candelaria
986851ad3aSJorge Eduardo Candelaria if (!strcmp(comp_attr.name, "comp1_threshold"))
996851ad3aSJorge Eduardo Candelaria id = COMP1;
1006851ad3aSJorge Eduardo Candelaria else if (!strcmp(comp_attr.name, "comp2_threshold"))
1016851ad3aSJorge Eduardo Candelaria id = COMP2;
1026851ad3aSJorge Eduardo Candelaria else
1036851ad3aSJorge Eduardo Candelaria return -EINVAL;
1046851ad3aSJorge Eduardo Candelaria
1056851ad3aSJorge Eduardo Candelaria uVolt = comp_threshold_get(tps65910, id);
1066851ad3aSJorge Eduardo Candelaria
1076851ad3aSJorge Eduardo Candelaria return sprintf(buf, "%d\n", uVolt);
1086851ad3aSJorge Eduardo Candelaria }
1096851ad3aSJorge Eduardo Candelaria
1106851ad3aSJorge Eduardo Candelaria static DEVICE_ATTR(comp1_threshold, S_IRUGO, comp_threshold_show, NULL);
1116851ad3aSJorge Eduardo Candelaria static DEVICE_ATTR(comp2_threshold, S_IRUGO, comp_threshold_show, NULL);
1126851ad3aSJorge Eduardo Candelaria
tps65911_comparator_probe(struct platform_device * pdev)113f791be49SBill Pemberton static int tps65911_comparator_probe(struct platform_device *pdev)
1146851ad3aSJorge Eduardo Candelaria {
1156851ad3aSJorge Eduardo Candelaria struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
1161e8ece5cSAxel Lin struct tps65910_board *pdata = dev_get_platdata(tps65910->dev);
1176851ad3aSJorge Eduardo Candelaria int ret;
1186851ad3aSJorge Eduardo Candelaria
1196851ad3aSJorge Eduardo Candelaria ret = comp_threshold_set(tps65910, COMP1, pdata->vmbch_threshold);
1206851ad3aSJorge Eduardo Candelaria if (ret < 0) {
1216851ad3aSJorge Eduardo Candelaria dev_err(&pdev->dev, "cannot set COMP1 threshold\n");
1226851ad3aSJorge Eduardo Candelaria return ret;
1236851ad3aSJorge Eduardo Candelaria }
1246851ad3aSJorge Eduardo Candelaria
1256851ad3aSJorge Eduardo Candelaria ret = comp_threshold_set(tps65910, COMP2, pdata->vmbch2_threshold);
1266851ad3aSJorge Eduardo Candelaria if (ret < 0) {
1275a4432b9SMasanari Iida dev_err(&pdev->dev, "cannot set COMP2 threshold\n");
1286851ad3aSJorge Eduardo Candelaria return ret;
1296851ad3aSJorge Eduardo Candelaria }
1306851ad3aSJorge Eduardo Candelaria
1316851ad3aSJorge Eduardo Candelaria /* Create sysfs entry */
1326851ad3aSJorge Eduardo Candelaria ret = device_create_file(&pdev->dev, &dev_attr_comp1_threshold);
1336851ad3aSJorge Eduardo Candelaria if (ret < 0)
1346851ad3aSJorge Eduardo Candelaria dev_err(&pdev->dev, "failed to add COMP1 sysfs file\n");
1356851ad3aSJorge Eduardo Candelaria
1366851ad3aSJorge Eduardo Candelaria ret = device_create_file(&pdev->dev, &dev_attr_comp2_threshold);
1376851ad3aSJorge Eduardo Candelaria if (ret < 0)
1386851ad3aSJorge Eduardo Candelaria dev_err(&pdev->dev, "failed to add COMP2 sysfs file\n");
1396851ad3aSJorge Eduardo Candelaria
1406851ad3aSJorge Eduardo Candelaria return ret;
1416851ad3aSJorge Eduardo Candelaria }
1426851ad3aSJorge Eduardo Candelaria
tps65911_comparator_remove(struct platform_device * pdev)1434740f73fSBill Pemberton static int tps65911_comparator_remove(struct platform_device *pdev)
1446851ad3aSJorge Eduardo Candelaria {
1456851ad3aSJorge Eduardo Candelaria struct tps65910 *tps65910;
1466851ad3aSJorge Eduardo Candelaria
1476851ad3aSJorge Eduardo Candelaria tps65910 = dev_get_drvdata(pdev->dev.parent);
1482f223341SAxel Lin device_remove_file(&pdev->dev, &dev_attr_comp2_threshold);
1492f223341SAxel Lin device_remove_file(&pdev->dev, &dev_attr_comp1_threshold);
1506851ad3aSJorge Eduardo Candelaria
1516851ad3aSJorge Eduardo Candelaria return 0;
1526851ad3aSJorge Eduardo Candelaria }
1536851ad3aSJorge Eduardo Candelaria
1546851ad3aSJorge Eduardo Candelaria static struct platform_driver tps65911_comparator_driver = {
1556851ad3aSJorge Eduardo Candelaria .driver = {
1566851ad3aSJorge Eduardo Candelaria .name = "tps65911-comparator",
1576851ad3aSJorge Eduardo Candelaria },
1586851ad3aSJorge Eduardo Candelaria .probe = tps65911_comparator_probe,
15984449216SBill Pemberton .remove = tps65911_comparator_remove,
1606851ad3aSJorge Eduardo Candelaria };
1616851ad3aSJorge Eduardo Candelaria
tps65911_comparator_init(void)1626851ad3aSJorge Eduardo Candelaria static int __init tps65911_comparator_init(void)
1636851ad3aSJorge Eduardo Candelaria {
1646851ad3aSJorge Eduardo Candelaria return platform_driver_register(&tps65911_comparator_driver);
1656851ad3aSJorge Eduardo Candelaria }
1666851ad3aSJorge Eduardo Candelaria subsys_initcall(tps65911_comparator_init);
1676851ad3aSJorge Eduardo Candelaria
tps65911_comparator_exit(void)1686851ad3aSJorge Eduardo Candelaria static void __exit tps65911_comparator_exit(void)
1696851ad3aSJorge Eduardo Candelaria {
1706851ad3aSJorge Eduardo Candelaria platform_driver_unregister(&tps65911_comparator_driver);
1716851ad3aSJorge Eduardo Candelaria }
1726851ad3aSJorge Eduardo Candelaria module_exit(tps65911_comparator_exit);
1736851ad3aSJorge Eduardo Candelaria
1746851ad3aSJorge Eduardo Candelaria MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>");
1756851ad3aSJorge Eduardo Candelaria MODULE_DESCRIPTION("TPS65911 comparator driver");
1766851ad3aSJorge Eduardo Candelaria MODULE_LICENSE("GPL v2");
1776851ad3aSJorge Eduardo Candelaria MODULE_ALIAS("platform:tps65911-comparator");
178