176 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * tps65910.c -- TI TPS6591x4 *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 021#define COMP2 122 23/* Comparator 1 voltage selection table in millivolts */24static 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 31struct comparator {32 const char *name;33 int reg;34 int uV_max;35 const u16 *vsel_table;36};37 38static 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 53static 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 = regmap_write(tps65910->regmap, tps_comp.reg, val);73 74 return ret;75}76 77static 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 = regmap_read(tps65910->regmap, tps_comp.reg, &val);84 if (ret < 0)85 return ret;86 87 val >>= 1;88 return tps_comp.vsel_table[val];89}90 91static 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 else103 return -EINVAL;104 105 uVolt = comp_threshold_get(tps65910, id);106 107 return sprintf(buf, "%d\n", uVolt);108}109 110static DEVICE_ATTR(comp1_threshold, S_IRUGO, comp_threshold_show, NULL);111static DEVICE_ATTR(comp2_threshold, S_IRUGO, comp_threshold_show, NULL);112 113static 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 143static void 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 152static struct platform_driver tps65911_comparator_driver = {153 .driver = {154 .name = "tps65911-comparator",155 },156 .probe = tps65911_comparator_probe,157 .remove_new = tps65911_comparator_remove,158};159 160static int __init tps65911_comparator_init(void)161{162 return platform_driver_register(&tps65911_comparator_driver);163}164subsys_initcall(tps65911_comparator_init);165 166static void __exit tps65911_comparator_exit(void)167{168 platform_driver_unregister(&tps65911_comparator_driver);169}170module_exit(tps65911_comparator_exit);171 172MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>");173MODULE_DESCRIPTION("TPS65911 comparator driver");174MODULE_LICENSE("GPL v2");175MODULE_ALIAS("platform:tps65911-comparator");176