cregit-Linux how code gets into the kernel

Release 4.7 drivers/hwmon/da9055-hwmon.c

Directory: drivers/hwmon
/*
 * HWMON Driver for Dialog DA9055
 *
 * Copyright(c) 2012 Dialog Semiconductor Ltd.
 *
 * Author: David Dajun Chen <dchen@diasemi.com>
 *
 *  This program is free software; you can redistribute  it and/or modify it
 *  under  the terms of  the GNU General  Public License as published by the
 *  Free Software Foundation;  either version 2 of the  License, or (at your
 *  option) any later version.
 *
 */

#include <linux/delay.h>
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/completion.h>

#include <linux/mfd/da9055/core.h>
#include <linux/mfd/da9055/reg.h>


#define DA9055_ADCIN_DIV	102

#define DA9055_VSYS_DIV	85


#define DA9055_ADC_VSYS	0

#define DA9055_ADC_ADCIN1	1

#define DA9055_ADC_ADCIN2	2

#define DA9055_ADC_ADCIN3	3

#define DA9055_ADC_TJUNC	4


struct da9055_hwmon {
	
struct da9055	*da9055;
	
struct mutex	hwmon_lock;
	
struct mutex	irq_lock;
	
struct completion done;
};


static const char * const input_names[] = {
	[DA9055_ADC_VSYS]	= "VSYS",
	[DA9055_ADC_ADCIN1]	= "ADC IN1",
	[DA9055_ADC_ADCIN2]	= "ADC IN2",
	[DA9055_ADC_ADCIN3]	= "ADC IN3",
	[DA9055_ADC_TJUNC]	= "CHIP TEMP",
};


static const u8 chan_mux[DA9055_ADC_TJUNC + 1] = {
	[DA9055_ADC_VSYS]	= DA9055_ADC_MUX_VSYS,
	[DA9055_ADC_ADCIN1]	= DA9055_ADC_MUX_ADCIN1,
	[DA9055_ADC_ADCIN2]	= DA9055_ADC_MUX_ADCIN2,
	[DA9055_ADC_ADCIN3]	= DA9055_ADC_MUX_ADCIN3,
	[DA9055_ADC_TJUNC]	= DA9055_ADC_MUX_T_SENSE,
};


static int da9055_adc_manual_read(struct da9055_hwmon *hwmon, unsigned char channel) { int ret; unsigned short calc_data; unsigned short data; unsigned char mux_sel; struct da9055 *da9055 = hwmon->da9055; if (channel > DA9055_ADC_TJUNC) return -EINVAL; mutex_lock(&hwmon->irq_lock); /* Selects desired MUX for manual conversion */ mux_sel = chan_mux[channel] | DA9055_ADC_MAN_CONV; ret = da9055_reg_write(da9055, DA9055_REG_ADC_MAN, mux_sel); if (ret < 0) goto err; /* Wait for an interrupt */ if (!wait_for_completion_timeout(&hwmon->done, msecs_to_jiffies(500))) { dev_err(da9055->dev, "timeout waiting for ADC conversion interrupt\n"); ret = -ETIMEDOUT; goto err; } ret = da9055_reg_read(da9055, DA9055_REG_ADC_RES_H); if (ret < 0) goto err; calc_data = (unsigned short)ret; data = calc_data << 2; ret = da9055_reg_read(da9055, DA9055_REG_ADC_RES_L); if (ret < 0) goto err; calc_data = (unsigned short)(ret & DA9055_ADC_LSB_MASK); data |= calc_data; ret = data; err: mutex_unlock(&hwmon->irq_lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
ashish jangamashish jangam206100.00%1100.00%
Total206100.00%1100.00%


static irqreturn_t da9055_auxadc_irq(int irq, void *irq_data) { struct da9055_hwmon *hwmon = irq_data; complete(&hwmon->done); return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
ashish jangamashish jangam31100.00%1100.00%
Total31100.00%1100.00%

/* Conversion function for VSYS and ADCINx */
static inline int volt_reg_to_mv(int value, int channel) { if (channel == DA9055_ADC_VSYS) return DIV_ROUND_CLOSEST(value * 1000, DA9055_VSYS_DIV) + 2500; else return DIV_ROUND_CLOSEST(value * 1000, DA9055_ADCIN_DIV); }

Contributors

PersonTokensPropCommitsCommitProp
ashish jangamashish jangam4197.62%150.00%
guenter roeckguenter roeck12.38%150.00%
Total42100.00%2100.00%


static int da9055_enable_auto_mode(struct da9055 *da9055, int channel) { return da9055_reg_update(da9055, DA9055_REG_ADC_CONT, 1 << channel, 1 << channel); }

Contributors

PersonTokensPropCommitsCommitProp
ashish jangamashish jangam30100.00%1100.00%
Total30100.00%1100.00%


static int da9055_disable_auto_mode(struct da9055 *da9055, int channel) { return da9055_reg_update(da9055, DA9055_REG_ADC_CONT, 1 << channel, 0); }

Contributors

PersonTokensPropCommitsCommitProp
ashish jangamashish jangam28100.00%1100.00%
Total28100.00%1100.00%


static ssize_t da9055_read_auto_ch(struct device *dev, struct device_attribute *devattr, char *buf) { struct da9055_hwmon *hwmon = dev_get_drvdata(dev); int ret, adc; int channel = to_sensor_dev_attr(devattr)->index; mutex_lock(&hwmon->hwmon_lock); ret = da9055_enable_auto_mode(hwmon->da9055, channel); if (ret < 0) goto hwmon_err; usleep_range(10000, 10500); adc = da9055_reg_read(hwmon->da9055, DA9055_REG_VSYS_RES + channel); if (adc < 0) { ret = adc; goto hwmon_err_release; } ret = da9055_disable_auto_mode(hwmon->da9055, channel); if (ret < 0) goto hwmon_err; mutex_unlock(&hwmon->hwmon_lock); return sprintf(buf, "%d\n", volt_reg_to_mv(adc, channel)); hwmon_err_release: da9055_disable_auto_mode(hwmon->da9055, channel); hwmon_err: mutex_unlock(&hwmon->hwmon_lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
ashish jangamashish jangam17499.43%150.00%
guenter roeckguenter roeck10.57%150.00%
Total175100.00%2100.00%


static ssize_t da9055_read_tjunc(struct device *dev, struct device_attribute *devattr, char *buf) { struct da9055_hwmon *hwmon = dev_get_drvdata(dev); int tjunc; int toffset; tjunc = da9055_adc_manual_read(hwmon, DA9055_ADC_TJUNC); if (tjunc < 0) return tjunc; toffset = da9055_reg_read(hwmon->da9055, DA9055_REG_T_OFFSET); if (toffset < 0) return toffset; /* * Degrees celsius = -0.4084 * (ADC_RES - T_OFFSET) + 307.6332 * T_OFFSET is a trim value used to improve accuracy of the result */ return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(-4084 * (tjunc - toffset) + 3076332, 10000)); }

Contributors

PersonTokensPropCommitsCommitProp
ashish jangamashish jangam99100.00%1100.00%
Total99100.00%1100.00%


static ssize_t show_label(struct device *dev, struct device_attribute *devattr, char *buf) { return sprintf(buf, "%s\n", input_names[to_sensor_dev_attr(devattr)->index]); }

Contributors

PersonTokensPropCommitsCommitProp
ashish jangamashish jangam38100.00%1100.00%
Total38100.00%1100.00%

static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, da9055_read_auto_ch, NULL, DA9055_ADC_VSYS); static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL, DA9055_ADC_VSYS); static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, da9055_read_auto_ch, NULL, DA9055_ADC_ADCIN1); static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_label, NULL, DA9055_ADC_ADCIN1); static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, da9055_read_auto_ch, NULL, DA9055_ADC_ADCIN2); static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_label, NULL, DA9055_ADC_ADCIN2); static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, da9055_read_auto_ch, NULL, DA9055_ADC_ADCIN3); static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, DA9055_ADC_ADCIN3); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, da9055_read_tjunc, NULL, DA9055_ADC_TJUNC); static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL, DA9055_ADC_TJUNC); static struct attribute *da9055_attrs[] = { &sensor_dev_attr_in0_input.dev_attr.attr, &sensor_dev_attr_in0_label.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_in1_label.dev_attr.attr, &sensor_dev_attr_in2_input.dev_attr.attr, &sensor_dev_attr_in2_label.dev_attr.attr, &sensor_dev_attr_in3_input.dev_attr.attr, &sensor_dev_attr_in3_label.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_label.dev_attr.attr, NULL }; ATTRIBUTE_GROUPS(da9055);
static int da9055_hwmon_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct da9055_hwmon *hwmon; struct device *hwmon_dev; int hwmon_irq, ret; hwmon = devm_kzalloc(dev, sizeof(struct da9055_hwmon), GFP_KERNEL); if (!hwmon) return -ENOMEM; mutex_init(&hwmon->hwmon_lock); mutex_init(&hwmon->irq_lock); init_completion(&hwmon->done); hwmon->da9055 = dev_get_drvdata(pdev->dev.parent); hwmon_irq = platform_get_irq_byname(pdev, "HWMON"); if (hwmon_irq < 0) return hwmon_irq; ret = devm_request_threaded_irq(&pdev->dev, hwmon_irq, NULL, da9055_auxadc_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "adc-irq", hwmon); if (ret != 0) { dev_err(hwmon->da9055->dev, "DA9055 ADC IRQ failed ret=%d\n", ret); return ret; } hwmon_dev = devm_hwmon_device_register_with_groups(dev, "da9055", hwmon, da9055_groups); return PTR_ERR_OR_ZERO(hwmon_dev); }

Contributors

PersonTokensPropCommitsCommitProp
ashish jangamashish jangam16087.91%150.00%
axel linaxel lin2212.09%150.00%
Total182100.00%2100.00%

static struct platform_driver da9055_hwmon_driver = { .probe = da9055_hwmon_probe, .driver = { .name = "da9055-hwmon", }, }; module_platform_driver(da9055_hwmon_driver); MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); MODULE_DESCRIPTION("DA9055 HWMON driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:da9055-hwmon");

Overall Contributors

PersonTokensPropCommitsCommitProp
ashish jangamashish jangam124097.56%125.00%
axel linaxel lin292.28%250.00%
guenter roeckguenter roeck20.16%125.00%
Total1271100.00%4100.00%
Directory: drivers/hwmon
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}