2011-02-20 20:35:43 +03:00
/*
* intel_mid_thermal . c - Intel MID platform thermal driver
*
* Copyright ( C ) 2011 Intel 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 ; version 2 of the License .
*
* 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 .
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
* Author : Durgadoss R < durgadoss . r @ intel . com >
*/
# define pr_fmt(fmt) "intel_mid_thermal: " fmt
# include <linux/module.h>
# include <linux/init.h>
# include <linux/err.h>
# include <linux/param.h>
# include <linux/device.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
# include <linux/pm.h>
# include <linux/thermal.h>
2012-03-06 03:01:03 +04:00
# include <linux/mfd/intel_msic.h>
2011-02-20 20:35:43 +03:00
/* Number of thermal sensors */
2011-04-01 17:54:11 +04:00
# define MSIC_THERMAL_SENSORS 4
2011-02-20 20:35:43 +03:00
/* ADC1 - thermal registers */
2011-04-01 17:54:11 +04:00
# define MSIC_ADC_ENBL 0x10
# define MSIC_ADC_START 0x08
2011-02-20 20:35:43 +03:00
2011-04-01 17:54:11 +04:00
# define MSIC_ADCTHERM_ENBL 0x04
# define MSIC_ADCRRDATA_ENBL 0x05
# define MSIC_CHANL_MASK_VAL 0x0F
2011-02-20 20:35:43 +03:00
2011-04-01 17:54:11 +04:00
# define MSIC_STOPBIT_MASK 16
# define MSIC_ADCTHERM_MASK 4
/* Number of ADC channels */
# define ADC_CHANLS_MAX 15
# define ADC_LOOP_MAX (ADC_CHANLS_MAX - MSIC_THERMAL_SENSORS)
2011-02-20 20:35:43 +03:00
/* ADC channel code values */
2011-04-01 17:54:11 +04:00
# define SKIN_SENSOR0_CODE 0x08
# define SKIN_SENSOR1_CODE 0x09
# define SYS_SENSOR_CODE 0x0A
# define MSIC_DIE_SENSOR_CODE 0x03
2011-02-20 20:35:43 +03:00
2011-04-01 17:54:11 +04:00
# define SKIN_THERM_SENSOR0 0
# define SKIN_THERM_SENSOR1 1
# define SYS_THERM_SENSOR2 2
# define MSIC_DIE_THERM_SENSOR3 3
2011-02-20 20:35:43 +03:00
/* ADC code range */
2011-04-01 17:54:11 +04:00
# define ADC_MAX 977
# define ADC_MIN 162
# define ADC_VAL0C 887
# define ADC_VAL20C 720
# define ADC_VAL40C 508
# define ADC_VAL60C 315
2011-02-20 20:35:43 +03:00
/* ADC base addresses */
2012-03-06 03:01:03 +04:00
# define ADC_CHNL_START_ADDR INTEL_MSIC_ADC1ADDR0 /* increments by 1 */
# define ADC_DATA_START_ADDR INTEL_MSIC_ADC1SNS0H /* increments by 2 */
2011-02-20 20:35:43 +03:00
/* MSIC die attributes */
2011-04-01 17:54:11 +04:00
# define MSIC_DIE_ADC_MIN 488
# define MSIC_DIE_ADC_MAX 1004
2011-02-20 20:35:43 +03:00
/* This holds the address of the first free ADC channel,
* among the 15 channels
*/
static int channel_index ;
struct platform_info {
2011-04-01 17:54:11 +04:00
struct platform_device * pdev ;
struct thermal_zone_device * tzd [ MSIC_THERMAL_SENSORS ] ;
2011-02-20 20:35:43 +03:00
} ;
struct thermal_device_info {
2011-04-01 17:54:11 +04:00
unsigned int chnl_addr ;
int direct ;
/* This holds the current temperature in millidegree celsius */
long curr_temp ;
2011-02-20 20:35:43 +03:00
} ;
/**
* to_msic_die_temp - converts adc_val to msic_die temperature
* @ adc_val : ADC value to be converted
*
* Can sleep
*/
static int to_msic_die_temp ( uint16_t adc_val )
{
2011-04-01 17:54:11 +04:00
return ( 368 * ( adc_val ) / 1000 ) - 220 ;
2011-02-20 20:35:43 +03:00
}
/**
* is_valid_adc - checks whether the adc code is within the defined range
* @ min : minimum value for the sensor
* @ max : maximum value for the sensor
*
* Can sleep
*/
static int is_valid_adc ( uint16_t adc_val , uint16_t min , uint16_t max )
{
2011-04-01 17:54:11 +04:00
return ( adc_val > = min ) & & ( adc_val < = max ) ;
2011-02-20 20:35:43 +03:00
}
/**
* adc_to_temp - converts the ADC code to temperature in C
* @ direct : true if ths channel is direct index
* @ adc_val : the adc_val that needs to be converted
* @ tp : temperature return value
*
* Linear approximation is used to covert the skin adc value into temperature .
* This technique is used to avoid very long look - up table to get
* the appropriate temp value from ADC value .
* The adc code vs sensor temp curve is split into five parts
* to achieve very close approximate temp value with less than
* 0.5 C error
*/
static int adc_to_temp ( int direct , uint16_t adc_val , unsigned long * tp )
{
2011-04-01 17:54:11 +04:00
int temp ;
/* Direct conversion for die temperature */
if ( direct ) {
if ( is_valid_adc ( adc_val , MSIC_DIE_ADC_MIN , MSIC_DIE_ADC_MAX ) ) {
* tp = to_msic_die_temp ( adc_val ) * 1000 ;
return 0 ;
}
return - ERANGE ;
}
if ( ! is_valid_adc ( adc_val , ADC_MIN , ADC_MAX ) )
return - ERANGE ;
/* Linear approximation for skin temperature */
if ( adc_val > ADC_VAL0C )
temp = 177 - ( adc_val / 5 ) ;
else if ( ( adc_val < = ADC_VAL0C ) & & ( adc_val > ADC_VAL20C ) )
temp = 111 - ( adc_val / 8 ) ;
else if ( ( adc_val < = ADC_VAL20C ) & & ( adc_val > ADC_VAL40C ) )
temp = 92 - ( adc_val / 10 ) ;
else if ( ( adc_val < = ADC_VAL40C ) & & ( adc_val > ADC_VAL60C ) )
temp = 91 - ( adc_val / 10 ) ;
else
temp = 112 - ( adc_val / 6 ) ;
/* Convert temperature in celsius to milli degree celsius */
* tp = temp * 1000 ;
return 0 ;
2011-02-20 20:35:43 +03:00
}
/**
* mid_read_temp - read sensors for temperature
* @ temp : holds the current temperature for the sensor after reading
*
* reads the adc_code from the channel and converts it to real
* temperature . The converted value is stored in temp .
*
* Can sleep
*/
static int mid_read_temp ( struct thermal_zone_device * tzd , unsigned long * temp )
{
2011-04-01 17:54:11 +04:00
struct thermal_device_info * td_info = tzd - > devdata ;
uint16_t adc_val , addr ;
uint8_t data = 0 ;
int ret ;
unsigned long curr_temp ;
addr = td_info - > chnl_addr ;
/* Enable the msic for conversion before reading */
2012-03-06 03:01:03 +04:00
ret = intel_msic_reg_write ( INTEL_MSIC_ADC1CNTL3 , MSIC_ADCRRDATA_ENBL ) ;
2011-04-01 17:54:11 +04:00
if ( ret )
return ret ;
/* Re-toggle the RRDATARD bit (temporary workaround) */
2012-03-06 03:01:03 +04:00
ret = intel_msic_reg_write ( INTEL_MSIC_ADC1CNTL3 , MSIC_ADCTHERM_ENBL ) ;
2011-04-01 17:54:11 +04:00
if ( ret )
return ret ;
/* Read the higher bits of data */
2012-03-06 03:01:03 +04:00
ret = intel_msic_reg_read ( addr , & data ) ;
2011-04-01 17:54:11 +04:00
if ( ret )
return ret ;
/* Shift bits to accommodate the lower two data bits */
adc_val = ( data < < 2 ) ;
addr + + ;
2012-03-06 03:01:03 +04:00
ret = intel_msic_reg_read ( addr , & data ) ; /* Read lower bits */
2011-04-01 17:54:11 +04:00
if ( ret )
return ret ;
/* Adding lower two bits to the higher bits */
data & = 03 ;
adc_val + = data ;
/* Convert ADC value to temperature */
ret = adc_to_temp ( td_info - > direct , adc_val , & curr_temp ) ;
if ( ret = = 0 )
* temp = td_info - > curr_temp = curr_temp ;
return ret ;
2011-02-20 20:35:43 +03:00
}
/**
* configure_adc - enables / disables the ADC for conversion
* @ val : zero : disables the ADC non - zero : enables the ADC
*
* Enable / Disable the ADC depending on the argument
*
* Can sleep
*/
static int configure_adc ( int val )
{
2011-04-01 17:54:11 +04:00
int ret ;
uint8_t data ;
2012-03-06 03:01:03 +04:00
ret = intel_msic_reg_read ( INTEL_MSIC_ADC1CNTL1 , & data ) ;
2011-04-01 17:54:11 +04:00
if ( ret )
return ret ;
if ( val ) {
/* Enable and start the ADC */
data | = ( MSIC_ADC_ENBL | MSIC_ADC_START ) ;
} else {
/* Just stop the ADC */
data & = ( ~ MSIC_ADC_START ) ;
}
2012-03-06 03:01:03 +04:00
return intel_msic_reg_write ( INTEL_MSIC_ADC1CNTL1 , data ) ;
2011-02-20 20:35:43 +03:00
}
/**
* set_up_therm_channel - enable thermal channel for conversion
* @ base_addr : index of free msic ADC channel
*
* Enable all the three channels for conversion
*
* Can sleep
*/
static int set_up_therm_channel ( u16 base_addr )
{
2011-04-01 17:54:11 +04:00
int ret ;
/* Enable all the sensor channels */
2012-03-06 03:01:03 +04:00
ret = intel_msic_reg_write ( base_addr , SKIN_SENSOR0_CODE ) ;
2011-04-01 17:54:11 +04:00
if ( ret )
return ret ;
2012-03-06 03:01:03 +04:00
ret = intel_msic_reg_write ( base_addr + 1 , SKIN_SENSOR1_CODE ) ;
2011-04-01 17:54:11 +04:00
if ( ret )
return ret ;
2012-03-06 03:01:03 +04:00
ret = intel_msic_reg_write ( base_addr + 2 , SYS_SENSOR_CODE ) ;
2011-04-01 17:54:11 +04:00
if ( ret )
return ret ;
/* Since this is the last channel, set the stop bit
* to 1 by ORing the DIE_SENSOR_CODE with 0x10 */
2012-03-06 03:01:03 +04:00
ret = intel_msic_reg_write ( base_addr + 3 ,
2011-04-01 17:54:11 +04:00
( MSIC_DIE_SENSOR_CODE | 0x10 ) ) ;
if ( ret )
return ret ;
/* Enable ADC and start it */
return configure_adc ( 1 ) ;
2011-02-20 20:35:43 +03:00
}
/**
* reset_stopbit - sets the stop bit to 0 on the given channel
* @ addr : address of the channel
*
* Can sleep
*/
static int reset_stopbit ( uint16_t addr )
{
2011-04-01 17:54:11 +04:00
int ret ;
uint8_t data ;
2012-03-06 03:01:03 +04:00
ret = intel_msic_reg_read ( addr , & data ) ;
2011-04-01 17:54:11 +04:00
if ( ret )
return ret ;
/* Set the stop bit to zero */
2012-03-06 03:01:03 +04:00
return intel_msic_reg_write ( addr , ( data & 0xEF ) ) ;
2011-02-20 20:35:43 +03:00
}
/**
* find_free_channel - finds an empty channel for conversion
*
* If the ADC is not enabled then start using 0 th channel
* itself . Otherwise find an empty channel by looking for a
* channel in which the stopbit is set to 1. returns the index
* of the first free channel if succeeds or an error code .
*
* Context : can sleep
*
* FIXME : Ultimately the channel allocator will move into the intel_scu_ipc
* code .
*/
static int find_free_channel ( void )
{
2011-04-01 17:54:11 +04:00
int ret ;
int i ;
uint8_t data ;
/* check whether ADC is enabled */
2012-03-06 03:01:03 +04:00
ret = intel_msic_reg_read ( INTEL_MSIC_ADC1CNTL1 , & data ) ;
2011-04-01 17:54:11 +04:00
if ( ret )
return ret ;
if ( ( data & MSIC_ADC_ENBL ) = = 0 )
return 0 ;
/* ADC is already enabled; Looking for an empty channel */
for ( i = 0 ; i < ADC_CHANLS_MAX ; i + + ) {
2012-03-06 03:01:03 +04:00
ret = intel_msic_reg_read ( ADC_CHNL_START_ADDR + i , & data ) ;
2011-04-01 17:54:11 +04:00
if ( ret )
return ret ;
if ( data & MSIC_STOPBIT_MASK ) {
ret = i ;
break ;
}
}
return ( ret > ADC_LOOP_MAX ) ? ( - EINVAL ) : ret ;
2011-02-20 20:35:43 +03:00
}
/**
* mid_initialize_adc - initializing the ADC
* @ dev : our device structure
*
* Initialize the ADC for reading thermistor values . Can sleep .
*/
static int mid_initialize_adc ( struct device * dev )
{
2011-04-01 17:54:11 +04:00
u8 data ;
u16 base_addr ;
int ret ;
/*
* Ensure that adctherm is disabled before we
* initialize the ADC
*/
2012-03-06 03:01:03 +04:00
ret = intel_msic_reg_read ( INTEL_MSIC_ADC1CNTL3 , & data ) ;
2011-04-01 17:54:11 +04:00
if ( ret )
return ret ;
2012-03-06 03:01:04 +04:00
data & = ~ MSIC_ADCTHERM_MASK ;
ret = intel_msic_reg_write ( INTEL_MSIC_ADC1CNTL3 , data ) ;
if ( ret )
return ret ;
2011-04-01 17:54:11 +04:00
/* Index of the first channel in which the stop bit is set */
channel_index = find_free_channel ( ) ;
if ( channel_index < 0 ) {
dev_err ( dev , " No free ADC channels " ) ;
return channel_index ;
}
base_addr = ADC_CHNL_START_ADDR + channel_index ;
if ( ! ( channel_index = = 0 | | channel_index = = ADC_LOOP_MAX ) ) {
/* Reset stop bit for channels other than 0 and 12 */
ret = reset_stopbit ( base_addr ) ;
if ( ret )
return ret ;
/* Index of the first free channel */
base_addr + + ;
channel_index + + ;
}
ret = set_up_therm_channel ( base_addr ) ;
if ( ret ) {
dev_err ( dev , " unable to enable ADC " ) ;
return ret ;
}
dev_dbg ( dev , " ADC initialization successful " ) ;
return ret ;
2011-02-20 20:35:43 +03:00
}
/**
* initialize_sensor - sets default temp and timer ranges
* @ index : index of the sensor
*
* Context : can sleep
*/
static struct thermal_device_info * initialize_sensor ( int index )
{
2011-04-01 17:54:11 +04:00
struct thermal_device_info * td_info =
kzalloc ( sizeof ( struct thermal_device_info ) , GFP_KERNEL ) ;
if ( ! td_info )
return NULL ;
/* Set the base addr of the channel for this sensor */
td_info - > chnl_addr = ADC_DATA_START_ADDR + 2 * ( channel_index + index ) ;
/* Sensor 3 is direct conversion */
if ( index = = 3 )
td_info - > direct = 1 ;
return td_info ;
2011-02-20 20:35:43 +03:00
}
/**
* mid_thermal_resume - resume routine
2012-06-28 01:19:45 +04:00
* @ dev : device structure
2011-02-20 20:35:43 +03:00
*
* mid thermal resume : re - initializes the adc . Can sleep .
*/
2012-06-28 01:19:45 +04:00
static int mid_thermal_resume ( struct device * dev )
2011-02-20 20:35:43 +03:00
{
2012-06-28 01:19:45 +04:00
return mid_initialize_adc ( dev ) ;
2011-02-20 20:35:43 +03:00
}
/**
* mid_thermal_suspend - suspend routine
2012-06-28 01:19:45 +04:00
* @ dev : device structure
2011-02-20 20:35:43 +03:00
*
* mid thermal suspend implements the suspend functionality
* by stopping the ADC . Can sleep .
*/
2012-06-28 01:19:45 +04:00
static int mid_thermal_suspend ( struct device * dev )
2011-02-20 20:35:43 +03:00
{
2011-04-01 17:54:11 +04:00
/*
* This just stops the ADC and does not disable it .
* temporary workaround until we have a generic ADC driver .
* If 0 is passed , it disables the ADC .
*/
return configure_adc ( 0 ) ;
2011-02-20 20:35:43 +03:00
}
2012-06-28 01:19:45 +04:00
static SIMPLE_DEV_PM_OPS ( mid_thermal_pm ,
mid_thermal_suspend , mid_thermal_resume ) ;
2011-02-20 20:35:43 +03:00
/**
* read_curr_temp - reads the current temperature and stores in temp
* @ temp : holds the current temperature value after reading
*
* Can sleep
*/
static int read_curr_temp ( struct thermal_zone_device * tzd , unsigned long * temp )
{
2011-04-01 17:54:11 +04:00
WARN_ON ( tzd = = NULL ) ;
return mid_read_temp ( tzd , temp ) ;
2011-02-20 20:35:43 +03:00
}
/* Can't be const */
static struct thermal_zone_device_ops tzd_ops = {
2011-04-01 17:54:11 +04:00
. get_temp = read_curr_temp ,
2011-02-20 20:35:43 +03:00
} ;
/**
* mid_thermal_probe - mfld thermal initialize
* @ pdev : platform device structure
*
* mid thermal probe initializes the hardware and registers
* all the sensors with the generic thermal framework . Can sleep .
*/
static int mid_thermal_probe ( struct platform_device * pdev )
{
2011-04-01 17:54:11 +04:00
static char * name [ MSIC_THERMAL_SENSORS ] = {
" skin0 " , " skin1 " , " sys " , " msicdie "
} ;
int ret ;
int i ;
struct platform_info * pinfo ;
ix86/mid/thermal: Introduce the use of the managed version of kzalloc
This patch moves data allocated using kzalloc to managed data allocated
using devm_kzalloc and cleans now unnecessary kfrees in probe and remove
functions.
The following Coccinelle semantic patch was used for making the change:
@platform@
identifier p, probefn, removefn;
@@
struct platform_driver p = {
.probe = probefn,
.remove = removefn,
};
@prb@
identifier platform.probefn, pdev;
expression e, e1, e2;
@@
probefn(struct platform_device *pdev, ...) {
<+...
- e = kzalloc(e1, e2)
+ e = devm_kzalloc(&pdev->dev, e1, e2)
...
?-kfree(e);
...+>
}
@rem depends on prb@
identifier platform.removefn;
expression e;
@@
removefn(...) {
<...
- kfree(e);
...>
}
Signed-off-by: Himangi Saraogi <himangi774@gmail.com>
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
2014-05-25 11:35:45 +04:00
pinfo = devm_kzalloc ( & pdev - > dev , sizeof ( struct platform_info ) ,
GFP_KERNEL ) ;
2011-04-01 17:54:11 +04:00
if ( ! pinfo )
return - ENOMEM ;
/* Initializing the hardware */
ret = mid_initialize_adc ( & pdev - > dev ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " ADC init failed " ) ;
return ret ;
}
/* Register each sensor with the generic thermal framework*/
for ( i = 0 ; i < MSIC_THERMAL_SENSORS ; i + + ) {
2011-07-06 19:40:51 +04:00
struct thermal_device_info * td_info = initialize_sensor ( i ) ;
if ( ! td_info ) {
ret = - ENOMEM ;
goto err ;
}
2011-04-01 17:54:11 +04:00
pinfo - > tzd [ i ] = thermal_zone_device_register ( name [ i ] ,
2012-09-18 09:34:56 +04:00
0 , 0 , td_info , & tzd_ops , NULL , 0 , 0 ) ;
2011-07-06 19:40:51 +04:00
if ( IS_ERR ( pinfo - > tzd [ i ] ) ) {
kfree ( td_info ) ;
ret = PTR_ERR ( pinfo - > tzd [ i ] ) ;
goto err ;
}
2011-04-01 17:54:11 +04:00
}
pinfo - > pdev = pdev ;
platform_set_drvdata ( pdev , pinfo ) ;
return 0 ;
2011-02-20 20:35:43 +03:00
2011-07-06 19:40:51 +04:00
err :
while ( - - i > = 0 ) {
kfree ( pinfo - > tzd [ i ] - > devdata ) ;
2011-04-01 17:54:11 +04:00
thermal_zone_device_unregister ( pinfo - > tzd [ i ] ) ;
2011-07-06 19:40:51 +04:00
}
2011-04-01 17:54:11 +04:00
configure_adc ( 0 ) ;
return ret ;
2011-02-20 20:35:43 +03:00
}
/**
* mid_thermal_remove - mfld thermal finalize
* @ dev : platform device structure
*
* MLFD thermal remove unregisters all the sensors from the generic
* thermal framework . Can sleep .
*/
static int mid_thermal_remove ( struct platform_device * pdev )
{
2011-04-01 17:54:11 +04:00
int i ;
struct platform_info * pinfo = platform_get_drvdata ( pdev ) ;
2011-02-20 20:35:43 +03:00
2011-07-06 19:40:51 +04:00
for ( i = 0 ; i < MSIC_THERMAL_SENSORS ; i + + ) {
kfree ( pinfo - > tzd [ i ] - > devdata ) ;
2011-04-01 17:54:11 +04:00
thermal_zone_device_unregister ( pinfo - > tzd [ i ] ) ;
2011-07-06 19:40:51 +04:00
}
2011-02-20 20:35:43 +03:00
2011-04-01 17:54:11 +04:00
/* Stop the ADC */
return configure_adc ( 0 ) ;
2011-02-20 20:35:43 +03:00
}
2012-03-06 03:01:03 +04:00
# define DRIVER_NAME "msic_thermal"
2011-02-20 20:35:43 +03:00
static const struct platform_device_id therm_id_table [ ] = {
2011-04-01 17:54:11 +04:00
{ DRIVER_NAME , 1 } ,
2011-12-16 02:27:59 +04:00
{ " msic_thermal " , 1 } ,
2011-04-01 17:54:11 +04:00
{ }
2011-02-20 20:35:43 +03:00
} ;
static struct platform_driver mid_thermal_driver = {
2011-04-01 17:54:11 +04:00
. driver = {
. name = DRIVER_NAME ,
. owner = THIS_MODULE ,
2012-06-28 01:19:45 +04:00
. pm = & mid_thermal_pm ,
2011-04-01 17:54:11 +04:00
} ,
. probe = mid_thermal_probe ,
2012-12-22 01:18:33 +04:00
. remove = mid_thermal_remove ,
2011-04-01 17:54:11 +04:00
. id_table = therm_id_table ,
2011-02-20 20:35:43 +03:00
} ;
2011-11-26 08:14:37 +04:00
module_platform_driver ( mid_thermal_driver ) ;
2011-02-20 20:35:43 +03:00
MODULE_AUTHOR ( " Durgadoss R <durgadoss.r@intel.com> " ) ;
MODULE_DESCRIPTION ( " Intel Medfield Platform Thermal Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;