Commit ad80d2d1 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/gregkh/linux/i2c-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents ed651f72 7d130b1b
...@@ -193,6 +193,10 @@ config I2C_IBM_OCP_ADAP ...@@ -193,6 +193,10 @@ config I2C_IBM_OCP_ADAP
tristate "IBM on-chip I2C Adapter" tristate "IBM on-chip I2C Adapter"
depends on I2C_IBM_OCP_ALGO depends on I2C_IBM_OCP_ALGO
config I2C_IOP3XX
tristate "Intel XScale IOP3xx on-chip I2C interface"
depends on ARCH_IOP3XX && I2C
config I2C_CHARDEV config I2C_CHARDEV
tristate "I2C device interface" tristate "I2C device interface"
depends on I2C depends on I2C
......
...@@ -16,4 +16,5 @@ obj-$(CONFIG_ITE_I2C_ADAP) += i2c-adap-ite.o ...@@ -16,4 +16,5 @@ obj-$(CONFIG_ITE_I2C_ADAP) += i2c-adap-ite.o
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_I2C_SENSOR) += i2c-sensor.o obj-$(CONFIG_I2C_SENSOR) += i2c-sensor.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-y += busses/ chips/ obj-y += busses/ chips/
...@@ -47,6 +47,21 @@ config SENSORS_LM75 ...@@ -47,6 +47,21 @@ config SENSORS_LM75
in the lm_sensors package, which you can download at in the lm_sensors package, which you can download at
http://www.lm-sensors.nu http://www.lm-sensors.nu
config SENSORS_LM85
tristate " National Semiconductors LM85 and compatibles"
depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for National Semiconductor LM85
sensor chips and clones: ADT7463 and ADM1027.
This can also be built as a module which can be inserted and
removed while the kernel is running.
The module will be called lm85.
You will also need the latest user-space utilties: you can find them
in the lm_sensors package, which you can download at
http://www.lm-sensors.nu
config SENSORS_VIA686A config SENSORS_VIA686A
tristate " VIA686A" tristate " VIA686A"
depends on I2C && EXPERIMENTAL depends on I2C && EXPERIMENTAL
...@@ -76,8 +91,8 @@ config SENSORS_W83781D ...@@ -76,8 +91,8 @@ config SENSORS_W83781D
config I2C_SENSOR config I2C_SENSOR
tristate tristate
default y if SENSORS_ADM1021=y || SENSORS_IT87=y || SENSORS_LM75=y || SENSORS_VIA686A=y || SENSORS_W83781D=y default y if SENSORS_ADM1021=y || SENSORS_IT87=y || SENSORS_LM75=y || SENSORS_VIA686A=y || SENSORS_W83781D=y || SENSORS_LM85=y
default m if SENSORS_ADM1021=m || SENSORS_IT87=m || SENSORS_LM75=m || SENSORS_VIA686A=m || SENSORS_W83781D=m default m if SENSORS_ADM1021=m || SENSORS_IT87=m || SENSORS_LM75=m || SENSORS_VIA686A=m || SENSORS_W83781D=m || SENSORS_LM85=m
default n default n
endmenu endmenu
...@@ -5,5 +5,6 @@ ...@@ -5,5 +5,6 @@
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_IT87) += it87.o
obj-$(CONFIG_SENSORS_LM75) += lm75.o obj-$(CONFIG_SENSORS_LM75) += lm75.o
obj-$(CONFIG_SENSORS_LM85) += lm85.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
obj-$(CONFIG_SENSORS_W83781D) += w83781d.o obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
/*
lm85.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com>
Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.de>
Chip details at <http://www.national.com/ds/LM/LM85.pdf>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/i2c-sensor.h>
#include <linux/i2c-vid.h>
/*
#include <asm/io.h>
*/
#undef LM85EXTENDEDFUNC /* Extended functionality */
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
SENSORS_INSMOD_4(lm85b, lm85c, adm1027, adt7463);
/* Enable debug if true */
static int lm85debug = 0;
/* The LM85 registers */
#define LM85_REG_IN(nr) (0x20 + (nr))
#define LM85_REG_IN_MIN(nr) (0x44 + (nr) * 2)
#define LM85_REG_IN_MAX(nr) (0x45 + (nr) * 2)
#define LM85_REG_TEMP(nr) (0x25 + (nr))
#define LM85_REG_TEMP_MIN(nr) (0x4e + (nr) * 2)
#define LM85_REG_TEMP_MAX(nr) (0x4f + (nr) * 2)
/* Fan speeds are LSB, MSB (2 bytes) */
#define LM85_REG_FAN(nr) (0x28 + (nr) *2)
#define LM85_REG_FAN_MIN(nr) (0x54 + (nr) *2)
#define LM85_REG_PWM(nr) (0x30 + (nr))
#define ADT7463_REG_OPPOINT(nr) (0x33 + (nr))
#define ADT7463_REG_TMIN_CTL1 0x36
#define ADT7463_REG_TMIN_CTL2 0x37
#define LM85_REG_DEVICE 0x3d
#define LM85_REG_COMPANY 0x3e
#define LM85_REG_VERSTEP 0x3f
/* These are the recognized values for the above regs */
#define LM85_DEVICE_ADX 0x27
#define LM85_COMPANY_NATIONAL 0x01
#define LM85_COMPANY_ANALOG_DEV 0x41
#define LM85_VERSTEP_GENERIC 0x60
#define LM85_VERSTEP_LM85C 0x60
#define LM85_VERSTEP_LM85B 0x62
#define LM85_VERSTEP_ADM1027 0x60
#define LM85_VERSTEP_ADT7463 0x62
#define LM85_REG_CONFIG 0x40
#define LM85_REG_ALARM1 0x41
#define LM85_REG_ALARM2 0x42
#define LM85_REG_VID 0x43
/* Automated FAN control */
#define LM85_REG_AFAN_CONFIG(nr) (0x5c + (nr))
#define LM85_REG_AFAN_RANGE(nr) (0x5f + (nr))
#define LM85_REG_AFAN_SPIKE1 0x62
#define LM85_REG_AFAN_SPIKE2 0x63
#define LM85_REG_AFAN_MINPWM(nr) (0x64 + (nr))
#define LM85_REG_AFAN_LIMIT(nr) (0x67 + (nr))
#define LM85_REG_AFAN_CRITICAL(nr) (0x6a + (nr))
#define LM85_REG_AFAN_HYST1 0x6d
#define LM85_REG_AFAN_HYST2 0x6e
#define LM85_REG_TACH_MODE 0x74
#define LM85_REG_SPINUP_CTL 0x75
#define ADM1027_REG_TEMP_OFFSET(nr) (0x70 + (nr))
#define ADM1027_REG_CONFIG2 0x73
#define ADM1027_REG_INTMASK1 0x74
#define ADM1027_REG_INTMASK2 0x75
#define ADM1027_REG_EXTEND_ADC1 0x76
#define ADM1027_REG_EXTEND_ADC2 0x77
#define ADM1027_REG_CONFIG3 0x78
#define ADM1027_REG_FAN_PPR 0x7b
#define ADT7463_REG_THERM 0x79
#define ADT7463_REG_THERM_LIMIT 0x7A
#define LM85_ALARM_IN0 0x0001
#define LM85_ALARM_IN1 0x0002
#define LM85_ALARM_IN2 0x0004
#define LM85_ALARM_IN3 0x0008
#define LM85_ALARM_TEMP1 0x0010
#define LM85_ALARM_TEMP2 0x0020
#define LM85_ALARM_TEMP3 0x0040
#define LM85_ALARM_ALARM2 0x0080
#define LM85_ALARM_IN4 0x0100
#define LM85_ALARM_RESERVED 0x0200
#define LM85_ALARM_FAN1 0x0400
#define LM85_ALARM_FAN2 0x0800
#define LM85_ALARM_FAN3 0x1000
#define LM85_ALARM_FAN4 0x2000
#define LM85_ALARM_TEMP1_FAULT 0x4000
#define LM85_ALARM_TEMP3_FAULT 0x8000
/* Conversions. Rounding and limit checking is only done on the TO_REG
variants. Note that you should be a bit careful with which arguments
these macros are called: arguments may be evaluated more than once.
*/
/* IN are scaled 1.000 == 0xc0, mag = 3 */
#define IN_TO_REG(val) (SENSORS_LIMIT((((val)*0xc0+500)/1000),0,255))
#define INEXT_FROM_REG(val,ext) (((val)*1000 + (ext)*250 + 96)/0xc0)
#define IN_FROM_REG(val) (INEXT_FROM_REG(val,0))
/* IN are scaled acording to built-in resistors */
static int lm85_scaling[] = { /* .001 Volts */
2500, 2250, 3300, 5000, 12000
};
#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from))
#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255))
#define INSEXT_FROM_REG(n,val,ext) (SCALE((val)*4 + (ext),192*4,lm85_scaling[n]))
/*
#define INS_FROM_REG(n,val) (INSEXT_FROM_REG(n,val,0))
*/
#define INS_FROM_REG(n,val) ( ( (val*4*lm85_scaling[n]) + (192*4/2) ) / (192*4) )
/* FAN speed is measured using 90kHz clock */
#define FAN_TO_REG(val) (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534))
#define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val))
/* Temperature is reported in .01 degC increments */
#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+50)/100,-127,127))
#define TEMPEXT_FROM_REG(val,ext) ((val)*100 + (ext)*25)
#define TEMP_FROM_REG(val) (TEMPEXT_FROM_REG(val,0))
#define EXTTEMP_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127))
#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255))
#define PWM_FROM_REG(val) (val)
#define EXT_FROM_REG(val,sensor) (((val)>>(sensor * 2))&0x03)
#ifdef LM85EXTENDEDFUNC /* Extended functionality */
/* ZONEs have the following parameters:
* Limit (low) temp, 1. degC
* Hysteresis (below limit), 1. degC (0-15)
* Range of speed control, .1 degC (2-80)
* Critical (high) temp, 1. degC
*
* FAN PWMs have the following parameters:
* Reference Zone, 1, 2, 3, etc.
* Spinup time, .05 sec
* PWM value at limit/low temp, 1 count
* PWM Frequency, 1. Hz
* PWM is Min or OFF below limit, flag
* Invert PWM output, flag
*
* Some chips filter the temp, others the fan.
* Filter constant (or disabled) .1 seconds
*/
/* These are the zone temperature range encodings */
static int lm85_range_map[] = { /* .1 degC */
20, 25, 33, 40, 50, 66,
80, 100, 133, 160, 200, 266,
320, 400, 533, 800
};
static int RANGE_TO_REG( int range )
{
int i;
if( range >= lm85_range_map[15] ) { return 15 ; }
for( i = 0 ; i < 15 ; ++i )
if( range <= lm85_range_map[i] )
break ;
return( i & 0x0f );
}
#define RANGE_FROM_REG(val) (lm85_range_map[(val)&0x0f])
/* These are the Acoustic Enhancement, or Temperature smoothing encodings
* NOTE: The enable/disable bit is INCLUDED in these encodings as the
* MSB (bit 3, value 8). If the enable bit is 0, the encoded value
* is ignored, or set to 0.
*/
static int lm85_smooth_map[] = { /* .1 sec */
350, 176, 118, 70, 44, 30, 16, 8
/* 35.4 * 1/1, 1/2, 1/3, 1/5, 1/8, 1/12, 1/24, 1/48 */
};
static int SMOOTH_TO_REG( int smooth )
{
int i;
if( smooth <= 0 ) { return 0 ; } /* Disabled */
for( i = 0 ; i < 7 ; ++i )
if( smooth >= lm85_smooth_map[i] )
break ;
return( (i & 0x07) | 0x08 );
}
#define SMOOTH_FROM_REG(val) ((val)&0x08?lm85_smooth_map[(val)&0x07]:0)
/* These are the fan spinup delay time encodings */
static int lm85_spinup_map[] = { /* .1 sec */
0, 1, 2, 4, 7, 10, 20, 40
};
static int SPINUP_TO_REG( int spinup )
{
int i;
if( spinup >= lm85_spinup_map[7] ) { return 7 ; }
for( i = 0 ; i < 7 ; ++i )
if( spinup <= lm85_spinup_map[i] )
break ;
return( i & 0x07 );
}
#define SPINUP_FROM_REG(val) (lm85_spinup_map[(val)&0x07])
/* These are the PWM frequency encodings */
static int lm85_freq_map[] = { /* .1 Hz */
100, 150, 230, 300, 380, 470, 620, 980
};
static int FREQ_TO_REG( int freq )
{
int i;
if( freq >= lm85_freq_map[7] ) { return 7 ; }
for( i = 0 ; i < 7 ; ++i )
if( freq <= lm85_freq_map[i] )
break ;
return( i & 0x07 );
}
#define FREQ_FROM_REG(val) (lm85_freq_map[(val)&0x07])
/* Since we can't use strings, I'm abusing these numbers
* to stand in for the following meanings:
* 1 -- PWM responds to Zone 1
* 2 -- PWM responds to Zone 2
* 3 -- PWM responds to Zone 3
* 23 -- PWM responds to the higher temp of Zone 2 or 3
* 123 -- PWM responds to highest of Zone 1, 2, or 3
* 0 -- PWM is always at 0% (ie, off)
* -1 -- PWM is always at 100%
* -2 -- PWM responds to manual control
*/
#endif /* Extended functionality */
static int lm85_zone_map[] = { 1, 2, 3, -1, 0, 23, 123, -2 };
#define ZONE_FROM_REG(val) (lm85_zone_map[((val)>>5)&0x07])
#ifdef LM85EXTENDEDFUNC /* Extended functionality */
static int ZONE_TO_REG( int zone )
{
int i;
for( i = 0 ; i <= 7 ; ++i )
if( zone == lm85_zone_map[i] )
break ;
if( i > 7 ) /* Not found. */
i = 3; /* Always 100% */
return( (i & 0x07)<<5 );
}
#endif /* Extended functionality */
#define HYST_TO_REG(val) (SENSORS_LIMIT((-(val)+5)/10,0,15))
#define HYST_FROM_REG(val) (-(val)*10)
#define OFFSET_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127))
#define OFFSET_FROM_REG(val) ((val)*25)
#define PPR_MASK(fan) (0x03<<(fan *2))
#define PPR_TO_REG(val,fan) (SENSORS_LIMIT((val)-1,0,3)<<(fan *2))
#define PPR_FROM_REG(val,fan) ((((val)>>(fan * 2))&0x03)+1)
/* i2c-vid.h defines vid_from_reg() */
#define VID_FROM_REG(val,vrm) (vid_from_reg((val),(vrm)))
#define ALARMS_FROM_REG(val) (val)
/* Unlike some other drivers we DO NOT set initial limits. Use
* the config file to set limits. Some users have reported
* motherboards shutting down when we set limits in a previous
* version of the driver.
*/
/* Typically used with Pentium 4 systems v9.1 VRM spec */
#define LM85_INIT_VRM 91
/* Chip sampling rates
*
* Some sensors are not updated more frequently than once per second
* so it doesn't make sense to read them more often than that.
* We cache the results and return the saved data if the driver
* is called again before a second has elapsed.
*
* Also, there is significant configuration data for this chip
* given the automatic PWM fan control that is possible. There
* are about 47 bytes of config data to only 22 bytes of actual
* readings. So, we keep the config data up to date in the cache
* when it is written and only sample it once every 1 *minute*
*/
#define LM85_DATA_INTERVAL (HZ + HZ / 2)
#define LM85_CONFIG_INTERVAL (1 * 60 * HZ)
/* For each registered LM85, we need to keep some data in memory. That
data is pointed to by lm85_list[NR]->data. The structure itself is
dynamically allocated, at the same time when a new lm85 client is
allocated. */
/* LM85 can automatically adjust fan speeds based on temperature
* This structure encapsulates an entire Zone config. There are
* three zones (one for each temperature input) on the lm85
*/
struct lm85_zone {
s8 limit; /* Low temp limit */
u8 hyst; /* Low limit hysteresis. (0-15) */
u8 range; /* Temp range, encoded */
s8 critical; /* "All fans ON" temp limit */
};
struct lm85_autofan {
u8 config; /* Register value */
u8 freq; /* PWM frequency, encoded */
u8 min_pwm; /* Minimum PWM value, encoded */
u8 min_off; /* Min PWM or OFF below "limit", flag */
};
struct lm85_data {
struct semaphore lock;
enum chips type;
struct semaphore update_lock;
int valid; /* !=0 if following fields are valid */
unsigned long last_reading; /* In jiffies */
unsigned long last_config; /* In jiffies */
u8 in[5]; /* Register value */
u8 in_max[5]; /* Register value */
u8 in_min[5]; /* Register value */
s8 temp[3]; /* Register value */
s8 temp_min[3]; /* Register value */
s8 temp_max[3]; /* Register value */
s8 temp_offset[3]; /* Register value */
u16 fan[4]; /* Register value */
u16 fan_min[4]; /* Register value */
u8 pwm[3]; /* Register value */
u8 spinup_ctl; /* Register encoding, combined */
u8 tach_mode; /* Register encoding, combined */
u16 extend_adc; /* Register value */
u8 fan_ppr; /* Register value */
u8 smooth[3]; /* Register encoding */
u8 vid; /* Register value */
u8 vrm; /* VRM version */
u8 syncpwm3; /* Saved PWM3 for TACH 2,3,4 config */
u8 oppoint[3]; /* Register value */
u16 tmin_ctl; /* Register value */
u32 therm_total; /* Cummulative therm count */
u8 therm_limit; /* Register value */
u16 alarms; /* Register encoding, combined */
struct lm85_autofan autofan[3];
struct lm85_zone zone[3];
};
static int lm85_attach_adapter(struct i2c_adapter *adapter);
static int lm85_detect(struct i2c_adapter *adapter, int address,
int kind);
static int lm85_detach_client(struct i2c_client *client);
static int lm85_read_value(struct i2c_client *client, u8 register);
static int lm85_write_value(struct i2c_client *client, u8 register, int value);
static void lm85_update_client(struct i2c_client *client);
static void lm85_init_client(struct i2c_client *client);
static struct i2c_driver lm85_driver = {
.owner = THIS_MODULE,
.name = "lm85",
.id = I2C_DRIVERID_LM85,
.flags = I2C_DF_NOTIFY,
.attach_adapter = lm85_attach_adapter,
.detach_client = lm85_detach_client,
};
/* Unique ID assigned to each LM85 detected */
static int lm85_id = 0;
/* 4 Fans */
static ssize_t show_fan(struct device *dev, char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
lm85_update_client(client);
return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr]) );
}
static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
lm85_update_client(client);
return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr]) );
}
static ssize_t set_fan_min(struct device *dev, const char *buf,
size_t count, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
data->fan_min[nr] = FAN_TO_REG(val);
lm85_write_value(client, LM85_REG_FAN_MIN(nr), data->fan_min[nr]);
return count;
}
#define show_fan_offset(offset) \
static ssize_t show_fan_##offset (struct device *dev, char *buf) \
{ \
return show_fan(dev, buf, 0x##offset - 1); \
} \
static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \
{ \
return show_fan_min(dev, buf, 0x##offset - 1); \
} \
static ssize_t set_fan_##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_fan_min(dev, buf, count, 0x##offset - 1); \
} \
static DEVICE_ATTR(fan_input##offset, S_IRUGO, show_fan_##offset, NULL) \
static DEVICE_ATTR(fan_min##offset, S_IRUGO | S_IWUSR, \
show_fan_##offset##_min, set_fan_##offset##_min)
show_fan_offset(1);
show_fan_offset(2);
show_fan_offset(3);
show_fan_offset(4);
/* vid, vrm, alarms */
static ssize_t show_vid_reg(struct device *dev, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
lm85_update_client(client);
return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
}
static DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL)
static ssize_t show_vrm_reg(struct device *dev, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
lm85_update_client(client);
return sprintf(buf, "%ld\n", (long) data->vrm);
}
static ssize_t store_vrm_reg(struct device *dev, const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
u32 val;
val = simple_strtoul(buf, NULL, 10);
data->vrm = val;
return count;
}
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg)
static ssize_t show_alarms_reg(struct device *dev, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
lm85_update_client(client);
return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms));
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL)
/* pwm */
static ssize_t show_pwm(struct device *dev, char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
lm85_update_client(client);
return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm[nr]) );
}
static ssize_t set_pwm(struct device *dev, const char *buf,
size_t count, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
data->pwm[nr] = PWM_TO_REG(val);
lm85_write_value(client, LM85_REG_PWM(nr), data->pwm[nr]);
return count;
}
static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
int pwm_zone;
lm85_update_client(client);
pwm_zone = ZONE_FROM_REG(data->autofan[nr].config);
return sprintf(buf,"%d\n", (pwm_zone != 0 && pwm_zone != -1) );
}
#define show_pwm_reg(offset) \
static ssize_t show_pwm_##offset (struct device *dev, char *buf) \
{ \
return show_pwm(dev, buf, 0x##offset - 1); \
} \
static ssize_t set_pwm_##offset (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_pwm(dev, buf, count, 0x##offset - 1); \
} \
static ssize_t show_pwm_enable##offset (struct device *dev, char *buf) \
{ \
return show_pwm_enable(dev, buf, 0x##offset - 1); \
} \
static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
show_pwm_##offset, set_pwm_##offset) \
static DEVICE_ATTR(pwm_enable##offset, S_IRUGO, show_pwm_enable##offset, NULL)
show_pwm_reg(1);
show_pwm_reg(2);
show_pwm_reg(3);
/* Voltages */
static ssize_t show_in(struct device *dev, char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
lm85_update_client(client);
return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in[nr]) );
}
static ssize_t show_in_min(struct device *dev, char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
lm85_update_client(client);
return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr]) );
}
static ssize_t set_in_min(struct device *dev, const char *buf,
size_t count, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
data->in_min[nr] = INS_TO_REG(nr, val);
lm85_write_value(client, LM85_REG_IN_MIN(nr), data->in_min[nr]);
return count;
}
static ssize_t show_in_max(struct device *dev, char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
lm85_update_client(client);
return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr]) );
}
static ssize_t set_in_max(struct device *dev, const char *buf,
size_t count, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
data->in_max[nr] = INS_TO_REG(nr, val);
lm85_write_value(client, LM85_REG_IN_MAX(nr), data->in_max[nr]);
return count;
}
#define show_in_reg(offset) \
static ssize_t show_in_##offset (struct device *dev, char *buf) \
{ \
return show_in(dev, buf, 0x##offset); \
} \
static ssize_t show_in_##offset##_min (struct device *dev, char *buf) \
{ \
return show_in_min(dev, buf, 0x##offset); \
} \
static ssize_t show_in_##offset##_max (struct device *dev, char *buf) \
{ \
return show_in_max(dev, buf, 0x##offset); \
} \
static ssize_t set_in_##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_in_min(dev, buf, count, 0x##offset); \
} \
static ssize_t set_in_##offset##_max (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_in_max(dev, buf, count, 0x##offset); \
} \
static DEVICE_ATTR(in_input##offset, S_IRUGO, show_in_##offset, NULL) \
static DEVICE_ATTR(in_min##offset, S_IRUGO | S_IWUSR, \
show_in_##offset##_min, set_in_##offset##_min) \
static DEVICE_ATTR(in_max##offset, S_IRUGO | S_IWUSR, \
show_in_##offset##_max, set_in_##offset##_max)
show_in_reg(0);
show_in_reg(1);
show_in_reg(2);
show_in_reg(3);
show_in_reg(4);
/* Temps */
static ssize_t show_temp(struct device *dev, char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
lm85_update_client(client);
return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp[nr]) );
}
static ssize_t show_temp_min(struct device *dev, char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
lm85_update_client(client);
return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr]) );
}
static ssize_t set_temp_min(struct device *dev, const char *buf,
size_t count, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
data->temp_min[nr] = TEMP_TO_REG(val);
lm85_write_value(client, LM85_REG_TEMP_MIN(nr), data->temp_min[nr]);
return count;
}
static ssize_t show_temp_max(struct device *dev, char *buf, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
lm85_update_client(client);
return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr]) );
}
static ssize_t set_temp_max(struct device *dev, const char *buf,
size_t count, int nr)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
data->temp_max[nr] = TEMP_TO_REG(val);
lm85_write_value(client, LM85_REG_TEMP_MAX(nr), data->temp_max[nr]);
return count;
}
#define show_temp_reg(offset) \
static ssize_t show_temp_##offset (struct device *dev, char *buf) \
{ \
return show_temp(dev, buf, 0x##offset - 1); \
} \
static ssize_t show_temp_##offset##_min (struct device *dev, char *buf) \
{ \
return show_temp_min(dev, buf, 0x##offset - 1); \
} \
static ssize_t show_temp_##offset##_max (struct device *dev, char *buf) \
{ \
return show_temp_max(dev, buf, 0x##offset - 1); \
} \
static ssize_t set_temp_##offset##_min (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_temp_min(dev, buf, count, 0x##offset - 1); \
} \
static ssize_t set_temp_##offset##_max (struct device *dev, \
const char *buf, size_t count) \
{ \
return set_temp_max(dev, buf, count, 0x##offset - 1); \
} \
static DEVICE_ATTR(temp_input##offset, S_IRUGO, show_temp_##offset, NULL) \
static DEVICE_ATTR(temp_min##offset, S_IRUGO | S_IWUSR, \
show_temp_##offset##_min, set_temp_##offset##_min) \
static DEVICE_ATTR(temp_max##offset, S_IRUGO | S_IWUSR, \
show_temp_##offset##_max, set_temp_##offset##_max)
show_temp_reg(1);
show_temp_reg(2);
show_temp_reg(3);
int lm85_attach_adapter(struct i2c_adapter *adapter)
{
return i2c_detect(adapter, &addr_data, lm85_detect);
}
int lm85_detect(struct i2c_adapter *adapter, int address,
int kind)
{
int company, verstep ;
struct i2c_client *new_client = NULL;
struct lm85_data *data;
int err = 0;
const char *type_name = "";
if (i2c_is_isa_adapter(adapter)) {
/* This chip has no ISA interface */
goto ERROR0 ;
};
if (!i2c_check_functionality(adapter,
I2C_FUNC_SMBUS_BYTE_DATA)) {
/* We need to be able to do byte I/O */
goto ERROR0 ;
};
/* OK. For now, we presume we have a valid client. We now create the
client structure, even though we cannot fill it completely yet.
But it allows us to access lm85_{read,write}_value. */
if (!(new_client = kmalloc((sizeof(struct i2c_client)) +
sizeof(struct lm85_data),
GFP_KERNEL))) {
err = -ENOMEM;
goto ERROR0;
}
memset(new_client, 0, sizeof(struct i2c_client) +
sizeof(struct lm85_data));
data = (struct lm85_data *) (new_client + 1);
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &lm85_driver;
new_client->flags = 0;
/* Now, we do the remaining detection. */
company = lm85_read_value(new_client, LM85_REG_COMPANY);
verstep = lm85_read_value(new_client, LM85_REG_VERSTEP);
if (lm85debug) {
printk("lm85: Detecting device at %d,0x%02x with"
" COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
i2c_adapter_id(new_client->adapter), new_client->addr,
company, verstep);
}
/* If auto-detecting, Determine the chip type. */
if (kind <= 0) {
if (lm85debug) {
printk("lm85: Autodetecting device at %d,0x%02x ...\n",
i2c_adapter_id(adapter), address );
}
if( company == LM85_COMPANY_NATIONAL
&& verstep == LM85_VERSTEP_LM85C ) {
kind = lm85c ;
} else if( company == LM85_COMPANY_NATIONAL
&& verstep == LM85_VERSTEP_LM85B ) {
kind = lm85b ;
} else if( company == LM85_COMPANY_NATIONAL
&& (verstep & 0xf0) == LM85_VERSTEP_GENERIC ) {
printk("lm85: Unrecgonized version/stepping 0x%02x"
" Defaulting to LM85.\n", verstep );
kind = any_chip ;
} else if( company == LM85_COMPANY_ANALOG_DEV
&& verstep == LM85_VERSTEP_ADM1027 ) {
kind = adm1027 ;
} else if( company == LM85_COMPANY_ANALOG_DEV
&& verstep == LM85_VERSTEP_ADT7463 ) {
kind = adt7463 ;
} else if( company == LM85_COMPANY_ANALOG_DEV
&& (verstep & 0xf0) == LM85_VERSTEP_GENERIC ) {
printk("lm85: Unrecgonized version/stepping 0x%02x"
" Defaulting to ADM1027.\n", verstep );
kind = adm1027 ;
} else if( kind == 0 && (verstep & 0xf0) == 0x60) {
printk("lm85: Generic LM85 Version 6 detected\n");
/* Leave kind as "any_chip" */
} else {
if (lm85debug) {
printk("lm85: Autodetection failed\n");
}
/* Not an LM85 ... */
if( kind == 0 ) { /* User used force=x,y */
printk("lm85: Generic LM85 Version 6 not"
" found at %d,0x%02x. Try force_lm85c.\n",
i2c_adapter_id(adapter), address );
}
err = 0 ;
goto ERROR1;
}
}
/* Fill in the chip specific driver values */
if ( kind == any_chip ) {
type_name = "lm85";
strlcpy(new_client->dev.name, "Generic LM85", DEVICE_NAME_SIZE);
} else if ( kind == lm85b ) {
type_name = "lm85b";
strlcpy(new_client->dev.name, "National LM85-B", DEVICE_NAME_SIZE);
} else if ( kind == lm85c ) {
type_name = "lm85c";
strlcpy(new_client->dev.name, "National LM85-C", DEVICE_NAME_SIZE);
} else if ( kind == adm1027 ) {
type_name = "adm1027";
strlcpy(new_client->dev.name, "Analog Devices ADM1027", DEVICE_NAME_SIZE);
} else if ( kind == adt7463 ) {
type_name = "adt7463";
strlcpy(new_client->dev.name, "Analog Devices ADT7463", DEVICE_NAME_SIZE);
} else {
dev_dbg(&adapter->dev, "Internal error, invalid kind (%d)!", kind);
err = -EFAULT ;
goto ERROR1;
}
/* Fill in the remaining client fields */
new_client->id = lm85_id++;
data->type = kind;
data->valid = 0;
init_MUTEX(&data->update_lock);
if (lm85debug) {
printk("lm85: Assigning ID %d to %s at %d,0x%02x\n",
new_client->id, new_client->dev.name,
i2c_adapter_id(new_client->adapter),
new_client->addr);
}
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
goto ERROR1;
/* Set the VRM version */
data->vrm = LM85_INIT_VRM ;
device_create_file(&new_client->dev, &dev_attr_fan_input1);
device_create_file(&new_client->dev, &dev_attr_fan_input2);
device_create_file(&new_client->dev, &dev_attr_fan_input3);
device_create_file(&new_client->dev, &dev_attr_fan_input4);
device_create_file(&new_client->dev, &dev_attr_fan_min1);
device_create_file(&new_client->dev, &dev_attr_fan_min2);
device_create_file(&new_client->dev, &dev_attr_fan_min3);
device_create_file(&new_client->dev, &dev_attr_fan_min4);
device_create_file(&new_client->dev, &dev_attr_pwm1);
device_create_file(&new_client->dev, &dev_attr_pwm2);
device_create_file(&new_client->dev, &dev_attr_pwm3);
device_create_file(&new_client->dev, &dev_attr_pwm_enable1);
device_create_file(&new_client->dev, &dev_attr_pwm_enable2);
device_create_file(&new_client->dev, &dev_attr_pwm_enable3);
device_create_file(&new_client->dev, &dev_attr_in_input0);
device_create_file(&new_client->dev, &dev_attr_in_input1);
device_create_file(&new_client->dev, &dev_attr_in_input2);
device_create_file(&new_client->dev, &dev_attr_in_input3);
device_create_file(&new_client->dev, &dev_attr_in_input4);
device_create_file(&new_client->dev, &dev_attr_in_min0);
device_create_file(&new_client->dev, &dev_attr_in_min1);
device_create_file(&new_client->dev, &dev_attr_in_min2);
device_create_file(&new_client->dev, &dev_attr_in_min3);
device_create_file(&new_client->dev, &dev_attr_in_min4);
device_create_file(&new_client->dev, &dev_attr_in_max0);
device_create_file(&new_client->dev, &dev_attr_in_max1);
device_create_file(&new_client->dev, &dev_attr_in_max2);
device_create_file(&new_client->dev, &dev_attr_in_max3);
device_create_file(&new_client->dev, &dev_attr_in_max4);
device_create_file(&new_client->dev, &dev_attr_temp_input1);
device_create_file(&new_client->dev, &dev_attr_temp_input2);
device_create_file(&new_client->dev, &dev_attr_temp_input3);
device_create_file(&new_client->dev, &dev_attr_temp_min1);
device_create_file(&new_client->dev, &dev_attr_temp_min2);
device_create_file(&new_client->dev, &dev_attr_temp_min3);
device_create_file(&new_client->dev, &dev_attr_temp_max1);
device_create_file(&new_client->dev, &dev_attr_temp_max2);
device_create_file(&new_client->dev, &dev_attr_temp_max3);
device_create_file(&new_client->dev, &dev_attr_vrm);
device_create_file(&new_client->dev, &dev_attr_vid);
device_create_file(&new_client->dev, &dev_attr_alarms);
/* Initialize the LM85 chip */
lm85_init_client(new_client);
return 0;
/* Error out and cleanup code */
ERROR1:
kfree(new_client);
ERROR0:
return err;
}
int lm85_detach_client(struct i2c_client *client)
{
i2c_detach_client(client);
kfree(client);
return 0;
}
int lm85_read_value(struct i2c_client *client, u8 reg)
{
int res;
/* What size location is it? */
switch( reg ) {
case LM85_REG_FAN(0) : /* Read WORD data */
case LM85_REG_FAN(1) :
case LM85_REG_FAN(2) :
case LM85_REG_FAN(3) :
case LM85_REG_FAN_MIN(0) :
case LM85_REG_FAN_MIN(1) :
case LM85_REG_FAN_MIN(2) :
case LM85_REG_FAN_MIN(3) :
case LM85_REG_ALARM1 : /* Read both bytes at once */
case ADM1027_REG_EXTEND_ADC1 : /* Read two bytes at once */
res = i2c_smbus_read_byte_data(client, reg) & 0xff ;
res |= i2c_smbus_read_byte_data(client, reg+1) << 8 ;
break ;
case ADT7463_REG_TMIN_CTL1 : /* Read WORD MSB, LSB */
res = i2c_smbus_read_byte_data(client, reg) << 8 ;
res |= i2c_smbus_read_byte_data(client, reg+1) & 0xff ;
break ;
default: /* Read BYTE data */
res = i2c_smbus_read_byte_data(client, reg);
break ;
}
return res ;
}
int lm85_write_value(struct i2c_client *client, u8 reg, int value)
{
int res ;
switch( reg ) {
case LM85_REG_FAN(0) : /* Write WORD data */
case LM85_REG_FAN(1) :
case LM85_REG_FAN(2) :
case LM85_REG_FAN(3) :
case LM85_REG_FAN_MIN(0) :
case LM85_REG_FAN_MIN(1) :
case LM85_REG_FAN_MIN(2) :
case LM85_REG_FAN_MIN(3) :
/* NOTE: ALARM is read only, so not included here */
res = i2c_smbus_write_byte_data(client, reg, value & 0xff) ;
res |= i2c_smbus_write_byte_data(client, reg+1, (value>>8) & 0xff) ;
break ;
case ADT7463_REG_TMIN_CTL1 : /* Write WORD MSB, LSB */
res = i2c_smbus_write_byte_data(client, reg, (value>>8) & 0xff);
res |= i2c_smbus_write_byte_data(client, reg+1, value & 0xff) ;
break ;
default: /* Write BYTE data */
res = i2c_smbus_write_byte_data(client, reg, value);
break ;
}
return res ;
}
void lm85_init_client(struct i2c_client *client)
{
int value;
struct lm85_data *data = i2c_get_clientdata(client);
if (lm85debug) {
printk("lm85(%d): Initializing device\n", client->id);
}
/* Warn if part was not "READY" */
value = lm85_read_value(client, LM85_REG_CONFIG);
if (lm85debug) {
printk("lm85(%d): LM85_REG_CONFIG is: 0x%02x\n", client->id, value );
}
if( value & 0x02 ) {
printk("lm85(%d): Client (%d,0x%02x) config is locked.\n",
client->id,
i2c_adapter_id(client->adapter), client->addr );
};
if( ! (value & 0x04) ) {
printk("lm85(%d): Client (%d,0x%02x) is not ready.\n",
client->id,
i2c_adapter_id(client->adapter), client->addr );
};
if( value & 0x10
&& ( data->type == adm1027
|| data->type == adt7463 ) ) {
printk("lm85(%d): Client (%d,0x%02x) VxI mode is set. "
"Please report this to the lm85 maintainer.\n",
client->id,
i2c_adapter_id(client->adapter), client->addr );
};
/* WE INTENTIONALLY make no changes to the limits,
* offsets, pwms, fans and zones. If they were
* configured, we don't want to mess with them.
* If they weren't, the default is 100% PWM, no
* control and will suffice until 'sensors -s'
* can be run by the user.
*/
/* Start monitoring */
value = lm85_read_value(client, LM85_REG_CONFIG);
/* Try to clear LOCK, Set START, save everything else */
value = (value & ~ 0x02) | 0x01 ;
if (lm85debug) {
printk("lm85(%d): Setting CONFIG to: 0x%02x\n", client->id, value );
}
lm85_write_value(client, LM85_REG_CONFIG, value);
}
void lm85_update_client(struct i2c_client *client)
{
struct lm85_data *data = i2c_get_clientdata(client);
int i;
down(&data->update_lock);
if ( !data->valid ||
(jiffies - data->last_reading > LM85_DATA_INTERVAL ) ) {
/* Things that change quickly */
if (lm85debug) {
printk("lm85(%d): Reading sensor values\n", client->id);
}
/* Have to read extended bits first to "freeze" the
* more significant bits that are read later.
*/
if ( (data->type == adm1027) || (data->type == adt7463) ) {
data->extend_adc =
lm85_read_value(client, ADM1027_REG_EXTEND_ADC1);
}
for (i = 0; i <= 4; ++i) {
data->in[i] =
lm85_read_value(client, LM85_REG_IN(i));
}
for (i = 0; i <= 3; ++i) {
data->fan[i] =
lm85_read_value(client, LM85_REG_FAN(i));
}
for (i = 0; i <= 2; ++i) {
data->temp[i] =
lm85_read_value(client, LM85_REG_TEMP(i));
}
for (i = 0; i <= 2; ++i) {
data->pwm[i] =
lm85_read_value(client, LM85_REG_PWM(i));
}
if ( data->type == adt7463 ) {
if( data->therm_total < ULONG_MAX - 256 ) {
data->therm_total +=
lm85_read_value(client, ADT7463_REG_THERM );
}
}
data->alarms = lm85_read_value(client, LM85_REG_ALARM1);
data->last_reading = jiffies ;
}; /* last_reading */
if ( !data->valid ||
(jiffies - data->last_config > LM85_CONFIG_INTERVAL) ) {
/* Things that don't change often */
if (lm85debug) {
printk("lm85(%d): Reading config values\n", client->id);
}
for (i = 0; i <= 4; ++i) {
data->in_min[i] =
lm85_read_value(client, LM85_REG_IN_MIN(i));
data->in_max[i] =
lm85_read_value(client, LM85_REG_IN_MAX(i));
}
for (i = 0; i <= 3; ++i) {
data->fan_min[i] =
lm85_read_value(client, LM85_REG_FAN_MIN(i));
}
for (i = 0; i <= 2; ++i) {
data->temp_min[i] =
lm85_read_value(client, LM85_REG_TEMP_MIN(i));
data->temp_max[i] =
lm85_read_value(client, LM85_REG_TEMP_MAX(i));
}
data->vid = lm85_read_value(client, LM85_REG_VID);
for (i = 0; i <= 2; ++i) {
int val ;
data->autofan[i].config =
lm85_read_value(client, LM85_REG_AFAN_CONFIG(i));
val = lm85_read_value(client, LM85_REG_AFAN_RANGE(i));
data->autofan[i].freq = val & 0x07 ;
data->zone[i].range = (val >> 4) & 0x0f ;
data->autofan[i].min_pwm =
lm85_read_value(client, LM85_REG_AFAN_MINPWM(i));
data->zone[i].limit =
lm85_read_value(client, LM85_REG_AFAN_LIMIT(i));
data->zone[i].critical =
lm85_read_value(client, LM85_REG_AFAN_CRITICAL(i));
}
i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1);
data->smooth[0] = i & 0x0f ;
data->syncpwm3 = i & 0x10 ; /* Save PWM3 config */
data->autofan[0].min_off = (i & 0x20) != 0 ;
data->autofan[1].min_off = (i & 0x40) != 0 ;
data->autofan[2].min_off = (i & 0x80) != 0 ;
i = lm85_read_value(client, LM85_REG_AFAN_SPIKE2);
data->smooth[1] = (i>>4) & 0x0f ;
data->smooth[2] = i & 0x0f ;
i = lm85_read_value(client, LM85_REG_AFAN_HYST1);
data->zone[0].hyst = (i>>4) & 0x0f ;
data->zone[1].hyst = i & 0x0f ;
i = lm85_read_value(client, LM85_REG_AFAN_HYST2);
data->zone[2].hyst = (i>>4) & 0x0f ;
if ( (data->type == lm85b) || (data->type == lm85c) ) {
data->tach_mode = lm85_read_value(client,
LM85_REG_TACH_MODE );
data->spinup_ctl = lm85_read_value(client,
LM85_REG_SPINUP_CTL );
} else if ( (data->type == adt7463) || (data->type == adm1027) ) {
if ( data->type == adt7463 ) {
for (i = 0; i <= 2; ++i) {
data->oppoint[i] = lm85_read_value(client,
ADT7463_REG_OPPOINT(i) );
}
data->tmin_ctl = lm85_read_value(client,
ADT7463_REG_TMIN_CTL1 );
data->therm_limit = lm85_read_value(client,
ADT7463_REG_THERM_LIMIT );
}
for (i = 0; i <= 2; ++i) {
data->temp_offset[i] = lm85_read_value(client,
ADM1027_REG_TEMP_OFFSET(i) );
}
data->tach_mode = lm85_read_value(client,
ADM1027_REG_CONFIG3 );
data->fan_ppr = lm85_read_value(client,
ADM1027_REG_FAN_PPR );
}
data->last_config = jiffies;
}; /* last_config */
data->valid = 1;
up(&data->update_lock);
}
static int __init sm_lm85_init(void)
{
return i2c_add_driver(&lm85_driver);
}
static void __exit sm_lm85_exit(void)
{
i2c_del_driver(&lm85_driver);
}
/* Thanks to Richard Barrington for adding the LM85 to sensors-detect.
* Thanks to Margit Schubert-While <margitsw@t-online.de> for help with
* post 2.7.0 CVS changes
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Philip Pokorny <ppokorny@penguincomputing.com>, Margit Schubert-While <margitsw@t-online.de>");
MODULE_DESCRIPTION("LM85-B, LM85-C driver");
MODULE_PARM(lm85debug, "i");
MODULE_PARM_DESC(lm85debug, "Enable debugging statements");
module_init(sm_lm85_init);
module_exit(sm_lm85_exit);
...@@ -510,7 +510,7 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count) ...@@ -510,7 +510,7 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
msg.addr = client->addr; msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN; msg.flags = client->flags & I2C_M_TEN;
msg.len = count; msg.len = count;
(const char *)msg.buf = buf; msg.buf = (char *)buf;
DEB2(dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n", DEB2(dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n",
count)); count));
...@@ -861,13 +861,13 @@ int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial, ...@@ -861,13 +861,13 @@ int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial,
return 0; return 0;
} }
extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value) s32 i2c_smbus_write_quick(struct i2c_client *client, u8 value)
{ {
return i2c_smbus_xfer(client->adapter,client->addr,client->flags, return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
value,0,I2C_SMBUS_QUICK,NULL); value,0,I2C_SMBUS_QUICK,NULL);
} }
extern s32 i2c_smbus_read_byte(struct i2c_client * client) s32 i2c_smbus_read_byte(struct i2c_client *client)
{ {
union i2c_smbus_data data; union i2c_smbus_data data;
if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
...@@ -877,14 +877,14 @@ extern s32 i2c_smbus_read_byte(struct i2c_client * client) ...@@ -877,14 +877,14 @@ extern s32 i2c_smbus_read_byte(struct i2c_client * client)
return 0x0FF & data.byte; return 0x0FF & data.byte;
} }
extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value) s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value)
{ {
union i2c_smbus_data data; /* only for PEC */ union i2c_smbus_data data; /* only for PEC */
return i2c_smbus_xfer(client->adapter,client->addr,client->flags, return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,&data); I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,&data);
} }
extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command) s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command)
{ {
union i2c_smbus_data data; union i2c_smbus_data data;
if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
...@@ -894,8 +894,7 @@ extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command) ...@@ -894,8 +894,7 @@ extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command)
return 0x0FF & data.byte; return 0x0FF & data.byte;
} }
extern s32 i2c_smbus_write_byte_data(struct i2c_client * client, u8 command, s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value)
u8 value)
{ {
union i2c_smbus_data data; union i2c_smbus_data data;
data.byte = value; data.byte = value;
...@@ -904,7 +903,7 @@ extern s32 i2c_smbus_write_byte_data(struct i2c_client * client, u8 command, ...@@ -904,7 +903,7 @@ extern s32 i2c_smbus_write_byte_data(struct i2c_client * client, u8 command,
I2C_SMBUS_BYTE_DATA,&data); I2C_SMBUS_BYTE_DATA,&data);
} }
extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command) s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command)
{ {
union i2c_smbus_data data; union i2c_smbus_data data;
if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
...@@ -914,8 +913,7 @@ extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command) ...@@ -914,8 +913,7 @@ extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command)
return 0x0FFFF & data.word; return 0x0FFFF & data.word;
} }
extern s32 i2c_smbus_write_word_data(struct i2c_client * client, s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
u8 command, u16 value)
{ {
union i2c_smbus_data data; union i2c_smbus_data data;
data.word = value; data.word = value;
...@@ -924,8 +922,7 @@ extern s32 i2c_smbus_write_word_data(struct i2c_client * client, ...@@ -924,8 +922,7 @@ extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
I2C_SMBUS_WORD_DATA,&data); I2C_SMBUS_WORD_DATA,&data);
} }
extern s32 i2c_smbus_process_call(struct i2c_client * client, s32 i2c_smbus_process_call(struct i2c_client *client, u8 command, u16 value)
u8 command, u16 value)
{ {
union i2c_smbus_data data; union i2c_smbus_data data;
data.word = value; data.word = value;
...@@ -938,8 +935,7 @@ extern s32 i2c_smbus_process_call(struct i2c_client * client, ...@@ -938,8 +935,7 @@ extern s32 i2c_smbus_process_call(struct i2c_client * client,
} }
/* Returns the number of read bytes */ /* Returns the number of read bytes */
extern s32 i2c_smbus_read_block_data(struct i2c_client * client, s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command, u8 *values)
u8 command, u8 *values)
{ {
union i2c_smbus_data data; union i2c_smbus_data data;
int i; int i;
...@@ -954,8 +950,7 @@ extern s32 i2c_smbus_read_block_data(struct i2c_client * client, ...@@ -954,8 +950,7 @@ extern s32 i2c_smbus_read_block_data(struct i2c_client * client,
} }
} }
extern s32 i2c_smbus_write_block_data(struct i2c_client * client, s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, u8 length, u8 *values)
u8 command, u8 length, u8 *values)
{ {
union i2c_smbus_data data; union i2c_smbus_data data;
int i; int i;
...@@ -970,8 +965,7 @@ extern s32 i2c_smbus_write_block_data(struct i2c_client * client, ...@@ -970,8 +965,7 @@ extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
} }
/* Returns the number of read bytes */ /* Returns the number of read bytes */
extern s32 i2c_smbus_block_process_call(struct i2c_client * client, s32 i2c_smbus_block_process_call(struct i2c_client *client, u8 command, u8 length, u8 *values)
u8 command, u8 length, u8 *values)
{ {
union i2c_smbus_data data; union i2c_smbus_data data;
int i; int i;
...@@ -990,8 +984,7 @@ extern s32 i2c_smbus_block_process_call(struct i2c_client * client, ...@@ -990,8 +984,7 @@ extern s32 i2c_smbus_block_process_call(struct i2c_client * client,
} }
/* Returns the number of read bytes */ /* Returns the number of read bytes */
extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values)
u8 command, u8 *values)
{ {
union i2c_smbus_data data; union i2c_smbus_data data;
int i; int i;
...@@ -1006,8 +999,7 @@ extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, ...@@ -1006,8 +999,7 @@ extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client,
} }
} }
extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, u8 length, u8 *values)
u8 command, u8 length, u8 *values)
{ {
union i2c_smbus_data data; union i2c_smbus_data data;
int i; int i;
......
...@@ -122,7 +122,7 @@ static ssize_t show_dev(struct class_device *class_dev, char *buf) ...@@ -122,7 +122,7 @@ static ssize_t show_dev(struct class_device *class_dev, char *buf)
} }
static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, static ssize_t i2cdev_read (struct file *file, char __user *buf, size_t count,
loff_t *offset) loff_t *offset)
{ {
char *tmp; char *tmp;
...@@ -147,7 +147,7 @@ static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, ...@@ -147,7 +147,7 @@ static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
return ret; return ret;
} }
static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t count,
loff_t *offset) loff_t *offset)
{ {
int ret; int ret;
...@@ -211,12 +211,12 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, ...@@ -211,12 +211,12 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
return 0; return 0;
case I2C_FUNCS: case I2C_FUNCS:
funcs = i2c_get_functionality(client->adapter); funcs = i2c_get_functionality(client->adapter);
return (copy_to_user((unsigned long *)arg,&funcs, return (copy_to_user((unsigned long __user *)arg, &funcs,
sizeof(unsigned long)))?-EFAULT:0; sizeof(unsigned long)))?-EFAULT:0;
case I2C_RDWR: case I2C_RDWR:
if (copy_from_user(&rdwr_arg, if (copy_from_user(&rdwr_arg,
(struct i2c_rdwr_ioctl_data *)arg, (struct i2c_rdwr_ioctl_data __user *)arg,
sizeof(rdwr_arg))) sizeof(rdwr_arg)))
return -EFAULT; return -EFAULT;
...@@ -284,7 +284,7 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, ...@@ -284,7 +284,7 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
case I2C_SMBUS: case I2C_SMBUS:
if (copy_from_user(&data_arg, if (copy_from_user(&data_arg,
(struct i2c_smbus_ioctl_data *) arg, (struct i2c_smbus_ioctl_data __user *) arg,
sizeof(struct i2c_smbus_ioctl_data))) sizeof(struct i2c_smbus_ioctl_data)))
return -EFAULT; return -EFAULT;
if ((data_arg.size != I2C_SMBUS_BYTE) && if ((data_arg.size != I2C_SMBUS_BYTE) &&
......
/* ------------------------------------------------------------------------- */
/* i2c-iop3xx.c i2c driver algorithms for Intel XScale IOP3xx */
/* ------------------------------------------------------------------------- */
/* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd
* <Peter dot Milne at D hyphen TACQ dot com>
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ------------------------------------------------------------------------- */
/*
With acknowledgements to i2c-algo-ibm_ocp.c by
Ian DaSilva, MontaVista Software, Inc. idasilva@mvista.com
And i2c-algo-pcf.c, which was created by Simon G. Vogl and Hans Berglund:
Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund
And which acknowledged Kysti Mlkki <kmalkki@cc.hut.fi>,
Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com>
---------------------------------------------------------------------------*/
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/i2c.h>
#include <asm/arch-iop3xx/iop321.h>
#include <asm/arch-iop3xx/iop321-irqs.h>
#include "i2c-iop3xx.h"
/* ----- global defines ----------------------------------------------- */
#define PASSERT(x) do { if (!(x) ) \
printk(KERN_CRIT "PASSERT %s in %s:%d\n", #x, __FILE__, __LINE__ );\
} while (0)
/* ----- global variables --------------------------------------------- */
static inline unsigned char iic_cook_addr(struct i2c_msg *msg)
{
unsigned char addr;
addr = (msg->addr << 1);
if (msg->flags & I2C_M_RD)
addr |= 1;
/* PGM: what is M_REV_DIR_ADDR - do we need it ?? */
if (msg->flags & I2C_M_REV_DIR_ADDR)
addr ^= 1;
return addr;
}
static inline void iop3xx_adap_reset(struct i2c_algo_iop3xx_data *iop3xx_adap)
{
/* Follows devman 9.3 */
*iop3xx_adap->biu->CR = IOP321_ICR_UNIT_RESET;
*iop3xx_adap->biu->SR = IOP321_ISR_CLEARBITS;
*iop3xx_adap->biu->CR = 0;
}
static inline void iop3xx_adap_set_slave_addr(struct i2c_algo_iop3xx_data *iop3xx_adap)
{
*iop3xx_adap->biu->SAR = MYSAR;
}
static inline void iop3xx_adap_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
{
u32 cr = IOP321_ICR_GCD|IOP321_ICR_SCLEN|IOP321_ICR_UE;
/* NB SR bits not same position as CR IE bits :-( */
iop3xx_adap->biu->SR_enabled =
IOP321_ISR_ALD | IOP321_ISR_BERRD |
IOP321_ISR_RXFULL | IOP321_ISR_TXEMPTY;
cr |= IOP321_ICR_ALDIE | IOP321_ICR_BERRIE |
IOP321_ICR_RXFULLIE | IOP321_ICR_TXEMPTYIE;
*iop3xx_adap->biu->CR = cr;
}
static void iop3xx_adap_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap)
{
unsigned cr = *iop3xx_adap->biu->CR;
cr &= ~(IOP321_ICR_MSTART | IOP321_ICR_TBYTE |
IOP321_ICR_MSTOP | IOP321_ICR_SCLEN);
*iop3xx_adap->biu->CR = cr;
}
static void iop3xx_adap_final_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap)
{
unsigned cr = *iop3xx_adap->biu->CR;
cr &= ~(IOP321_ICR_ALDIE | IOP321_ICR_BERRIE |
IOP321_ICR_RXFULLIE | IOP321_ICR_TXEMPTYIE);
iop3xx_adap->biu->SR_enabled = 0;
*iop3xx_adap->biu->CR = cr;
}
/*
* NB: the handler has to clear the source of the interrupt!
* Then it passes the SR flags of interest to BH via adap data
*/
static void iop3xx_i2c_handler(int this_irq,
void *dev_id,
struct pt_regs *regs)
{
struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id;
u32 sr = *iop3xx_adap->biu->SR;
if ((sr &= iop3xx_adap->biu->SR_enabled)) {
*iop3xx_adap->biu->SR = sr;
iop3xx_adap->biu->SR_received |= sr;
wake_up_interruptible(&iop3xx_adap->waitq);
}
}
/* check all error conditions, clear them , report most important */
static int iop3xx_adap_error(u32 sr)
{
int rc = 0;
if ((sr&IOP321_ISR_BERRD)) {
if ( !rc ) rc = -I2C_ERR_BERR;
}
if ((sr&IOP321_ISR_ALD)) {
if ( !rc ) rc = -I2C_ERR_ALD;
}
return rc;
}
static inline u32 get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap)
{
unsigned long flags;
u32 sr;
spin_lock_irqsave(&iop3xx_adap->lock, flags);
sr = iop3xx_adap->biu->SR_received;
iop3xx_adap->biu->SR_received = 0;
spin_unlock_irqrestore(&iop3xx_adap->lock, flags);
return sr;
}
/*
* sleep until interrupted, then recover and analyse the SR
* saved by handler
*/
typedef int (* compare_func)(unsigned test, unsigned mask);
/* returns 1 on correct comparison */
static int iop3xx_adap_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap,
unsigned flags, unsigned* status,
compare_func compare)
{
unsigned sr = 0;
int interrupted;
int done;
int rc;
do {
interrupted = wait_event_interruptible_timeout (
iop3xx_adap->waitq,
(done = compare( sr = get_srstat(iop3xx_adap),flags )),
iop3xx_adap->timeout
);
if ((rc = iop3xx_adap_error(sr)) < 0) {
*status = sr;
return rc;
}else if (!interrupted) {
*status = sr;
return rc = -ETIMEDOUT;
}
} while(!done);
*status = sr;
return rc = 0;
}
/*
* Concrete compare_funcs
*/
static int all_bits_clear(unsigned test, unsigned mask)
{
return (test & mask) == 0;
}
static int any_bits_set(unsigned test, unsigned mask)
{
return (test & mask) != 0;
}
static int iop3xx_adap_wait_tx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
{
return iop3xx_adap_wait_event(
iop3xx_adap,
IOP321_ISR_TXEMPTY|IOP321_ISR_ALD|IOP321_ISR_BERRD,
status, any_bits_set);
}
static int iop3xx_adap_wait_rx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
{
return iop3xx_adap_wait_event(
iop3xx_adap,
IOP321_ISR_RXFULL|IOP321_ISR_ALD|IOP321_ISR_BERRD,
status, any_bits_set);
}
static int iop3xx_adap_wait_idle(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
{
return iop3xx_adap_wait_event(
iop3xx_adap, IOP321_ISR_UNITBUSY, status, all_bits_clear);
}
/*
* Description: This performs the IOP3xx initialization sequence
* Valid for IOP321. Maybe valid for IOP310?.
*/
static int iop3xx_adap_init (struct i2c_algo_iop3xx_data *iop3xx_adap)
{
*IOP321_GPOD &= ~(iop3xx_adap->channel==0 ?
IOP321_GPOD_I2C0:
IOP321_GPOD_I2C1);
iop3xx_adap_reset(iop3xx_adap);
iop3xx_adap_set_slave_addr(iop3xx_adap);
iop3xx_adap_enable(iop3xx_adap);
return 0;
}
static int iop3xx_adap_send_target_slave_addr(struct i2c_algo_iop3xx_data *iop3xx_adap,
struct i2c_msg* msg)
{
unsigned cr = *iop3xx_adap->biu->CR;
int status;
int rc;
*iop3xx_adap->biu->DBR = iic_cook_addr(msg);
cr &= ~(IOP321_ICR_MSTOP | IOP321_ICR_NACK);
cr |= IOP321_ICR_MSTART | IOP321_ICR_TBYTE;
*iop3xx_adap->biu->CR = cr;
rc = iop3xx_adap_wait_tx_done(iop3xx_adap, &status);
/* this assert fires every time, contrary to IOP manual
PASSERT((status&IOP321_ISR_UNITBUSY)!=0);
*/
PASSERT((status&IOP321_ISR_RXREAD)==0);
return rc;
}
static int iop3xx_adap_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte, int stop)
{
unsigned cr = *iop3xx_adap->biu->CR;
int status;
int rc;
*iop3xx_adap->biu->DBR = byte;
cr &= ~IOP321_ICR_MSTART;
if (stop) {
cr |= IOP321_ICR_MSTOP;
} else {
cr &= ~IOP321_ICR_MSTOP;
}
*iop3xx_adap->biu->CR = cr |= IOP321_ICR_TBYTE;
rc = iop3xx_adap_wait_tx_done(iop3xx_adap, &status);
return rc;
}
static int iop3xx_adap_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap,
char* byte, int stop)
{
unsigned cr = *iop3xx_adap->biu->CR;
int status;
int rc;
cr &= ~IOP321_ICR_MSTART;
if (stop) {
cr |= IOP321_ICR_MSTOP|IOP321_ICR_NACK;
} else {
cr &= ~(IOP321_ICR_MSTOP|IOP321_ICR_NACK);
}
*iop3xx_adap->biu->CR = cr |= IOP321_ICR_TBYTE;
rc = iop3xx_adap_wait_rx_done(iop3xx_adap, &status);
*byte = *iop3xx_adap->biu->DBR;
return rc;
}
static int iop3xx_i2c_writebytes(struct i2c_adapter *i2c_adap,
const char *buf, int count)
{
struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
int ii;
int rc = 0;
for (ii = 0; rc == 0 && ii != count; ++ii) {
rc = iop3xx_adap_write_byte(iop3xx_adap, buf[ii], ii==count-1);
}
return rc;
}
static int iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap,
char *buf, int count)
{
struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
int ii;
int rc = 0;
for (ii = 0; rc == 0 && ii != count; ++ii) {
rc = iop3xx_adap_read_byte(iop3xx_adap, &buf[ii], ii==count-1);
}
return rc;
}
/*
* Description: This function implements combined transactions. Combined
* transactions consist of combinations of reading and writing blocks of data.
* FROM THE SAME ADDRESS
* Each transfer (i.e. a read or a write) is separated by a repeated start
* condition.
*/
static int iop3xx_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg)
{
struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
int rc;
rc = iop3xx_adap_send_target_slave_addr(iop3xx_adap, pmsg);
if (rc < 0) {
return rc;
}
if ((pmsg->flags&I2C_M_RD)) {
return iop3xx_i2c_readbytes(i2c_adap, pmsg->buf, pmsg->len);
} else {
return iop3xx_i2c_writebytes(i2c_adap, pmsg->buf, pmsg->len);
}
}
/*
* master_xfer() - main read/write entry
*/
static int iop3xx_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
{
struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
int im = 0;
int ret = 0;
int status;
iop3xx_adap_wait_idle(iop3xx_adap, &status);
iop3xx_adap_reset(iop3xx_adap);
iop3xx_adap_enable(iop3xx_adap);
for (im = 0; ret == 0 && im != num; ++im) {
ret = iop3xx_handle_msg(i2c_adap, &msgs[im]);
}
iop3xx_adap_transaction_cleanup(iop3xx_adap);
return ret;
}
static int algo_control(struct i2c_adapter *adapter, unsigned int cmd,
unsigned long arg)
{
return 0;
}
static u32 iic_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
/* -----exported algorithm data: ------------------------------------- */
static struct i2c_algorithm iic_algo = {
.name = "IOP3xx I2C algorithm",
.id = I2C_ALGO_OCP_IOP3XX,
.master_xfer = iop3xx_master_xfer,
.algo_control = algo_control,
.functionality = iic_func,
};
/*
* registering functions to load algorithms at runtime
*/
static int i2c_iop3xx_add_bus(struct i2c_adapter *iic_adap)
{
struct i2c_algo_iop3xx_data *iop3xx_adap = iic_adap->algo_data;
if (!request_region( REGION_START(iop3xx_adap),
REGION_LENGTH(iop3xx_adap),
iic_adap->name)) {
return -ENODEV;
}
init_waitqueue_head(&iop3xx_adap->waitq);
spin_lock_init(&iop3xx_adap->lock);
if (request_irq(
iop3xx_adap->biu->irq,
iop3xx_i2c_handler,
/* SA_SAMPLE_RANDOM */ 0,
iic_adap->name,
iop3xx_adap)) {
return -ENODEV;
}
/* register new iic_adapter to i2c module... */
iic_adap->id |= iic_algo.id;
iic_adap->algo = &iic_algo;
iic_adap->timeout = 100; /* default values, should */
iic_adap->retries = 3; /* be replaced by defines */
iop3xx_adap_init(iic_adap->algo_data);
i2c_add_adapter(iic_adap);
return 0;
}
static int i2c_iop3xx_del_bus(struct i2c_adapter *iic_adap)
{
struct i2c_algo_iop3xx_data *iop3xx_adap = iic_adap->algo_data;
iop3xx_adap_final_cleanup(iop3xx_adap);
free_irq(iop3xx_adap->biu->irq, iop3xx_adap);
release_region(REGION_START(iop3xx_adap), REGION_LENGTH(iop3xx_adap));
return i2c_del_adapter(iic_adap);
}
#ifdef CONFIG_ARCH_IOP321
static struct iop3xx_biu biu0 = {
.CR = IOP321_ICR0,
.SR = IOP321_ISR0,
.SAR = IOP321_ISAR0,
.DBR = IOP321_IDBR0,
.BMR = IOP321_IBMR0,
.irq = IRQ_IOP321_I2C_0,
};
static struct iop3xx_biu biu1 = {
.CR = IOP321_ICR1,
.SR = IOP321_ISR1,
.SAR = IOP321_ISAR1,
.DBR = IOP321_IDBR1,
.BMR = IOP321_IBMR1,
.irq = IRQ_IOP321_I2C_1,
};
#define ADAPTER_NAME_ROOT "IOP321 i2c biu adapter "
#else
#error Please define the BIU struct iop3xx_biu for your processor arch
#endif
static struct i2c_algo_iop3xx_data algo_iop3xx_data0 = {
.channel = 0,
.biu = &biu0,
.timeout = 1*HZ,
};
static struct i2c_algo_iop3xx_data algo_iop3xx_data1 = {
.channel = 1,
.biu = &biu1,
.timeout = 1*HZ,
};
static struct i2c_adapter iop3xx_ops0 = {
.owner = THIS_MODULE,
.name = ADAPTER_NAME_ROOT "0",
.id = I2C_HW_IOP321,
.algo_data = &algo_iop3xx_data0,
};
static struct i2c_adapter iop3xx_ops1 = {
.owner = THIS_MODULE,
.name = ADAPTER_NAME_ROOT "1",
.id = I2C_HW_IOP321,
.algo_data = &algo_iop3xx_data1,
};
static int __init i2c_iop3xx_init (void)
{
return i2c_iop3xx_add_bus(&iop3xx_ops0) ||
i2c_iop3xx_add_bus(&iop3xx_ops1);
}
static void __exit i2c_iop3xx_exit (void)
{
i2c_iop3xx_del_bus(&iop3xx_ops0);
i2c_iop3xx_del_bus(&iop3xx_ops1);
}
module_init (i2c_iop3xx_init);
module_exit (i2c_iop3xx_exit);
MODULE_AUTHOR("D-TACQ Solutions Ltd <www.d-tacq.com>");
MODULE_DESCRIPTION("IOP3xx iic algorithm and driver");
MODULE_LICENSE("GPL");
MODULE_PARM(i2c_debug,"i");
MODULE_PARM_DESC(i2c_debug, "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol");
/* ------------------------------------------------------------------------- */
/* i2c-iop3xx.h algorithm driver definitions private to i2c-iop3xx.c */
/* ------------------------------------------------------------------------- */
/* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd
* <Peter dot Milne at D hyphen TACQ dot com>
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ------------------------------------------------------------------------- */
#ifndef I2C_IOP3XX_H
#define I2C_IOP3XX_H 1
/*
* iop321 hardware bit definitions
*/
#define IOP321_ICR_FAST_MODE 0x8000 /* 1=400kBps, 0=100kBps */
#define IOP321_ICR_UNIT_RESET 0x4000 /* 1=RESET */
#define IOP321_ICR_SADIE 0x2000 /* 1=Slave Detect Interrupt Enable */
#define IOP321_ICR_ALDIE 0x1000 /* 1=Arb Loss Detect Interrupt Enable */
#define IOP321_ICR_SSDIE 0x0800 /* 1=Slave STOP Detect Interrupt Enable */
#define IOP321_ICR_BERRIE 0x0400 /* 1=Bus Error Interrupt Enable */
#define IOP321_ICR_RXFULLIE 0x0200 /* 1=Receive Full Interrupt Enable */
#define IOP321_ICR_TXEMPTYIE 0x0100 /* 1=Transmit Empty Interrupt Enable */
#define IOP321_ICR_GCD 0x0080 /* 1=General Call Disable */
/*
* IOP321_ICR_GCD: 1 disables response as slave. "This bit must be set
* when sending a master mode general call message from the I2C unit"
*/
#define IOP321_ICR_UE 0x0040 /* 1=Unit Enable */
/*
* "NOTE: To avoid I2C bus integrity problems,
* the user needs to ensure that the GPIO Output Data Register -
* GPOD bits associated with an I2C port are cleared prior to setting
* the enable bit for that I2C serial port.
* The user prepares to enable I2C port 0 and
* I2C port 1 by clearing GPOD bits 7:6 and GPOD bits 5:4, respectively.
*/
#define IOP321_ICR_SCLEN 0x0020 /* 1=SCL enable for master mode */
#define IOP321_ICR_MABORT 0x0010 /* 1=Send a STOP with no data
* NB TBYTE must be clear */
#define IOP321_ICR_TBYTE 0x0008 /* 1=Send/Receive a byte. i2c clears */
#define IOP321_ICR_NACK 0x0004 /* 1=reply with NACK */
#define IOP321_ICR_MSTOP 0x0002 /* 1=send a STOP after next data byte */
#define IOP321_ICR_MSTART 0x0001 /* 1=initiate a START */
#define IOP321_ISR_BERRD 0x0400 /* 1=BUS ERROR Detected */
#define IOP321_ISR_SAD 0x0200 /* 1=Slave ADdress Detected */
#define IOP321_ISR_GCAD 0x0100 /* 1=General Call Address Detected */
#define IOP321_ISR_RXFULL 0x0080 /* 1=Receive Full */
#define IOP321_ISR_TXEMPTY 0x0040 /* 1=Transmit Empty */
#define IOP321_ISR_ALD 0x0020 /* 1=Arbitration Loss Detected */
#define IOP321_ISR_SSD 0x0010 /* 1=Slave STOP Detected */
#define IOP321_ISR_BBUSY 0x0008 /* 1=Bus BUSY */
#define IOP321_ISR_UNITBUSY 0x0004 /* 1=Unit Busy */
#define IOP321_ISR_NACK 0x0002 /* 1=Unit Rx or Tx a NACK */
#define IOP321_ISR_RXREAD 0x0001 /* 1=READ 0=WRITE (R/W bit of slave addr */
#define IOP321_ISR_CLEARBITS 0x07f0
#define IOP321_ISAR_SAMASK 0x007f
#define IOP321_IDBR_MASK 0x00ff
#define IOP321_IBMR_SCL 0x0002
#define IOP321_IBMR_SDA 0x0001
#define IOP321_GPOD_I2C0 0x00c0 /* clear these bits to enable ch0 */
#define IOP321_GPOD_I2C1 0x0030 /* clear these bits to enable ch1 */
#define MYSAR 0x02 /* SWAG a suitable slave address */
#define I2C_ERR 321
#define I2C_ERR_BERR (I2C_ERR+0)
#define I2C_ERR_ALD (I2C_ERR+1)
struct iop3xx_biu { /* Bus Interface Unit - the hardware */
/* physical hardware defs - regs*/
u32 *CR;
u32 *SR;
u32 *SAR;
u32 *DBR;
u32 *BMR;
/* irq bit vector */
u32 irq;
/* stored flags */
u32 SR_enabled, SR_received;
};
struct i2c_algo_iop3xx_data {
int channel;
wait_queue_head_t waitq;
spinlock_t lock;
int timeout;
struct iop3xx_biu* biu;
};
#define REGION_START(adap) ((u32)((adap)->biu->CR))
#define REGION_END(adap) ((u32)((adap)->biu->BMR+1))
#define REGION_LENGTH(adap) (REGION_END(adap)-REGION_START(adap))
#define IRQ_STATUS_MASK(adap) (1<<adap->biu->irq)
#endif /* I2C_IOP3XX_H */
...@@ -34,13 +34,13 @@ struct i2c_smbus_ioctl_data { ...@@ -34,13 +34,13 @@ struct i2c_smbus_ioctl_data {
__u8 read_write; __u8 read_write;
__u8 command; __u8 command;
__u32 size; __u32 size;
union i2c_smbus_data *data; union i2c_smbus_data __user *data;
}; };
/* This is the structure as used in the I2C_RDWR ioctl call */ /* This is the structure as used in the I2C_RDWR ioctl call */
struct i2c_rdwr_ioctl_data { struct i2c_rdwr_ioctl_data {
struct i2c_msg *msgs; /* pointers to i2c_msgs */ struct i2c_msg __user *msgs; /* pointers to i2c_msgs */
__u32 nmsgs; /* number of i2c_msgs */ __u32 nmsgs; /* number of i2c_msgs */
}; };
#endif /* _LINUX_I2C_DEV_H */ #endif /* _LINUX_I2C_DEV_H */
...@@ -176,7 +176,7 @@ static inline void *i2c_get_clientdata (struct i2c_client *dev) ...@@ -176,7 +176,7 @@ static inline void *i2c_get_clientdata (struct i2c_client *dev)
static inline void i2c_set_clientdata (struct i2c_client *dev, void *data) static inline void i2c_set_clientdata (struct i2c_client *dev, void *data)
{ {
return dev_set_drvdata (&dev->dev, data); dev_set_drvdata (&dev->dev, data);
} }
#define I2C_DEVNAME(str) .dev = { .name = str } #define I2C_DEVNAME(str) .dev = { .name = str }
...@@ -261,7 +261,7 @@ static inline void *i2c_get_adapdata (struct i2c_adapter *dev) ...@@ -261,7 +261,7 @@ static inline void *i2c_get_adapdata (struct i2c_adapter *dev)
static inline void i2c_set_adapdata (struct i2c_adapter *dev, void *data) static inline void i2c_set_adapdata (struct i2c_adapter *dev, void *data)
{ {
return dev_set_drvdata (&dev->dev, data); dev_set_drvdata (&dev->dev, data);
} }
/*flags for the driver struct: */ /*flags for the driver struct: */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment