Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
7cbfaf48
Commit
7cbfaf48
authored
Oct 08, 2003
by
Jean Delvare
Committed by
Greg Kroah-Hartman
Oct 08, 2003
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[PATCH] I2C: Add lm83 chip driver
parent
d0a2fba8
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
426 additions
and
0 deletions
+426
-0
drivers/i2c/chips/Kconfig
drivers/i2c/chips/Kconfig
+11
-0
drivers/i2c/chips/Makefile
drivers/i2c/chips/Makefile
+1
-0
drivers/i2c/chips/lm83.c
drivers/i2c/chips/lm83.c
+413
-0
include/linux/i2c-id.h
include/linux/i2c-id.h
+1
-0
No files found.
drivers/i2c/chips/Kconfig
View file @
7cbfaf48
...
...
@@ -68,6 +68,17 @@ config SENSORS_LM78
This driver can also be built as a module. If so, the module
will be called lm78.
config SENSORS_LM83
tristate "National Semiconductor LM83"
depends on I2C && EXPERIMENTAL
select I2C_SENSOR
help
If you say yes here you get support for National Semiconductor
LM83 sensor chips.
This driver can also be built as a module. If so, the module
will be called lm83.
config SENSORS_LM85
tristate "National Semiconductors LM85 and compatibles"
depends on I2C && EXPERIMENTAL
...
...
drivers/i2c/chips/Makefile
View file @
7cbfaf48
...
...
@@ -10,5 +10,6 @@ obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o
obj-$(CONFIG_SENSORS_IT87)
+=
it87.o
obj-$(CONFIG_SENSORS_LM75)
+=
lm75.o
obj-$(CONFIG_SENSORS_LM78)
+=
lm78.o
obj-$(CONFIG_SENSORS_LM83)
+=
lm83.o
obj-$(CONFIG_SENSORS_LM85)
+=
lm85.o
obj-$(CONFIG_SENSORS_VIA686A)
+=
via686a.o
drivers/i2c/chips/lm83.c
0 → 100644
View file @
7cbfaf48
/*
* lm83.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring
* Copyright (C) 2003 Jean Delvare <khali@linux-fr.org>
*
* Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is
* a sensor chip made by National Semiconductor. It reports up to four
* temperatures (its own plus up to three external ones) with a 1 deg
* resolution and a 3-4 deg accuracy. Complete datasheet can be obtained
* from National's website at:
* http://www.national.com/pf/LM/LM83.html
* Since the datasheet omits to give the chip stepping code, I give it
* here: 0x03 (at register 0xff).
*
* 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>
/*
* Addresses to scan
* Address is selected using 2 three-level pins, resulting in 9 possible
* addresses.
*/
static
unsigned
short
normal_i2c
[]
=
{
I2C_CLIENT_END
};
static
unsigned
short
normal_i2c_range
[]
=
{
0x18
,
0x1a
,
0x29
,
0x2b
,
0x4c
,
0x4e
,
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_1
(
lm83
);
/*
* The LM83 registers
* Manufacturer ID is 0x01 for National Semiconductor.
*/
#define LM83_REG_R_MAN_ID 0xFE
#define LM83_REG_R_CHIP_ID 0xFF
#define LM83_REG_R_CONFIG 0x03
#define LM83_REG_W_CONFIG 0x09
#define LM83_REG_R_STATUS1 0x02
#define LM83_REG_R_STATUS2 0x35
#define LM83_REG_R_LOCAL_TEMP 0x00
#define LM83_REG_R_LOCAL_HIGH 0x05
#define LM83_REG_W_LOCAL_HIGH 0x0B
#define LM83_REG_R_REMOTE1_TEMP 0x30
#define LM83_REG_R_REMOTE1_HIGH 0x38
#define LM83_REG_W_REMOTE1_HIGH 0x50
#define LM83_REG_R_REMOTE2_TEMP 0x01
#define LM83_REG_R_REMOTE2_HIGH 0x07
#define LM83_REG_W_REMOTE2_HIGH 0x0D
#define LM83_REG_R_REMOTE3_TEMP 0x31
#define LM83_REG_R_REMOTE3_HIGH 0x3A
#define LM83_REG_W_REMOTE3_HIGH 0x52
#define LM83_REG_R_TCRIT 0x42
#define LM83_REG_W_TCRIT 0x5A
/*
* Conversions, initial values and various macros
* The LM83 uses signed 8-bit values.
*/
#define TEMP_FROM_REG(val) ((val > 127 ? val-256 : val) * 1000)
#define TEMP_TO_REG(val) ((val < 0 ? val+256 : val) / 1000)
#define LM83_INIT_HIGH 100
#define LM83_INIT_CRIT 120
static
const
u8
LM83_REG_R_TEMP
[]
=
{
LM83_REG_R_LOCAL_TEMP
,
LM83_REG_R_REMOTE1_TEMP
,
LM83_REG_R_REMOTE2_TEMP
,
LM83_REG_R_REMOTE3_TEMP
};
static
const
u8
LM83_REG_R_HIGH
[]
=
{
LM83_REG_R_LOCAL_HIGH
,
LM83_REG_R_REMOTE1_HIGH
,
LM83_REG_R_REMOTE2_HIGH
,
LM83_REG_R_REMOTE3_HIGH
};
static
const
u8
LM83_REG_W_HIGH
[]
=
{
LM83_REG_W_LOCAL_HIGH
,
LM83_REG_W_REMOTE1_HIGH
,
LM83_REG_W_REMOTE2_HIGH
,
LM83_REG_W_REMOTE3_HIGH
};
/*
* Functions declaration
*/
static
int
lm83_attach_adapter
(
struct
i2c_adapter
*
adapter
);
static
int
lm83_detect
(
struct
i2c_adapter
*
adapter
,
int
address
,
int
kind
);
static
void
lm83_init_client
(
struct
i2c_client
*
client
);
static
int
lm83_detach_client
(
struct
i2c_client
*
client
);
static
void
lm83_update_client
(
struct
i2c_client
*
client
);
/*
* Driver data (common to all clients)
*/
static
struct
i2c_driver
lm83_driver
=
{
.
owner
=
THIS_MODULE
,
.
name
=
"lm83"
,
.
id
=
I2C_DRIVERID_LM83
,
.
flags
=
I2C_DF_NOTIFY
,
.
attach_adapter
=
lm83_attach_adapter
,
.
detach_client
=
lm83_detach_client
,
};
/*
* Client data (each client gets its own)
*/
struct
lm83_data
{
struct
semaphore
update_lock
;
char
valid
;
/* zero until following fields are valid */
unsigned
long
last_updated
;
/* in jiffies */
/* registers values */
u8
temp_input
[
4
];
u8
temp_high
[
4
];
u8
temp_crit
;
u16
alarms
;
/* bitvector, combined */
};
/*
* Internal variables
*/
static
int
lm83_id
=
0
;
/*
* Sysfs stuff
*/
#define show_temp(suffix, value) \
static ssize_t show_temp_##suffix(struct device *dev, char *buf) \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct lm83_data *data = i2c_get_clientdata(client); \
lm83_update_client(client); \
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \
}
show_temp
(
input1
,
temp_input
[
0
]);
show_temp
(
input2
,
temp_input
[
1
]);
show_temp
(
input3
,
temp_input
[
2
]);
show_temp
(
input4
,
temp_input
[
3
]);
show_temp
(
high1
,
temp_high
[
0
]);
show_temp
(
high2
,
temp_high
[
1
]);
show_temp
(
high3
,
temp_high
[
2
]);
show_temp
(
high4
,
temp_high
[
3
]);
show_temp
(
crit
,
temp_crit
);
#define set_temp(suffix, value, reg) \
static ssize_t set_temp_##suffix(struct device *dev, const char *buf, \
size_t count) \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct lm83_data *data = i2c_get_clientdata(client); \
data->value = TEMP_TO_REG(simple_strtoul(buf, NULL, 10)); \
i2c_smbus_write_byte_data(client, reg, data->value); \
return count; \
}
set_temp
(
high1
,
temp_high
[
0
],
LM83_REG_W_LOCAL_HIGH
);
set_temp
(
high2
,
temp_high
[
1
],
LM83_REG_W_REMOTE1_HIGH
);
set_temp
(
high3
,
temp_high
[
2
],
LM83_REG_W_REMOTE2_HIGH
);
set_temp
(
high4
,
temp_high
[
3
],
LM83_REG_W_REMOTE3_HIGH
);
set_temp
(
crit
,
temp_crit
,
LM83_REG_W_TCRIT
);
static
ssize_t
show_alarms
(
struct
device
*
dev
,
char
*
buf
)
{
struct
i2c_client
*
client
=
to_i2c_client
(
dev
);
struct
lm83_data
*
data
=
i2c_get_clientdata
(
client
);
lm83_update_client
(
client
);
return
sprintf
(
buf
,
"%d
\n
"
,
data
->
alarms
);
}
static
DEVICE_ATTR
(
temp_input1
,
S_IRUGO
,
show_temp_input1
,
NULL
);
static
DEVICE_ATTR
(
temp_input2
,
S_IRUGO
,
show_temp_input2
,
NULL
);
static
DEVICE_ATTR
(
temp_input3
,
S_IRUGO
,
show_temp_input3
,
NULL
);
static
DEVICE_ATTR
(
temp_input4
,
S_IRUGO
,
show_temp_input4
,
NULL
);
static
DEVICE_ATTR
(
temp_max1
,
S_IWUSR
|
S_IRUGO
,
show_temp_high1
,
set_temp_high1
);
static
DEVICE_ATTR
(
temp_max2
,
S_IWUSR
|
S_IRUGO
,
show_temp_high2
,
set_temp_high2
);
static
DEVICE_ATTR
(
temp_max3
,
S_IWUSR
|
S_IRUGO
,
show_temp_high3
,
set_temp_high3
);
static
DEVICE_ATTR
(
temp_max4
,
S_IWUSR
|
S_IRUGO
,
show_temp_high4
,
set_temp_high4
);
static
DEVICE_ATTR
(
temp_crit
,
S_IWUSR
|
S_IRUGO
,
show_temp_crit
,
set_temp_crit
);
static
DEVICE_ATTR
(
alarms
,
S_IRUGO
,
show_alarms
,
NULL
);
/*
* Real code
*/
static
int
lm83_attach_adapter
(
struct
i2c_adapter
*
adapter
)
{
if
(
!
(
adapter
->
class
&
I2C_ADAP_CLASS_SMBUS
))
return
0
;
return
i2c_detect
(
adapter
,
&
addr_data
,
lm83_detect
);
}
/*
* The following function does more than just detection. If detection
* succeeds, it also registers the new chip.
*/
static
int
lm83_detect
(
struct
i2c_adapter
*
adapter
,
int
address
,
int
kind
)
{
struct
i2c_client
*
new_client
;
struct
lm83_data
*
data
;
int
err
=
0
;
const
char
*
name
=
""
;
if
(
!
i2c_check_functionality
(
adapter
,
I2C_FUNC_SMBUS_BYTE_DATA
))
goto
exit
;
if
(
!
(
new_client
=
kmalloc
(
sizeof
(
struct
i2c_client
)
+
sizeof
(
struct
lm83_data
),
GFP_KERNEL
)))
{
err
=
-
ENOMEM
;
goto
exit
;
}
memset
(
new_client
,
0x00
,
sizeof
(
struct
i2c_client
)
+
sizeof
(
struct
lm83_data
));
/* The LM83-specific data is placed right after the common I2C
* client data. */
data
=
(
struct
lm83_data
*
)
(
new_client
+
1
);
i2c_set_clientdata
(
new_client
,
data
);
new_client
->
addr
=
address
;
new_client
->
adapter
=
adapter
;
new_client
->
driver
=
&
lm83_driver
;
new_client
->
flags
=
0
;
/* Now we do the detection and identification. A negative kind
* means that the driver was loaded with no force parameter
* (default), so we must both detect and identify the chip
* (actually there is only one possible kind of chip for now, LM83).
* A zero kind means that the driver was loaded with the force
* parameter, the detection step shall be skipped. A positive kind
* means that the driver was loaded with the force parameter and a
* given kind of chip is requested, so both the detection and the
* identification steps are skipped. */
if
(
kind
<
0
)
{
/* detection */
if
(((
i2c_smbus_read_byte_data
(
new_client
,
LM83_REG_R_STATUS1
)
&
0xA8
)
!=
0x00
)
||
((
i2c_smbus_read_byte_data
(
new_client
,
LM83_REG_R_STATUS2
)
&
0x48
)
!=
0x00
)
||
((
i2c_smbus_read_byte_data
(
new_client
,
LM83_REG_R_CONFIG
)
&
0x41
)
!=
0x00
))
{
dev_dbg
(
&
client
->
dev
,
"LM83 detection failed at 0x%02x.
\n
"
,
address
);
goto
exit_free
;
}
}
if
(
kind
<=
0
)
{
/* identification */
u8
man_id
,
chip_id
;
man_id
=
i2c_smbus_read_byte_data
(
new_client
,
LM83_REG_R_MAN_ID
);
chip_id
=
i2c_smbus_read_byte_data
(
new_client
,
LM83_REG_R_CHIP_ID
);
if
(
man_id
==
0x01
)
{
/* National Semiconductor */
if
(
chip_id
==
0x03
)
{
kind
=
lm83
;
name
=
"lm83"
;
}
}
if
(
kind
<=
0
)
{
/* identification failed */
dev_info
(
&
adapter
->
dev
,
"Unsupported chip (man_id=0x%02X, "
"chip_id=0x%02X).
\n
"
,
man_id
,
chip_id
);
goto
exit_free
;
}
}
/* We can fill in the remaining client fields */
strlcpy
(
new_client
->
name
,
name
,
I2C_NAME_SIZE
);
new_client
->
id
=
lm83_id
++
;
data
->
valid
=
0
;
init_MUTEX
(
&
data
->
update_lock
);
/* Tell the I2C layer a new client has arrived */
if
((
err
=
i2c_attach_client
(
new_client
)))
goto
exit_free
;
/* Initialize the LM83 chip */
lm83_init_client
(
new_client
);
/* Register sysfs hooks */
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_input4
);
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_temp_max4
);
device_create_file
(
&
new_client
->
dev
,
&
dev_attr_temp_crit
);
device_create_file
(
&
new_client
->
dev
,
&
dev_attr_alarms
);
return
0
;
exit_free:
kfree
(
new_client
);
exit:
return
err
;
}
static
void
lm83_init_client
(
struct
i2c_client
*
client
)
{
int
nr
;
for
(
nr
=
0
;
nr
<
4
;
nr
++
)
i2c_smbus_write_byte_data
(
client
,
LM83_REG_W_HIGH
[
nr
],
TEMP_TO_REG
(
LM83_INIT_HIGH
));
i2c_smbus_write_byte_data
(
client
,
LM83_REG_W_TCRIT
,
TEMP_TO_REG
(
LM83_INIT_CRIT
));
}
static
int
lm83_detach_client
(
struct
i2c_client
*
client
)
{
int
err
;
if
((
err
=
i2c_detach_client
(
client
)))
{
dev_err
(
&
client
->
dev
,
"Client deregistration failed, client not detached.
\n
"
);
return
err
;
}
kfree
(
client
);
return
0
;
}
static
void
lm83_update_client
(
struct
i2c_client
*
client
)
{
struct
lm83_data
*
data
=
i2c_get_clientdata
(
client
);
down
(
&
data
->
update_lock
);
if
((
jiffies
-
data
->
last_updated
>
HZ
*
2
)
||
(
jiffies
<
data
->
last_updated
)
||
!
data
->
valid
)
{
int
nr
;
dev_dbg
(
&
client
->
dev
,
"Updating lm83 data.
\n
"
);
for
(
nr
=
0
;
nr
<
4
;
nr
++
)
{
data
->
temp_input
[
nr
]
=
i2c_smbus_read_byte_data
(
client
,
LM83_REG_R_TEMP
[
nr
]);
data
->
temp_high
[
nr
]
=
i2c_smbus_read_byte_data
(
client
,
LM83_REG_R_HIGH
[
nr
]);
}
data
->
temp_crit
=
i2c_smbus_read_byte_data
(
client
,
LM83_REG_R_TCRIT
);
data
->
alarms
=
i2c_smbus_read_byte_data
(
client
,
LM83_REG_R_STATUS1
)
+
(
i2c_smbus_read_byte_data
(
client
,
LM83_REG_R_STATUS2
)
<<
8
);
data
->
last_updated
=
jiffies
;
data
->
valid
=
1
;
}
up
(
&
data
->
update_lock
);
}
static
int
__init
sensors_lm83_init
(
void
)
{
return
i2c_add_driver
(
&
lm83_driver
);
}
static
void
__exit
sensors_lm83_exit
(
void
)
{
i2c_del_driver
(
&
lm83_driver
);
}
MODULE_AUTHOR
(
"Jean Delvare <khali@linux-fr.org>"
);
MODULE_DESCRIPTION
(
"LM83 driver"
);
MODULE_LICENSE
(
"GPL"
);
module_init
(
sensors_lm83_init
);
module_exit
(
sensors_lm83_exit
);
include/linux/i2c-id.h
View file @
7cbfaf48
...
...
@@ -153,6 +153,7 @@
#define I2C_DRIVERID_FS451 1037
#define I2C_DRIVERID_W83627HF 1038
#define I2C_DRIVERID_LM85 1039
#define I2C_DRIVERID_LM83 1040
/*
* ---- Adapter types ----------------------------------------------------
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment