[go: nahoru, domu]

15510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo/*
2592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann * mcp3021.c - driver for Microchip MCP3021 and MCP3221
35510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo *
45510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo * Copyright (C) 2008-2009, 2012 Freescale Semiconductor, Inc.
55510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo * Author: Mingkai Hu <Mingkai.hu@freescale.com>
68b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann * Reworked by Sven Schuchmann <schuchmann@schleissheimer.de>
75510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo *
85510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo * This driver export the value of analog input voltage to sysfs, the
95510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo * voltage unit is mV. Through the sysfs interface, lm-sensors tool
105510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo * can also display the input voltage.
115510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo *
125510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo * This program is free software; you can redistribute it and/or modify
135510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo * it under the terms of the GNU General Public License as published by
145510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo * the Free Software Foundation; either version 2 of the License, or
155510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo * (at your option) any later version.
165510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo */
175510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
185510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo#include <linux/kernel.h>
195510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo#include <linux/module.h>
205510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo#include <linux/hwmon.h>
215510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo#include <linux/slab.h>
225510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo#include <linux/i2c.h>
235510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo#include <linux/err.h>
245510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo#include <linux/device.h>
255510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
265510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo/* Vdd info */
275510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo#define MCP3021_VDD_MAX		5500
285510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo#define MCP3021_VDD_MIN		2700
295510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo#define MCP3021_VDD_REF		3300
305510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
315510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo/* output format */
325510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo#define MCP3021_SAR_SHIFT	2
335510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo#define MCP3021_SAR_MASK	0x3ff
345510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
355510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo#define MCP3021_OUTPUT_RES	10	/* 10-bit resolution */
365510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo#define MCP3021_OUTPUT_SCALE	4
375510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
38592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann#define MCP3221_SAR_SHIFT	0
39592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann#define MCP3221_SAR_MASK	0xfff
40592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann#define MCP3221_OUTPUT_RES	12	/* 12-bit resolution */
41592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann#define MCP3221_OUTPUT_SCALE	1
42592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann
438b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmannenum chips {
44592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann	mcp3021,
45592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann	mcp3221
468b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann};
47592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann
485510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo/*
495510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo * Client data (each client gets its own)
505510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo */
515510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobostruct mcp3021_data {
525510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	struct device *hwmon_dev;
535510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	u32 vdd;	/* device power supply */
548b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann	u16 sar_shift;
558b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann	u16 sar_mask;
568b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann	u8 output_res;
578b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann	u8 output_scale;
585510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo};
595510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
605510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobostatic int mcp3021_read16(struct i2c_client *client)
615510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo{
628b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann	struct mcp3021_data *data = i2c_get_clientdata(client);
635510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	int ret;
645510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	u16 reg;
655510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	__be16 buf;
665510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
675510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	ret = i2c_master_recv(client, (char *)&buf, 2);
685510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	if (ret < 0)
695510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo		return ret;
705510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	if (ret != 2)
715510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo		return -EIO;
725510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
735510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	/* The output code of the MCP3021 is transmitted with MSB first. */
745510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	reg = be16_to_cpu(buf);
755510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
765510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	/*
775510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	 * The ten-bit output code is composed of the lower 4-bit of the
785510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	 * first byte and the upper 6-bit of the second byte.
795510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	 */
808b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann	reg = (reg >> data->sar_shift) & data->sar_mask;
815510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
825510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	return reg;
835510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo}
845510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
858b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmannstatic inline u16 volts_from_reg(struct mcp3021_data *data, u16 val)
865510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo{
875510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	if (val == 0)
885510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo		return 0;
895510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
908b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann	val = val * data->output_scale - data->output_scale / 2;
915510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
928b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann	return val * DIV_ROUND_CLOSEST(data->vdd,
938b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann			(1 << data->output_res) * data->output_scale);
945510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo}
955510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
965510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobostatic ssize_t show_in_input(struct device *dev, struct device_attribute *attr,
975510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo		char *buf)
985510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo{
995510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	struct i2c_client *client = to_i2c_client(dev);
1005510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	struct mcp3021_data *data = i2c_get_clientdata(client);
1015510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	int reg, in_input;
1025510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1035510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	reg = mcp3021_read16(client);
1045510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	if (reg < 0)
1055510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo		return reg;
1065510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1078b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann	in_input = volts_from_reg(data, reg);
1088b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann
1095510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	return sprintf(buf, "%d\n", in_input);
1105510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo}
1115510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1125510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobostatic DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL);
1135510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1145510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobostatic int mcp3021_probe(struct i2c_client *client,
1155510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo				const struct i2c_device_id *id)
1165510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo{
1175510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	int err;
1185510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	struct mcp3021_data *data = NULL;
1195510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1205510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
1215510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo		return -ENODEV;
1225510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
12379831fd4e0820bdc882d08707e4650ed4dfff3b8Guenter Roeck	data = devm_kzalloc(&client->dev, sizeof(struct mcp3021_data),
12479831fd4e0820bdc882d08707e4650ed4dfff3b8Guenter Roeck			    GFP_KERNEL);
1255510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	if (!data)
1265510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo		return -ENOMEM;
1275510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1285510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	i2c_set_clientdata(client, data);
1295510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1308b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann	switch (id->driver_data) {
1318b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann	case mcp3021:
1328b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann		data->sar_shift = MCP3021_SAR_SHIFT;
1338b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann		data->sar_mask = MCP3021_SAR_MASK;
1348b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann		data->output_res = MCP3021_OUTPUT_RES;
1358b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann		data->output_scale = MCP3021_OUTPUT_SCALE;
1368b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann		break;
137592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann
138592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann	case mcp3221:
139592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann		data->sar_shift = MCP3221_SAR_SHIFT;
140592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann		data->sar_mask = MCP3221_SAR_MASK;
141592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann		data->output_res = MCP3221_OUTPUT_RES;
142592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann		data->output_scale = MCP3221_OUTPUT_SCALE;
143592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann		break;
1448b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann	}
1458b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann
146a8b3a3a53f9a814e9938ea9cc179086ff5c0a387Jingoo Han	if (dev_get_platdata(&client->dev)) {
147a8b3a3a53f9a814e9938ea9cc179086ff5c0a387Jingoo Han		data->vdd = *(u32 *)dev_get_platdata(&client->dev);
14879831fd4e0820bdc882d08707e4650ed4dfff3b8Guenter Roeck		if (data->vdd > MCP3021_VDD_MAX || data->vdd < MCP3021_VDD_MIN)
14979831fd4e0820bdc882d08707e4650ed4dfff3b8Guenter Roeck			return -EINVAL;
150a8b3a3a53f9a814e9938ea9cc179086ff5c0a387Jingoo Han	} else {
1515510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo		data->vdd = MCP3021_VDD_REF;
152a8b3a3a53f9a814e9938ea9cc179086ff5c0a387Jingoo Han	}
1535510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1545510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr);
1555510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	if (err)
15679831fd4e0820bdc882d08707e4650ed4dfff3b8Guenter Roeck		return err;
1575510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1585510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	data->hwmon_dev = hwmon_device_register(&client->dev);
1595510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	if (IS_ERR(data->hwmon_dev)) {
1605510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo		err = PTR_ERR(data->hwmon_dev);
1615510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo		goto exit_remove;
1625510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	}
1635510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1645510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	return 0;
1655510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1665510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaoboexit_remove:
1675510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
1685510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	return err;
1695510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo}
1705510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1715510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobostatic int mcp3021_remove(struct i2c_client *client)
1725510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo{
1735510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	struct mcp3021_data *data = i2c_get_clientdata(client);
1745510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1755510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	hwmon_device_unregister(data->hwmon_dev);
1765510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
1775510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1785510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	return 0;
1795510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo}
1805510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1815510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobostatic const struct i2c_device_id mcp3021_id[] = {
1828b662f38e066d8fc1b73a8655da547c348206904Sven Schuchmann	{ "mcp3021", mcp3021 },
183592758b12f2e327bb5902dabd3d36b2e86049871Sven Schuchmann	{ "mcp3221", mcp3221 },
1845510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	{ }
1855510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo};
1865510e62a66bad22b104d5d854445523d7f5754f7Xie XiaoboMODULE_DEVICE_TABLE(i2c, mcp3021_id);
1875510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1885510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobostatic struct i2c_driver mcp3021_driver = {
1895510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	.driver = {
1905510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo		.name = "mcp3021",
1915510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	},
1925510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	.probe = mcp3021_probe,
1935510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	.remove = mcp3021_remove,
1945510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo	.id_table = mcp3021_id,
1955510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo};
1965510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1975510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobomodule_i2c_driver(mcp3021_driver);
1985510e62a66bad22b104d5d854445523d7f5754f7Xie Xiaobo
1995510e62a66bad22b104d5d854445523d7f5754f7Xie XiaoboMODULE_AUTHOR("Mingkai Hu <Mingkai.hu@freescale.com>");
200592758b12f2e327bb5902dabd3d36b2e86049871Sven SchuchmannMODULE_DESCRIPTION("Microchip MCP3021/MCP3221 driver");
2015510e62a66bad22b104d5d854445523d7f5754f7Xie XiaoboMODULE_LICENSE("GPL");
202