Merge branch 'linux-tegra-2.6.36' into android-tegra-2.6.36

Conflicts:
	drivers/misc/Kconfig
	drivers/misc/Makefile

Change-Id: I826244513f799fdd2fb0269abad3271c96661293
This commit is contained in:
Colin Cross 2011-01-08 14:47:29 -08:00
commit c07aee9df0
6 changed files with 365 additions and 0 deletions

View File

@ -123,11 +123,34 @@ int tegra_powergate_remove_clamping(int id)
return 0;
}
/* Must be called with clk disabled, and returns with clk enabled */
static int tegra_powergate_reset_module(struct clk *clk)
{
int ret;
tegra_periph_reset_assert(clk);
udelay(10);
ret = clk_enable(clk);
if (ret)
return ret;
udelay(10);
tegra_periph_reset_deassert(clk);
return 0;
}
/* Must be called with clk disabled, and returns with clk enabled */
int tegra_powergate_sequence_power_up(int id, struct clk *clk)
{
int ret;
if (tegra_powergate_is_powered(id))
return tegra_powergate_reset_module(clk);
tegra_periph_reset_assert(clk);
ret = tegra_powergate_power_on(id);

View File

@ -340,6 +340,14 @@ config SENSORS_AK8975
If you say yes here you get support for Asahi Kasei's
orientation sensor AK8975.
config SENSORS_NCT1008
tristate "ON Semiconductor Temperature Sensor"
default n
depends on I2C
help
Say yes here if you wish to include the ON Semiconductor
NCT1008 Temperature sensor.
config EP93XX_PWM
tristate "EP93xx PWM support"
depends on ARCH_EP93XX

View File

@ -41,3 +41,4 @@ obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o
obj-$(CONFIG_WL127X_RFKILL) += wl127x-rfkill.o
obj-$(CONFIG_APANIC) += apanic.o
obj-$(CONFIG_SENSORS_AK8975) += akm8975.o
obj-$(CONFIG_SENSORS_NCT1008) += nct1008.o

291
drivers/misc/nct1008.c Executable file
View File

@ -0,0 +1,291 @@
/*
* drivers/misc/nct1008.c
*
* Driver for NCT1008, temperature monitoring device from ON Semiconductors
*
* Copyright (c) 2010, NVIDIA Corporation.
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/nct1008.h>
#define DRIVER_NAME "nct1008"
/* Register Addresses */
#define LOCAL_TEMP_RD 0x00
#define STATUS_RD 0x02
#define CONFIG_RD 0x03
#define CONFIG_WR 0x09
#define CONV_RATE_WR 0x0A
#define LOCAL_TEMP_HI_LIMIT_WR 0x0B
#define EXT_TEMP_HI_LIMIT_HI_BYTE 0x0D
#define OFFSET_WR 0x11
#define EXT_THERM_LIMIT_WR 0x19
#define LOCAL_THERM_LIMIT_WR 0x20
#define THERM_HYSTERESIS_WR 0x21
/* Configuration Register Bits */
#define EXTENDED_RANGE_BIT (0x1 << 2)
#define THERM2_BIT (0x1 << 5)
#define STANDBY_BIT (0x1 << 6)
/* Max Temperature Measurements */
#define EXTENDED_RANGE_OFFSET 64U
#define STANDARD_RANGE_MAX 127U
#define EXTENDED_RANGE_MAX (150U + EXTENDED_RANGE_OFFSET)
struct nct1008_data {
struct work_struct work;
struct i2c_client *client;
struct mutex mutex;
u8 config;
void (*alarm_fn)(bool raised);
};
static void nct1008_enable(struct i2c_client *client)
{
struct nct1008_data *data = i2c_get_clientdata(client);
i2c_smbus_write_byte_data(client, CONFIG_WR,
data->config & ~STANDBY_BIT);
}
static void nct1008_disable(struct i2c_client *client)
{
struct nct1008_data *data = i2c_get_clientdata(client);
i2c_smbus_write_byte_data(client, CONFIG_WR,
data->config | STANDBY_BIT);
}
static void nct1008_work_func(struct work_struct *work)
{
struct nct1008_data *data = container_of(work, struct nct1008_data, work);
int irq = data->client->irq;
mutex_lock(&data->mutex);
if (data->alarm_fn) {
/* Therm2 line is active low */
data->alarm_fn(!gpio_get_value(irq_to_gpio(irq)));
}
mutex_unlock(&data->mutex);
}
static irqreturn_t nct1008_irq(int irq, void *dev_id)
{
struct nct1008_data *data = dev_id;
schedule_work(&data->work);
return IRQ_HANDLED;
}
static inline u8 value_to_temperature(bool extended, u8 value)
{
return (extended ? (u8)(value - EXTENDED_RANGE_OFFSET) : value);
}
static inline u8 temperature_to_value(bool extended, u8 temp)
{
return (extended ? (u8)(temp + EXTENDED_RANGE_OFFSET) : temp);
}
static int __devinit nct1008_configure_sensor(struct nct1008_data* data)
{
struct i2c_client *client = data->client;
struct nct1008_platform_data *pdata = client->dev.platform_data;
u8 value;
int err;
if (!pdata || !pdata->supported_hwrev)
return -ENODEV;
/*
* Initial Configuration - device is placed in standby and
* ALERT/THERM2 pin is configured as THERM2
*/
data->config = value = pdata->ext_range ?
(STANDBY_BIT | THERM2_BIT | EXTENDED_RANGE_BIT) :
(STANDBY_BIT | THERM2_BIT);
err = i2c_smbus_write_byte_data(client, CONFIG_WR, value);
if (err < 0)
goto error;
/* Temperature conversion rate */
err = i2c_smbus_write_byte_data(client, CONV_RATE_WR, pdata->conv_rate);
if (err < 0)
goto error;
/* External temperature h/w shutdown limit */
value = temperature_to_value(pdata->ext_range, pdata->shutdown_ext_limit);
err = i2c_smbus_write_byte_data(client, EXT_THERM_LIMIT_WR, value);
if (err < 0)
goto error;
/* Local temperature h/w shutdown limit */
value = temperature_to_value(pdata->ext_range, pdata->shutdown_local_limit);
err = i2c_smbus_write_byte_data(client, LOCAL_THERM_LIMIT_WR, value);
if (err < 0)
goto error;
/* External Temperature Throttling limit */
value = temperature_to_value(pdata->ext_range, pdata->throttling_ext_limit);
err = i2c_smbus_write_byte_data(client, EXT_TEMP_HI_LIMIT_HI_BYTE, value);
if (err < 0)
goto error;
/* Local Temperature Throttling limit */
value = pdata->ext_range ? EXTENDED_RANGE_MAX : STANDARD_RANGE_MAX;
err = i2c_smbus_write_byte_data(client, LOCAL_TEMP_HI_LIMIT_WR, value);
if (err < 0)
goto error;
/* Remote channel offset */
err = i2c_smbus_write_byte_data(client, OFFSET_WR, pdata->offset);
if (err < 0)
goto error;
/* THERM hysteresis */
err = i2c_smbus_write_byte_data(client, THERM_HYSTERESIS_WR, pdata->hysteresis);
if (err < 0)
goto error;
data->alarm_fn = pdata->alarm_fn;
return 0;
error:
return err;
}
static int __devinit nct1008_configure_irq(struct nct1008_data *data)
{
INIT_WORK(&data->work, nct1008_work_func);
return request_irq(data->client->irq, nct1008_irq, IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING, DRIVER_NAME, data);
}
static int __devinit nct1008_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct nct1008_data *data;
int err;
data = kzalloc(sizeof(struct nct1008_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->client = client;
i2c_set_clientdata(client, data);
mutex_init(&data->mutex);
err = nct1008_configure_sensor(data); /* sensor is in standby */
if (err < 0)
goto error;
err = nct1008_configure_irq(data);
if (err < 0)
goto error;
nct1008_enable(client); /* sensor is running */
schedule_work(&data->work); /* check initial state */
return 0;
error:
kfree(data);
return err;
}
static int __devexit nct1008_remove(struct i2c_client *client)
{
struct nct1008_data *data = i2c_get_clientdata(client);
free_irq(data->client->irq, data);
cancel_work_sync(&data->work);
kfree(data);
return 0;
}
#ifdef CONFIG_PM
static int nct1008_suspend(struct i2c_client *client, pm_message_t state)
{
disable_irq(client->irq);
nct1008_disable(client);
return 0;
}
static int nct1008_resume(struct i2c_client *client)
{
struct nct1008_data *data = i2c_get_clientdata(client);
nct1008_enable(client);
enable_irq(client->irq);
schedule_work(&data->work);
return 0;
}
#endif
static const struct i2c_device_id nct1008_id[] = {
{ DRIVER_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, nct1008_id);
static struct i2c_driver nct1008_driver = {
.driver = {
.name = DRIVER_NAME,
},
.probe = nct1008_probe,
.remove = __devexit_p(nct1008_remove),
.id_table = nct1008_id,
#ifdef CONFIG_PM
.suspend = nct1008_suspend,
.resume = nct1008_resume,
#endif
};
static int __init nct1008_init(void)
{
return i2c_add_driver(&nct1008_driver);
}
static void __exit nct1008_exit(void)
{
i2c_del_driver(&nct1008_driver);
}
MODULE_DESCRIPTION("Temperature sensor driver for OnSemi NCT1008");
MODULE_LICENSE("GPL");
module_init (nct1008_init);
module_exit (nct1008_exit);

View File

@ -119,6 +119,7 @@ static void _dump_regs(struct tegra_dc *dc, void *data,
char buff[256];
tegra_dc_io_start(dc);
clk_enable(dc->clk);
DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0);
DUMP_REG(DC_CMD_DISPLAY_COMMAND);
@ -256,6 +257,7 @@ static void _dump_regs(struct tegra_dc *dc, void *data,
DUMP_REG(DC_WIN_CSC_KVB);
}
clk_disable(dc->clk);
tegra_dc_io_end(dc);
}

40
include/linux/nct1008.h Normal file
View File

@ -0,0 +1,40 @@
/*
* include/linux/nct1008.h
*
* NCT1008, temperature monitoring device from ON Semiconductors
*
* Copyright (c) 2010, NVIDIA Corporation.
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _LINUX_NCT1008_H
#define _LINUX_NCT1008_H
#include <linux/types.h>
struct nct1008_platform_data {
bool supported_hwrev;
bool ext_range;
u8 conv_rate;
u8 offset;
u8 hysteresis;
u8 shutdown_ext_limit;
u8 shutdown_local_limit;
u8 throttling_ext_limit;
void (*alarm_fn)(bool raised);
};
#endif /* _LINUX_NCT1008_H */