mirror of
https://github.com/torvalds/linux.git
synced 2026-06-10 07:32:29 +02:00
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:
commit
c07aee9df0
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
291
drivers/misc/nct1008.c
Executable 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);
|
||||
|
|
@ -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
40
include/linux/nct1008.h
Normal 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 */
|
||||
Loading…
Reference in New Issue
Block a user