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