On 05/21/10 13:17, Datta, Shubhrajyoti wrote:
> 
> Adds the driver support for the TMP105 temperature sensor device. The 
> interface is I2C.The driver supports the read of the temperature values.
> 
> Signed-off-by: Shubhrajyoti D <[email protected]>
This device looks at first glance to be pretty similar to the TMP101 as 
supported
by the lm75 driver.  Would it make more sense to merge this support into that
driver?

I've not read the data sheets that closely so may have missed something!

Couple of nitpicks below.
> ---
>  drivers/hwmon/Kconfig  |   10 ++
>  drivers/hwmon/Makefile |    1 +
>  drivers/hwmon/tmp105.c |  326 
> ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 337 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/hwmon/tmp105.c
> 
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 68cf877..a4a5352 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -1076,6 +1076,16 @@ config SENSORS_MC13783_ADC
>          help
>            Support for the A/D converter on MC13783 PMIC.
>  
> +config SENSORS_TMP105
> +     tristate "Texas Instruments TMP421 and compatible"
 TMP105 or TMP421? 
> +     depends on I2C
> +     help
> +       If you say yes here you get support for Texas Instruments TMP105
> +       temperature sensor chips.
> +
> +       This driver can also be built as a module.  If so, the module
> +       will be called tmp105.
> +
>  if ACPI
>  
>  comment "ACPI drivers"
> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> index 4bc215c..2c4e7a5 100644
> --- a/drivers/hwmon/Makefile
> +++ b/drivers/hwmon/Makefile
> @@ -99,6 +99,7 @@ obj-$(CONFIG_SENSORS_W83L785TS)     += w83l785ts.o
>  obj-$(CONFIG_SENSORS_W83L786NG)      += w83l786ng.o
>  obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
>  obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
> +obj-$(CONFIG_SENSORS_TMP105)    += tmp105.o
>  
>  ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
>  EXTRA_CFLAGS += -DDEBUG
> diff --git a/drivers/hwmon/tmp105.c b/drivers/hwmon/tmp105.c
> new file mode 100644
> index 0000000..8765b11
> --- /dev/null
> +++ b/drivers/hwmon/tmp105.c
> @@ -0,0 +1,326 @@
> +/*
> + * tmp105.c
> + *
> + * TMP105 temperature sensor driver
> + *
> + * Copyright (C) 2010 Texas Instruments
> + *
> + * Author: Shubhrajyoti Datta <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published 
> by
> + * the Free Software Foundation.
> + *
> + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> +*/
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/i2c.h>
> +#include <linux/kernel.h>
> +#include <linux/hwmon.h>
> +#include <linux/hwmon-sysfs.h>
> +#include <linux/err.h>
> +#include <linux/slab.h>
> +
> +/* Registers */
> +#define              TMP105_TEMP_REG         0x00
> +#define              TMP105_CONF_REG         0x01
> +#define              TMP105_TLOW_REG         0x02
> +#define              TMP105_THIGH_REG        0x03
> +
> +/* Configuration register parameters */
> +#define              TMP105_CONF_SD          0x01
> +#define              TMP105_CONF_TM          0x02
> +#define              TMP105_CONF_POL         0x04
> +#define              TMP105_CONF_F0          0x08
> +#define              TMP105_CONF_F1          0x10
> +#define              TMP105_CONF_R0          0x20
> +#define              TMP105_CONF_R1          0x40
> +#define              TMP105_CONF_OS          0x80
> +
> +#define      TMP105_I2C_ADDRESS      0x48
> +
> +#define         MAX_TEMP             128
> +#define         MIN_TEMP             -55
> +
> +/* Each client has this additional data */
> +struct tmp105_data {
> +     struct i2c_client *client;
> +     /* mutex for sysfs operations */
> +     struct mutex lock;
> +     struct device *hwmon_dev;
> +     s16 temp[3];
> +     unsigned long last_updated;
> +     u8 configuration_setting;
> +};
> +
> +static const u8 tmp105_reg[] = {
> +     TMP105_TEMP_REG,
> +     TMP105_TLOW_REG,
> +     TMP105_THIGH_REG,
> +};
> +
> +static void tmp105_init_client(struct i2c_client *client);
> +
> +static signed long tmp105_reg_to_mC(s16 val)
> +{
> +     signed long temp_mC;
> +     if (val  & 0x800)
> +             val = val - 0x1000 ;
Stray space.

> +      temp_mC = (val * 64000) / 1024;
> +      return temp_mC;
> +}
> +
> +static u16 tmp105_C_to_reg(signed long val)
> +{
> +     val =  (val * 1024) / 64000;
> +     if (val < 0)
> +             val = val + 0x1000;
> +     return (u16)val;
> +}
> +
> +static s16 *tmp105_update_device(struct i2c_client *client,
> +                                             int  index)
> +{
> +     struct tmp105_data *data = i2c_get_clientdata(client);
> +     u8 tmp[2];
> +
> +     mutex_lock(&data->lock);
> +
> +     if (time_after(jiffies, data->last_updated +  HZ/4)) {
> +             i2c_smbus_read_i2c_block_data(client,
> +                                             tmp105_reg[index], 2, tmp);
> +             data->temp[index] = ((tmp[0] << 4) | ((tmp[1] & 0xF0) >> 4));
> +             printk(KERN_INFO "Raw temperature: %u\n", data->temp[index]);
> +             data->last_updated = jiffies;
> +     }
> +
> +     mutex_unlock(&data->lock);
> +     return data->temp[index] ;
> +}
> +
> +static ssize_t show_temp_value(struct device *dev,
> +                            struct device_attribute *devattr, char *buf)
> +{
> +     struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr);
> +     struct i2c_client *client = to_i2c_client(dev);
> +     s16 temperature = tmp105_update_device(client , sda->index);
> +     signed long temp_in_mC;
> +
> +     temp_in_mC = tmp105_reg_to_mC(temperature);
> +
> +     return sprintf(buf, "%d\n", temp_in_mC);
> +}
> +
> +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL , 0);
> +
> +static ssize_t tmp105_set_temp(struct device *dev,
> +                             struct device_attribute *attr,
> +                             const char *buf, size_t count)
> +{
> +     struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
> +     struct i2c_client *client = to_i2c_client(dev);
> +     struct tmp105_data *tmp105 = i2c_get_clientdata(client);
> +     signed long val;
> +     int status = 0;
> +     u16 temp;
> +
> +     if ((strict_strtol(buf, 10, &val) < 0))
> +             return -EINVAL;
> +
> +     SENSORS_LIMIT(val , MIN_TEMP , MAX_TEMP);
> +
> +     mutex_lock(&tmp105->lock);
> +
> +     temp = tmp105_C_to_reg(val);
> +     temp = ((temp & 0xFF0) >> 4) | ((temp & 0xF)<<12);
Random spacing 

> +
> +     status = i2c_smbus_write_word_data(client, tmp105_reg[sda->index],
> +                     temp);
> +
> +     tmp105->temp[sda->index] = temp;
> +     mutex_unlock(&tmp105->lock);
> +     return status ? : count;
> +}
> +
> +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_value,
> +     tmp105_set_temp, 1);
> +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_value,
> +     tmp105_set_temp, 2);
> +
> +/* sysfs call */
> +static ssize_t set_configuration(struct device *dev,
> +                             struct device_attribute *attr,
> +                             const char *buf, size_t count)
> +{
> +     s32 status;
> +     struct i2c_client *client = to_i2c_client(dev);
> +     struct tmp105_data *data = i2c_get_clientdata(client);
> +     data->configuration_setting = simple_strtoul(buf, NULL, 10);
> +     /* I2C write to the configuration register */
> +     status = i2c_smbus_write_byte_data(client, TMP105_CONF_REG,
> +                     data->configuration_setting);
What's status for given you don't take any notice of it?

> +     return count;
> +}
> +
> +static ssize_t show_configuration(struct device *dev,
> +                             struct device_attribute *attr, char *buf)
> +{
> +     struct i2c_client *client = to_i2c_client(dev);
> +     struct tmp105_data *data = i2c_get_clientdata(client);
> +     u8 tmp;
> +     i2c_smbus_read_i2c_block_data(client, TMP105_CONF_REG, 1, &tmp);
> +     data->configuration_setting = tmp;
> +     return sprintf(buf, "%u\n", data->configuration_setting);
> +}
> +static DEVICE_ATTR(configuration, S_IWUSR | S_IRUGO, show_configuration,
> +             set_configuration);
> +
> +
> +static struct attribute *tmp105_attributes[] = {
> +     &dev_attr_configuration.attr,
> +     &sensor_dev_attr_temp1_input.dev_attr.attr,
> +     &sensor_dev_attr_temp1_min.dev_attr.attr,
> +     &sensor_dev_attr_temp1_max.dev_attr.attr,
> +     NULL
> +};
> +
> +static const struct attribute_group tmp105_attr_group = {
> +     .attrs = tmp105_attributes,
> +};
> +
> +static int tmp105_probe(struct i2c_client *client,
> +                      const struct i2c_device_id *id)
> +{
> +     struct tmp105_data *tmp105_data;
> +     int err;
> +
> +     if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> +             dev_dbg(&client->dev, "adapter doesn't support I2C\n");
> +             return -ENODEV;
> +     }
> +
> +     tmp105_data = kzalloc(sizeof(struct tmp105_data), GFP_KERNEL);
> +     if (!tmp105_data) {
> +             err = -ENOMEM;
> +             goto exit;
> +     }
> +     tmp105_data->client = client;
> +
> +     i2c_set_clientdata(client, tmp105_data);
> +     mutex_init(&tmp105_data->lock);
> +
> +     /* Initialize the TMP105 chip */
> +     tmp105_init_client(client);
> +
> +     /* Register sysfs hooks */
> +     err = sysfs_create_group(&client->dev.kobj, &tmp105_attr_group);
> +     if (err)
> +             goto exit_free;
> +     tmp105_data->hwmon_dev = hwmon_device_register(&client->dev);
> +     if (IS_ERR(tmp105_data->hwmon_dev)) {
> +             err = PTR_ERR(tmp105_data->hwmon_dev);
> +             tmp105_data->hwmon_dev = NULL;
> +             goto exit_remove;
> +     }
> +     return 0;
> +
> +exit_remove:
> +     sysfs_remove_group(&client->dev.kobj, &tmp105_attr_group);
> +exit_free:
> +     i2c_set_clientdata(client, NULL);
> +     kfree(tmp105_data);
> +exit:
> +     return err;
> +}
> +
> +static int tmp105_remove(struct i2c_client *client)
> +{
> +     struct tmp105_data *tmp105 = i2c_get_clientdata(client);
> +     hwmon_device_unregister(tmp105->hwmon_dev);
> +
> +     sysfs_remove_group(&client->dev.kobj, &tmp105_attr_group);
> +     i2c_set_clientdata(client, NULL);
> +     kfree(tmp105);
> +     return 0;
> +}
> +
> +/* Called when we have found a new TMP105. */
> +static void tmp105_init_client(struct i2c_client *client)
> +{
> +     struct tmp105_data *data = i2c_get_clientdata(client);
> +     data->last_updated = jiffies - HZ;
> +     mutex_init(&data->lock);
> +}
> +
> +static const struct i2c_device_id tmp105_id[] = {
> +     { "tmp105", 0 },
> +     { }
> +};
> +
> +#ifdef CONFIG_PM
> +static int tmp105_suspend(struct device *dev)
> +{
> +     struct i2c_client *client = to_i2c_client(dev);
> +     u8 config_reg;
> +     i2c_smbus_read_i2c_block_data(client, TMP105_CONF_REG, 1, &config_reg);
> +     config_reg = config_reg | TMP102_CONF_SD;
> +     i2c_smbus_write_byte_data(client, TMP105_CONF_REG, TMP102_CONF_SD);
> +     return 0;
> +}
> +
> +static int tmp105_resume(struct device *dev)
> +{
> +     struct i2c_client *client = to_i2c_client(dev);
> +     i2c_smbus_read_i2c_block_data(client, TMP105_CONF_REG, 1, &config_reg);
> +     config_reg = config_reg & ~TMP102_CONF_SD;
> +     i2c_smbus_write_byte_data(client, TMP105_CONF_REG, TMP102_CONF_SD);
> +}
> +
> +static struct dev_pm_ops tmp105_dev_pm_ops = {
> +     .suspend = tmp105_suspend,
> +     .resume = tmp105_resume,
> +};
> +
> +#define TMP105_DEV_PM_OPS (&tmp105_dev_pm_ops)
> +#else
> +#define TMP105_DEV_PM_OPS NULL
> +#endif /* CONFIG_PM */
> +
> +
> +static struct i2c_driver tmp105_driver = {
> +     .driver = {
> +             .name   = "tmp105",
> +             .owner = THIS_MODULE,
> +             .pm = TMP105_DEV_PM_OPS,
> +     },
> +     .probe          = tmp105_probe,
> +     .remove         = tmp105_remove,
> +     .id_table       = tmp105_id,
> +     .class = I2C_CLASS_HWMON,
> +};
> +
> +static int __init tmp105_init(void)
> +{
> +     return i2c_add_driver(&tmp105_driver);
> +}
> +
> +static void __exit tmp105_exit(void)
> +{
> +     i2c_del_driver(&tmp105_driver);
> +}
> +
> +MODULE_DESCRIPTION("TMP105 driver");
> +MODULE_LICENSE("GPL");
> +
> +module_init(tmp105_init);
> +module_exit(tmp105_exit);
> +

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to