cregit-Linux how code gets into the kernel

Release 4.7 drivers/hwmon/pcf8591.c

Directory: drivers/hwmon
/*
 * Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net>
 * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
 * the help of Jean Delvare <jdelvare@suse.de>
 *
 * 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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/hwmon.h>

/* Insmod parameters */


static int input_mode;
module_param(input_mode, int, 0);
MODULE_PARM_DESC(input_mode,
	"Analog input mode:\n"
	" 0 = four single ended inputs\n"
	" 1 = three differential inputs\n"
	" 2 = single ended and differential mixed\n"
	" 3 = two differential inputs\n");

/*
 * The PCF8591 control byte
 *      7    6    5    4    3    2    1    0
 *   |  0 |AOEF|   AIP   |  0 |AINC|  AICH   |
 */

/* Analog Output Enable Flag (analog output active if 1) */

#define PCF8591_CONTROL_AOEF		0x40

/*
 * Analog Input Programming
 * 0x00 = four single ended inputs
 * 0x10 = three differential inputs
 * 0x20 = single ended and differential mixed
 * 0x30 = two differential inputs
 */

#define PCF8591_CONTROL_AIP_MASK	0x30

/* Autoincrement Flag (switch on if 1) */

#define PCF8591_CONTROL_AINC		0x04

/*
 * Channel selection
 * 0x00 = channel 0
 * 0x01 = channel 1
 * 0x02 = channel 2
 * 0x03 = channel 3
 */

#define PCF8591_CONTROL_AICH_MASK	0x03

/* Initial values */

#define PCF8591_INIT_CONTROL	((input_mode << 4) | PCF8591_CONTROL_AOEF)

#define PCF8591_INIT_AOUT	0	
/* DAC out = 0 */

/* Conversions */

#define REG_TO_SIGNED(reg)	(((reg) & 0x80) ? ((reg) - 256) : (reg))


struct pcf8591_data {
	
struct device *hwmon_dev;
	
struct mutex update_lock;

	
u8 control;
	
u8 aout;
};

static void pcf8591_init_client(struct i2c_client *client);
static int pcf8591_read_channel(struct device *dev, int channel);

/* following are the sysfs callback functions */

#define show_in_channel(channel)					\
static ssize_t show_in##channel##_input(struct device *dev,             \
                                        struct device_attribute *attr,  \
                                        char *buf)                      \
{                                                                       \
        return sprintf(buf, "%d\n", pcf8591_read_channel(dev, channel));\
}                                                                       \
static DEVICE_ATTR(in##channel##_input, S_IRUGO,                        \
                   show_in##channel##_input, NULL);

show_in_channel(0);
show_in_channel(1);
show_in_channel(2);
show_in_channel(3);


static ssize_t show_out0_ouput(struct device *dev, struct device_attribute *attr, char *buf) { struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); return sprintf(buf, "%d\n", data->aout * 10); }

Contributors

PersonTokensPropCommitsCommitProp
aurelien jarnoaurelien jarno4289.36%150.00%
yani ioannouyani ioannou510.64%150.00%
Total47100.00%2100.00%


static ssize_t set_out0_output(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long val; struct i2c_client *client = to_i2c_client(dev); struct pcf8591_data *data = i2c_get_clientdata(client); int err; err = kstrtoul(buf, 10, &val); if (err) return err; val /= 10; if (val > 255) return -EINVAL; data->aout = val; i2c_smbus_write_byte_data(client, data->control, data->aout); return count; }

Contributors

PersonTokensPropCommitsCommitProp
aurelien jarnoaurelien jarno7166.98%133.33%
guenter roeckguenter roeck3028.30%133.33%
yani ioannouyani ioannou54.72%133.33%
Total106100.00%3100.00%

static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO, show_out0_ouput, set_out0_output);
static ssize_t show_out0_enable(struct device *dev, struct device_attribute *attr, char *buf) { struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); return sprintf(buf, "%u\n", !(!(data->control & PCF8591_CONTROL_AOEF))); }

Contributors

PersonTokensPropCommitsCommitProp
aurelien jarnoaurelien jarno4890.57%150.00%
yani ioannouyani ioannou59.43%150.00%
Total53100.00%2100.00%


static ssize_t set_out0_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct pcf8591_data *data = i2c_get_clientdata(client); unsigned long val; int err; err = kstrtoul(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); if (val) data->control |= PCF8591_CONTROL_AOEF; else data->control &= ~PCF8591_CONTROL_AOEF; i2c_smbus_write_byte(client, data->control); mutex_unlock(&data->update_lock); return count; }

Contributors

PersonTokensPropCommitsCommitProp
aurelien jarnoaurelien jarno7161.21%120.00%
jean delvarejean delvare2017.24%120.00%
guenter roeckguenter roeck1815.52%120.00%
yani ioannouyani ioannou54.31%120.00%
ingo molnaringo molnar21.72%120.00%
Total116100.00%5100.00%

static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO, show_out0_enable, set_out0_enable); static struct attribute *pcf8591_attributes[] = { &dev_attr_out0_enable.attr, &dev_attr_out0_output.attr, &dev_attr_in0_input.attr, &dev_attr_in1_input.attr, NULL }; static const struct attribute_group pcf8591_attr_group = { .attrs = pcf8591_attributes, }; static struct attribute *pcf8591_attributes_opt[] = { &dev_attr_in2_input.attr, &dev_attr_in3_input.attr, NULL }; static const struct attribute_group pcf8591_attr_group_opt = { .attrs = pcf8591_attributes_opt, }; /* * Real code */
static int pcf8591_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pcf8591_data *data; int err; data = devm_kzalloc(&client->dev, sizeof(struct pcf8591_data), GFP_KERNEL); if (!data) return -ENOMEM; i2c_set_clientdata(client, data); mutex_init(&data->update_lock); /* Initialize the PCF8591 chip */ pcf8591_init_client(client); /* Register sysfs hooks */ err = sysfs_create_group(&client->dev.kobj, &pcf8591_attr_group); if (err) return err; /* Register input2 if not in "two differential inputs" mode */ if (input_mode != 3) { err = device_create_file(&client->dev, &dev_attr_in2_input); if (err) goto exit_sysfs_remove; } /* Register input3 only in "four single ended inputs" mode */ if (input_mode == 0) { err = device_create_file(&client->dev, &dev_attr_in3_input); if (err) goto exit_sysfs_remove; } data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto exit_sysfs_remove; } return 0; exit_sysfs_remove: sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt); sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group); return err; }

Contributors

PersonTokensPropCommitsCommitProp
jean delvarejean delvare10647.53%550.00%
aurelien jarnoaurelien jarno9140.81%110.00%
guenter roeckguenter roeck2410.76%220.00%
ingo molnaringo molnar10.45%110.00%
ben dooksben dooks10.45%110.00%
Total223100.00%10100.00%


static int pcf8591_remove(struct i2c_client *client) { struct pcf8591_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt); sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jean delvarejean delvare4477.19%375.00%
aurelien jarnoaurelien jarno1322.81%125.00%
Total57100.00%4100.00%

/* Called when we have found a new PCF8591. */
static void pcf8591_init_client(struct i2c_client *client) { struct pcf8591_data *data = i2c_get_clientdata(client); data->control = PCF8591_INIT_CONTROL; data->aout = PCF8591_INIT_AOUT; i2c_smbus_write_byte_data(client, data->control, data->aout); /* * The first byte transmitted contains the conversion code of the * previous read cycle. FLUSH IT! */ i2c_smbus_read_byte(client); }

Contributors

PersonTokensPropCommitsCommitProp
aurelien jarnoaurelien jarno5198.08%150.00%
guenter roeckguenter roeck11.92%150.00%
Total52100.00%2100.00%


static int pcf8591_read_channel(struct device *dev, int channel) { u8 value; struct i2c_client *client = to_i2c_client(dev); struct pcf8591_data *data = i2c_get_clientdata(client); mutex_lock(&data->update_lock); if ((data->control & PCF8591_CONTROL_AICH_MASK) != channel) { data->control = (data->control & ~PCF8591_CONTROL_AICH_MASK) | channel; i2c_smbus_write_byte(client, data->control); /* * The first byte transmitted contains the conversion code of * the previous read cycle. FLUSH IT! */ i2c_smbus_read_byte(client); } value = i2c_smbus_read_byte(client); mutex_unlock(&data->update_lock); if ((channel == 2 && input_mode == 2) || (channel != 3 && (input_mode == 1 || input_mode == 3))) return 10 * REG_TO_SIGNED(value); else return 10 * value; }

Contributors

PersonTokensPropCommitsCommitProp
aurelien jarnoaurelien jarno14397.95%133.33%
ingo molnaringo molnar21.37%133.33%
guenter roeckguenter roeck10.68%133.33%
Total146100.00%3100.00%

static const struct i2c_device_id pcf8591_id[] = { { "pcf8591", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, pcf8591_id); static struct i2c_driver pcf8591_driver = { .driver = { .name = "pcf8591", }, .probe = pcf8591_probe, .remove = pcf8591_remove, .id_table = pcf8591_id, };
static int __init pcf8591_init(void) { if (input_mode < 0 || input_mode > 3) { pr_warn("invalid input_mode (%d)\n", input_mode); input_mode = 0; } return i2c_add_driver(&pcf8591_driver); }

Contributors

PersonTokensPropCommitsCommitProp
aurelien jarnoaurelien jarno3794.87%150.00%
joe perchesjoe perches25.13%150.00%
Total39100.00%2100.00%


static void __exit pcf8591_exit(void) { i2c_del_driver(&pcf8591_driver); }

Contributors

PersonTokensPropCommitsCommitProp
aurelien jarnoaurelien jarno15100.00%1100.00%
Total15100.00%1100.00%

MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>"); MODULE_DESCRIPTION("PCF8591 driver"); MODULE_LICENSE("GPL"); module_init(pcf8591_init); module_exit(pcf8591_exit);

Overall Contributors

PersonTokensPropCommitsCommitProp
aurelien jarnoaurelien jarno77063.74%16.67%
jean delvarejean delvare31626.16%746.67%
guenter roeckguenter roeck796.54%213.33%
yani ioannouyani ioannou201.66%16.67%
ingo molnaringo molnar90.75%16.67%
joe perchesjoe perches90.75%16.67%
greg kroah-hartmangreg kroah-hartman40.33%16.67%
ben dooksben dooks10.08%16.67%
Total1208100.00%15100.00%
Directory: drivers/hwmon
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}