1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * tps65910.c -- TI TPS6591x 4 * 5 * Copyright 2010 Texas Instruments Inc. 6 * 7 * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> 8 */ 9 10 #include <linux/kernel.h> 11 #include <linux/module.h> 12 #include <linux/init.h> 13 #include <linux/slab.h> 14 #include <linux/err.h> 15 #include <linux/platform_device.h> 16 #include <linux/debugfs.h> 17 #include <linux/gpio.h> 18 #include <linux/mfd/tps65910.h> 19 20 #define COMP1 0 21 #define COMP2 1 22 23 /* Comparator 1 voltage selection table in millivolts */ 24 static const u16 COMP_VSEL_TABLE[] = { 25 0, 2500, 2500, 2500, 2500, 2550, 2600, 2650, 26 2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050, 27 3100, 3150, 3200, 3250, 3300, 3350, 3400, 3450, 28 3500, 29 }; 30 31 struct comparator { 32 const char *name; 33 int reg; 34 int uV_max; 35 const u16 *vsel_table; 36 }; 37 38 static struct comparator tps_comparators[] = { 39 { 40 .name = "COMP1", 41 .reg = TPS65911_VMBCH, 42 .uV_max = 3500, 43 .vsel_table = COMP_VSEL_TABLE, 44 }, 45 { 46 .name = "COMP2", 47 .reg = TPS65911_VMBCH2, 48 .uV_max = 3500, 49 .vsel_table = COMP_VSEL_TABLE, 50 }, 51 }; 52 53 static int comp_threshold_set(struct tps65910 *tps65910, int id, int voltage) 54 { 55 struct comparator tps_comp = tps_comparators[id]; 56 int curr_voltage = 0; 57 int ret; 58 u8 index = 0, val; 59 60 while (curr_voltage < tps_comp.uV_max) { 61 curr_voltage = tps_comp.vsel_table[index]; 62 if (curr_voltage >= voltage) 63 break; 64 else if (curr_voltage < voltage) 65 index ++; 66 } 67 68 if (curr_voltage > tps_comp.uV_max) 69 return -EINVAL; 70 71 val = index << 1; 72 ret = tps65910_reg_write(tps65910, tps_comp.reg, val); 73 74 return ret; 75 } 76 77 static int comp_threshold_get(struct tps65910 *tps65910, int id) 78 { 79 struct comparator tps_comp = tps_comparators[id]; 80 unsigned int val; 81 int ret; 82 83 ret = tps65910_reg_read(tps65910, tps_comp.reg, &val); 84 if (ret < 0) 85 return ret; 86 87 val >>= 1; 88 return tps_comp.vsel_table[val]; 89 } 90 91 static ssize_t comp_threshold_show(struct device *dev, 92 struct device_attribute *attr, char *buf) 93 { 94 struct tps65910 *tps65910 = dev_get_drvdata(dev->parent); 95 struct attribute comp_attr = attr->attr; 96 int id, uVolt; 97 98 if (!strcmp(comp_attr.name, "comp1_threshold")) 99 id = COMP1; 100 else if (!strcmp(comp_attr.name, "comp2_threshold")) 101 id = COMP2; 102 else 103 return -EINVAL; 104 105 uVolt = comp_threshold_get(tps65910, id); 106 107 return sprintf(buf, "%d\n", uVolt); 108 } 109 110 static DEVICE_ATTR(comp1_threshold, S_IRUGO, comp_threshold_show, NULL); 111 static DEVICE_ATTR(comp2_threshold, S_IRUGO, comp_threshold_show, NULL); 112 113 static int tps65911_comparator_probe(struct platform_device *pdev) 114 { 115 struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); 116 struct tps65910_board *pdata = dev_get_platdata(tps65910->dev); 117 int ret; 118 119 ret = comp_threshold_set(tps65910, COMP1, pdata->vmbch_threshold); 120 if (ret < 0) { 121 dev_err(&pdev->dev, "cannot set COMP1 threshold\n"); 122 return ret; 123 } 124 125 ret = comp_threshold_set(tps65910, COMP2, pdata->vmbch2_threshold); 126 if (ret < 0) { 127 dev_err(&pdev->dev, "cannot set COMP2 threshold\n"); 128 return ret; 129 } 130 131 /* Create sysfs entry */ 132 ret = device_create_file(&pdev->dev, &dev_attr_comp1_threshold); 133 if (ret < 0) 134 dev_err(&pdev->dev, "failed to add COMP1 sysfs file\n"); 135 136 ret = device_create_file(&pdev->dev, &dev_attr_comp2_threshold); 137 if (ret < 0) 138 dev_err(&pdev->dev, "failed to add COMP2 sysfs file\n"); 139 140 return ret; 141 } 142 143 static int tps65911_comparator_remove(struct platform_device *pdev) 144 { 145 struct tps65910 *tps65910; 146 147 tps65910 = dev_get_drvdata(pdev->dev.parent); 148 device_remove_file(&pdev->dev, &dev_attr_comp2_threshold); 149 device_remove_file(&pdev->dev, &dev_attr_comp1_threshold); 150 151 return 0; 152 } 153 154 static struct platform_driver tps65911_comparator_driver = { 155 .driver = { 156 .name = "tps65911-comparator", 157 }, 158 .probe = tps65911_comparator_probe, 159 .remove = tps65911_comparator_remove, 160 }; 161 162 static int __init tps65911_comparator_init(void) 163 { 164 return platform_driver_register(&tps65911_comparator_driver); 165 } 166 subsys_initcall(tps65911_comparator_init); 167 168 static void __exit tps65911_comparator_exit(void) 169 { 170 platform_driver_unregister(&tps65911_comparator_driver); 171 } 172 module_exit(tps65911_comparator_exit); 173 174 MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>"); 175 MODULE_DESCRIPTION("TPS65911 comparator driver"); 176 MODULE_LICENSE("GPL v2"); 177 MODULE_ALIAS("platform:tps65911-comparator"); 178