mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 14:30:06 -04:00
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/i2c-2.6
This commit is contained in:
@@ -26,11 +26,8 @@ static unsigned short normal_addr[] = { 0x50, I2C_CLIENT_END };
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_addr,
|
||||
.normal_i2c_range = ignore,
|
||||
.probe = ignore,
|
||||
.probe_range = ignore,
|
||||
.ignore = ignore,
|
||||
.ignore_range = ignore,
|
||||
.force = ignore,
|
||||
};
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ static int i2c_debug=0;
|
||||
/*
|
||||
* Generate a start condition on the i2c bus.
|
||||
*
|
||||
* returns after the start condition has occured
|
||||
* returns after the start condition has occurred
|
||||
*/
|
||||
static void pca_start(struct i2c_algo_pca_data *adap)
|
||||
{
|
||||
@@ -62,9 +62,9 @@ static void pca_start(struct i2c_algo_pca_data *adap)
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a repeated start condition on the i2c bus
|
||||
* Generate a repeated start condition on the i2c bus
|
||||
*
|
||||
* return after the repeated start condition has occured
|
||||
* return after the repeated start condition has occurred
|
||||
*/
|
||||
static void pca_repeated_start(struct i2c_algo_pca_data *adap)
|
||||
{
|
||||
@@ -82,7 +82,7 @@ static void pca_repeated_start(struct i2c_algo_pca_data *adap)
|
||||
* returns after the stop condition has been generated
|
||||
*
|
||||
* STOPs do not generate an interrupt or set the SI flag, since the
|
||||
* part returns the the idle state (0xf8). Hence we don't need to
|
||||
* part returns the idle state (0xf8). Hence we don't need to
|
||||
* pca_wait here.
|
||||
*/
|
||||
static void pca_stop(struct i2c_algo_pca_data *adap)
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
/* Ported for SiByte SOCs by Broadcom Corporation. */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
@@ -7,7 +7,7 @@ menu "I2C Hardware Bus support"
|
||||
|
||||
config I2C_ALI1535
|
||||
tristate "ALI 1535"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the SMB
|
||||
Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB
|
||||
@@ -31,7 +31,7 @@ config I2C_ALI1563
|
||||
|
||||
config I2C_ALI15X3
|
||||
tristate "ALI 15x3"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces.
|
||||
@@ -41,7 +41,7 @@ config I2C_ALI15X3
|
||||
|
||||
config I2C_AMD756
|
||||
tristate "AMD 756/766/768/8111 and nVidia nForce"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the AMD
|
||||
756/766/768 mainboard I2C interfaces. The driver also includes
|
||||
@@ -66,7 +66,7 @@ config I2C_AMD756_S4882
|
||||
|
||||
config I2C_AMD8111
|
||||
tristate "AMD 8111"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
second (SMBus 2.0) AMD 8111 mainboard I2C interface.
|
||||
@@ -109,7 +109,7 @@ config I2C_HYDRA
|
||||
|
||||
config I2C_I801
|
||||
tristate "Intel 82801 (ICH)"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the Intel
|
||||
801 family of mainboard I2C interfaces. Specifically, the following
|
||||
@@ -130,7 +130,7 @@ config I2C_I801
|
||||
|
||||
config I2C_I810
|
||||
tristate "Intel 810/815"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for the Intel
|
||||
@@ -183,7 +183,7 @@ config I2C_IOP3XX
|
||||
|
||||
config I2C_ISA
|
||||
tristate "ISA Bus support"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes to this option, support will be included for i2c
|
||||
interfaces that are on the ISA bus.
|
||||
@@ -248,12 +248,11 @@ config I2C_MPC
|
||||
will be called i2c-mpc.
|
||||
|
||||
config I2C_NFORCE2
|
||||
tristate "Nvidia Nforce2"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
tristate "Nvidia nForce2, nForce3 and nForce4"
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the Nvidia
|
||||
Nforce2 family of mainboard I2C interfaces.
|
||||
This driver also supports the nForce3 Pro 150 MCP.
|
||||
nForce2, nForce3 and nForce4 families of mainboard I2C interfaces.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-nforce2.
|
||||
@@ -305,7 +304,7 @@ config I2C_PARPORT_LIGHT
|
||||
|
||||
config I2C_PROSAVAGE
|
||||
tristate "S3/VIA (Pro)Savage"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
@@ -388,7 +387,7 @@ config SCx200_ACB
|
||||
|
||||
config I2C_SIS5595
|
||||
tristate "SiS 5595"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
SiS5595 SMBus (a subset of I2C) interface.
|
||||
@@ -398,7 +397,7 @@ config I2C_SIS5595
|
||||
|
||||
config I2C_SIS630
|
||||
tristate "SiS 630/730"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
SiS630 and SiS730 SMBus (a subset of I2C) interface.
|
||||
@@ -408,7 +407,7 @@ config I2C_SIS630
|
||||
|
||||
config I2C_SIS96X
|
||||
tristate "SiS 96x"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the SiS
|
||||
96x SMBus (a subset of I2C) interfaces. Specifically, the following
|
||||
@@ -419,6 +418,7 @@ config I2C_SIS96X
|
||||
648/961
|
||||
650/961
|
||||
735
|
||||
745
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-sis96x.
|
||||
@@ -449,7 +449,7 @@ config I2C_VIA
|
||||
|
||||
config I2C_VIAPRO
|
||||
tristate "VIA 82C596/82C686/823x"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
help
|
||||
If you say yes to this option, support will be included for the VIA
|
||||
82C596/82C686/823x I2C interfaces. Specifically, the following
|
||||
@@ -467,7 +467,7 @@ config I2C_VIAPRO
|
||||
|
||||
config I2C_VOODOO3
|
||||
tristate "Voodoo 3"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
|
||||
@@ -53,7 +53,6 @@
|
||||
|
||||
/* Note: we assume there can only be one ALI1535, with one SMBus interface */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
@@ -60,7 +60,6 @@
|
||||
|
||||
/* Note: we assume there can only be one ALI15X3, with one SMBus interface */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
Note: we assume there can only be one device, with one SMBus interface.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
* the Free Software Foundation version 2.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
/* Partialy rewriten by Oleg I. Vdovikin for mmapped support of
|
||||
for Alpha Processor Inc. UP-2000(+) boards */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
|
||||
/* Note: we assume there can only be one I801, with one SMBus interface */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
i815 1132
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
@@ -695,7 +695,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
|
||||
|
||||
dev->irq = iic_force_poll ? -1 : ocp->def->irq;
|
||||
if (dev->irq >= 0){
|
||||
/* Disable interrupts until we finish intialization,
|
||||
/* Disable interrupts until we finish initialization,
|
||||
assumes level-sensitive IRQ setup...
|
||||
*/
|
||||
iic_interrupt_mode(dev, 0);
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#ifndef __I2C_IBM_IIC_H_
|
||||
#define __I2C_IBM_IIC_H_
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
struct iic_regs {
|
||||
|
||||
@@ -85,7 +85,7 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
|
||||
u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE;
|
||||
|
||||
/*
|
||||
* Everytime unit enable is asserted, GPOD needs to be cleared
|
||||
* Every time unit enable is asserted, GPOD needs to be cleared
|
||||
* on IOP321 to avoid data corruption on the bus.
|
||||
*/
|
||||
#ifdef CONFIG_ARCH_IOP321
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
the SMBus and the ISA bus very much easier. See lm78.c for an example
|
||||
of this. */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
/* With some changes from Ky<4B>sti M<>lkki <kmalkki@cc.hut.fi> and even
|
||||
Frodo Looijaard <frodol@dds.nl> */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
@@ -26,11 +26,6 @@
|
||||
* 'enabled' to drive the GPIOs.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#ifdef CONFIG_I2C_DEBUG_BUS
|
||||
#define DEBUG 1
|
||||
#endif
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
@@ -26,11 +26,6 @@
|
||||
* that is passed as the platform_data to this driver.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#ifdef CONFIG_I2C_DEBUG_BUS
|
||||
#define DEBUG 1
|
||||
#endif
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
sound driver to be happy
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ioport.h>
|
||||
|
||||
@@ -325,7 +325,7 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp)
|
||||
if (i2c->irq != OCP_IRQ_NA)
|
||||
{
|
||||
if ((result = request_irq(ocp->def->irq, mpc_i2c_isr,
|
||||
0, "i2c-mpc", i2c)) < 0) {
|
||||
SA_SHIRQ, "i2c-mpc", i2c)) < 0) {
|
||||
printk(KERN_ERR
|
||||
"i2c-mpc - failed to attach interrupt\n");
|
||||
goto fail_irq;
|
||||
@@ -333,6 +333,9 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp)
|
||||
} else
|
||||
i2c->irq = 0;
|
||||
|
||||
mpc_i2c_setclock(i2c);
|
||||
ocp_set_drvdata(ocp, i2c);
|
||||
|
||||
i2c->adap = mpc_ops;
|
||||
i2c_set_adapdata(&i2c->adap, i2c);
|
||||
|
||||
@@ -341,8 +344,6 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp)
|
||||
goto fail_add;
|
||||
}
|
||||
|
||||
mpc_i2c_setclock(i2c);
|
||||
ocp_set_drvdata(ocp, i2c);
|
||||
return result;
|
||||
|
||||
fail_add:
|
||||
@@ -358,8 +359,8 @@ static int __devinit mpc_i2c_probe(struct ocp_device *ocp)
|
||||
static void __devexit mpc_i2c_remove(struct ocp_device *ocp)
|
||||
{
|
||||
struct mpc_i2c *i2c = ocp_get_drvdata(ocp);
|
||||
ocp_set_drvdata(ocp, NULL);
|
||||
i2c_del_adapter(&i2c->adap);
|
||||
ocp_set_drvdata(ocp, NULL);
|
||||
|
||||
if (ocp->def->irq != OCP_IRQ_NA)
|
||||
free_irq(i2c->irq, i2c);
|
||||
@@ -424,12 +425,15 @@ static int fsl_i2c_probe(struct device *device)
|
||||
|
||||
if (i2c->irq != 0)
|
||||
if ((result = request_irq(i2c->irq, mpc_i2c_isr,
|
||||
0, "fsl-i2c", i2c)) < 0) {
|
||||
SA_SHIRQ, "i2c-mpc", i2c)) < 0) {
|
||||
printk(KERN_ERR
|
||||
"i2c-mpc - failed to attach interrupt\n");
|
||||
goto fail_irq;
|
||||
}
|
||||
|
||||
mpc_i2c_setclock(i2c);
|
||||
dev_set_drvdata(device, i2c);
|
||||
|
||||
i2c->adap = mpc_ops;
|
||||
i2c_set_adapdata(&i2c->adap, i2c);
|
||||
i2c->adap.dev.parent = &pdev->dev;
|
||||
@@ -438,8 +442,6 @@ static int fsl_i2c_probe(struct device *device)
|
||||
goto fail_add;
|
||||
}
|
||||
|
||||
mpc_i2c_setclock(i2c);
|
||||
dev_set_drvdata(device, i2c);
|
||||
return result;
|
||||
|
||||
fail_add:
|
||||
@@ -456,8 +458,8 @@ static int fsl_i2c_remove(struct device *device)
|
||||
{
|
||||
struct mpc_i2c *i2c = dev_get_drvdata(device);
|
||||
|
||||
dev_set_drvdata(device, NULL);
|
||||
i2c_del_adapter(&i2c->adap);
|
||||
dev_set_drvdata(device, NULL);
|
||||
|
||||
if (i2c->irq != 0)
|
||||
free_irq(i2c->irq, i2c);
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
|
||||
/* Note: we assume there can only be one nForce2, with two SMBus interfaces */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* ------------------------------------------------------------------------ */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* ------------------------------------------------------------------------ */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
@@ -131,7 +130,7 @@ static int parport_getsda(void *data)
|
||||
/* Encapsulate the functions above in the correct structure.
|
||||
Note that this is only a template, from which the real structures are
|
||||
copied. The attaching code will set getscl to NULL for adapters that
|
||||
cannot read SCL back, and will also make the the data field point to
|
||||
cannot read SCL back, and will also make the data field point to
|
||||
the parallel port structure. */
|
||||
static struct i2c_algo_bit_data parport_algo_data = {
|
||||
.setsda = parport_setsda,
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
Note: we assume there can only be one device, with one SMBus interface.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
* (Additional documentation needed :(
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
* changed to eliminate RPXLite references.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
@@ -533,7 +534,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int
|
||||
/* s3c24xx_i2c_xfer
|
||||
*
|
||||
* first port of call from the i2c bus code when an message needs
|
||||
* transfering across the i2c bus.
|
||||
* transferring across the i2c bus.
|
||||
*/
|
||||
|
||||
static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
it easier to add later.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c-algo-sibyte.h>
|
||||
#include <asm/sibyte/sb1250_regs.h>
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
* Add adapter resets
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
Note: we assume there can only be one device, with one SMBus interface.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
We assume there can only be one SiS96x with one SMBus interface.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#define DEBUG 1
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
Note: we assume there can only be one device, with one SMBus interface.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
/* This interfaces to the I2C bus of the Voodoo3 to gain access to
|
||||
the BT869 and possibly other I2C devices. */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# I2C Sensor device configuration
|
||||
# I2C Sensor and "other" chip configuration
|
||||
#
|
||||
|
||||
menu "Hardware Sensors Chip support"
|
||||
@@ -11,7 +11,7 @@ config I2C_SENSOR
|
||||
|
||||
config SENSORS_ADM1021
|
||||
tristate "Analog Devices ADM1021 and compatibles"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
depends on I2C
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for Analog Devices ADM1021
|
||||
@@ -29,6 +29,7 @@ config SENSORS_ADM1025
|
||||
help
|
||||
If you say yes here you get support for Analog Devices ADM1025
|
||||
and Philips NE1619 sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adm1025.
|
||||
|
||||
@@ -38,6 +39,8 @@ config SENSORS_ADM1026
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for Analog Devices ADM1026
|
||||
sensor chip.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adm1026.
|
||||
|
||||
@@ -48,9 +51,21 @@ config SENSORS_ADM1031
|
||||
help
|
||||
If you say yes here you get support for Analog Devices ADM1031
|
||||
and ADM1030 sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adm1031.
|
||||
|
||||
config SENSORS_ADM9240
|
||||
tristate "Analog Devices ADM9240 and compatibles"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for Analog Devices ADM9240,
|
||||
Dallas DS1780, National Semiconductor LM81 sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adm9240.
|
||||
|
||||
config SENSORS_ASB100
|
||||
tristate "Asus ASB100 Bach"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
@@ -62,6 +77,19 @@ config SENSORS_ASB100
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called asb100.
|
||||
|
||||
config SENSORS_ATXP1
|
||||
tristate "Attansic ATXP1 VID controller"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
help
|
||||
If you say yes here you get support for the Attansic ATXP1 VID
|
||||
controller.
|
||||
|
||||
If your board have such a chip, you are able to control your CPU
|
||||
core and other voltages.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called atxp1.
|
||||
|
||||
config SENSORS_DS1621
|
||||
tristate "Dallas Semiconductor DS1621 and DS1625"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
@@ -97,7 +125,7 @@ config SENSORS_FSCPOS
|
||||
|
||||
config SENSORS_GL518SM
|
||||
tristate "Genesys Logic GL518SM"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
depends on I2C
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for Genesys Logic GL518SM
|
||||
@@ -119,7 +147,7 @@ config SENSORS_GL520SM
|
||||
|
||||
config SENSORS_IT87
|
||||
tristate "ITE IT87xx and compatibles"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
depends on I2C
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for ITE IT87xx sensor chips
|
||||
@@ -143,7 +171,7 @@ config SENSORS_LM63
|
||||
|
||||
config SENSORS_LM75
|
||||
tristate "National Semiconductor LM75 and compatibles"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
depends on I2C
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for National Semiconductor LM75
|
||||
@@ -174,8 +202,7 @@ config SENSORS_LM78
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for National Semiconductor LM78,
|
||||
LM78-J and LM79. This can also be built as a module which can be
|
||||
inserted and removed while the kernel is running.
|
||||
LM78-J and LM79.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called lm78.
|
||||
@@ -208,7 +235,7 @@ config SENSORS_LM85
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for National Semiconductor LM85
|
||||
sensor chips and clones: ADT7463 and ADM1027.
|
||||
sensor chips and clones: ADT7463, EMC6D100, EMC6D102 and ADM1027.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called lm85.
|
||||
@@ -307,14 +334,14 @@ config SENSORS_SMSC47M1
|
||||
help
|
||||
If you say yes here you get support for the integrated fan
|
||||
monitoring and control capabilities of the SMSC LPC47B27x,
|
||||
LPC47M10x, LPC47M13x and LPC47M14x chips.
|
||||
LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192 chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called smsc47m1.
|
||||
|
||||
config SENSORS_VIA686A
|
||||
tristate "VIA686A"
|
||||
depends on I2C && PCI && EXPERIMENTAL
|
||||
depends on I2C && PCI
|
||||
select I2C_SENSOR
|
||||
select I2C_ISA
|
||||
help
|
||||
@@ -326,7 +353,7 @@ config SENSORS_VIA686A
|
||||
|
||||
config SENSORS_W83781D
|
||||
tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
depends on I2C
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for the Winbond W8378x series
|
||||
@@ -360,22 +387,47 @@ config SENSORS_W83627HF
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called w83627hf.
|
||||
|
||||
config SENSORS_W83627EHF
|
||||
tristate "Winbond W83627EHF"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
select I2C_SENSOR
|
||||
select I2C_ISA
|
||||
help
|
||||
If you say yes here you get preliminary support for the hardware
|
||||
monitoring functionality of the Winbond W83627EHF Super-I/O chip.
|
||||
Only fan and temperature inputs are supported at the moment, while
|
||||
the chip does much more than that.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called w83627ehf.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Other I2C Chip support"
|
||||
depends on I2C
|
||||
|
||||
config SENSORS_DS1337
|
||||
tristate "Dallas Semiconductor DS1337 Real Time Clock"
|
||||
tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for Dallas Semiconductor
|
||||
DS1337 real-time clock chips.
|
||||
DS1337 and DS1339 real-time clock chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ds1337.
|
||||
|
||||
config SENSORS_DS1374
|
||||
tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
select I2C_SENSOR
|
||||
help
|
||||
If you say yes here you get support for Dallas Semiconductor
|
||||
DS1374 real-time clock chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ds1374.
|
||||
|
||||
config SENSORS_EEPROM
|
||||
tristate "EEPROM reader"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
@@ -399,6 +451,16 @@ config SENSORS_PCF8574
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called pcf8574.
|
||||
|
||||
config SENSORS_PCA9539
|
||||
tristate "Philips PCA9539 16-bit I/O port"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
help
|
||||
If you say yes here you get support for the Philips PCA9539
|
||||
16-bit I/O port.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called pca9539.
|
||||
|
||||
config SENSORS_PCF8591
|
||||
tristate "Philips PCF8591"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
@@ -431,6 +493,23 @@ config ISP1301_OMAP
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called isp1301_omap.
|
||||
|
||||
# NOTE: This isn't really OMAP-specific, except for the current
|
||||
# interface location in <include/asm-arm/arch-omap/tps65010.h>
|
||||
# and having mostly OMAP-specific board support
|
||||
config TPS65010
|
||||
tristate "TPS6501x Power Management chips"
|
||||
depends on I2C && ARCH_OMAP
|
||||
default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
|
||||
help
|
||||
If you say yes here you get support for the TPS6501x series of
|
||||
Power Management chips. These include voltage regulators,
|
||||
lithium ion/polymer battery charging, and other features that
|
||||
are often used in portable devices like cell phones and cameras.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tps65010.
|
||||
|
||||
|
||||
config SENSORS_M41T00
|
||||
tristate "ST M41T00 RTC chip"
|
||||
depends on I2C && PPC32
|
||||
@@ -440,4 +519,16 @@ config SENSORS_M41T00
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called m41t00.
|
||||
|
||||
config SENSORS_MAX6875
|
||||
tristate "MAXIM MAX6875 Power supply supervisor"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
help
|
||||
If you say yes here you get support for the MAX6875
|
||||
EEPROM-Programmable, Hex/Quad, Power-Suppy Sequencers/Supervisors.
|
||||
|
||||
This provides a interface to program the EEPROM and reset the chip.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max6875.
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Makefile for the kernel hardware sensors chip drivers.
|
||||
# Makefile for sensor and "other" I2C chip drivers.
|
||||
#
|
||||
|
||||
# asb100, then w83781d go first, as they can override other drivers' addresses.
|
||||
@@ -11,7 +11,10 @@ obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
|
||||
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
|
||||
obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
|
||||
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
|
||||
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
|
||||
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
|
||||
obj-$(CONFIG_SENSORS_DS1337) += ds1337.o
|
||||
obj-$(CONFIG_SENSORS_DS1374) += ds1374.o
|
||||
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
|
||||
obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o
|
||||
obj-$(CONFIG_SENSORS_FSCHER) += fscher.o
|
||||
@@ -30,8 +33,10 @@ obj-$(CONFIG_SENSORS_LM87) += lm87.o
|
||||
obj-$(CONFIG_SENSORS_LM90) += lm90.o
|
||||
obj-$(CONFIG_SENSORS_LM92) += lm92.o
|
||||
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
|
||||
obj-$(CONFIG_SENSORS_MAX6875) += max6875.o
|
||||
obj-$(CONFIG_SENSORS_M41T00) += m41t00.o
|
||||
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
|
||||
obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o
|
||||
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
|
||||
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
|
||||
obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o
|
||||
@@ -39,8 +44,11 @@ obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
|
||||
obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
|
||||
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
|
||||
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
|
||||
obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o
|
||||
obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
|
||||
|
||||
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
|
||||
obj-$(CONFIG_TPS65010) += tps65010.o
|
||||
|
||||
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -103,8 +102,6 @@ struct adm1021_data {
|
||||
u8 remote_temp_hyst;
|
||||
u8 remote_temp_input;
|
||||
u8 alarms;
|
||||
/* special values for ADM1021 only */
|
||||
u8 die_code;
|
||||
/* Special values for ADM1023 only */
|
||||
u8 remote_temp_prec;
|
||||
u8 remote_temp_os_prec;
|
||||
@@ -156,7 +153,6 @@ static ssize_t show_##value(struct device *dev, struct device_attribute *attr, c
|
||||
return sprintf(buf, "%d\n", data->value); \
|
||||
}
|
||||
show2(alarms);
|
||||
show2(die_code);
|
||||
|
||||
#define set(value, reg) \
|
||||
static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
|
||||
@@ -183,7 +179,6 @@ static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remot
|
||||
static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst);
|
||||
static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL);
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
static DEVICE_ATTR(die_code, S_IRUGO, show_die_code, NULL);
|
||||
|
||||
|
||||
static int adm1021_attach_adapter(struct i2c_adapter *adapter)
|
||||
@@ -307,8 +302,6 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
if (data->type == adm1021)
|
||||
device_create_file(&new_client->dev, &dev_attr_die_code);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -371,8 +364,6 @@ static struct adm1021_data *adm1021_update_device(struct device *dev)
|
||||
data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R);
|
||||
data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R);
|
||||
data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c;
|
||||
if (data->type == adm1021)
|
||||
data->die_code = adm1021_read_value(client, ADM1021_REG_DIE_CODE);
|
||||
if (data->type == adm1023) {
|
||||
data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC);
|
||||
data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC);
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -287,7 +286,9 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char
|
||||
struct adm1025_data *data = adm1025_update_device(dev);
|
||||
return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
|
||||
}
|
||||
/* in1_ref is deprecated in favour of cpu0_vid, remove after 2005-11-11 */
|
||||
static DEVICE_ATTR(in1_ref, S_IRUGO, show_vid, NULL);
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
|
||||
|
||||
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -437,7 +438,9 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
/* in1_ref is deprecated, remove after 2005-11-11 */
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_ref);
|
||||
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
|
||||
device_create_file(&new_client->dev, &dev_attr_vrm);
|
||||
|
||||
/* Pin 11 is either in4 (+12V) or VID4 */
|
||||
|
||||
@@ -23,15 +23,14 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
#include <linux/i2c-sysfs.h>
|
||||
#include <linux/i2c-vid.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
|
||||
@@ -1225,8 +1224,9 @@ static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, c
|
||||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
return sprintf(buf,"%d\n", vid_from_reg(data->vid & 0x3f, data->vrm));
|
||||
}
|
||||
|
||||
/* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */
|
||||
static DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL);
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
|
||||
|
||||
static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -1666,7 +1666,9 @@ int adm1026_detect(struct i2c_adapter *adapter, int address,
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable);
|
||||
/* vid deprecated in favour of cpu0_vid, remove after 2005-11-11 */
|
||||
device_create_file(&new_client->dev, &dev_attr_vid);
|
||||
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
|
||||
device_create_file(&new_client->dev, &dev_attr_vrm);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarm_mask);
|
||||
|
||||
@@ -440,7 +440,7 @@ pwm_reg(2);
|
||||
|
||||
/*
|
||||
* That function checks the cases where the fan reading is not
|
||||
* relevent. It is used to provide 0 as fan reading when the fan is
|
||||
* relevant. It is used to provide 0 as fan reading when the fan is
|
||||
* not supposed to run
|
||||
*/
|
||||
static int trust_fan_readings(struct adm1031_data *data, int chan)
|
||||
|
||||
791
drivers/i2c/chips/adm9240.c
Normal file
791
drivers/i2c/chips/adm9240.c
Normal file
@@ -0,0 +1,791 @@
|
||||
/*
|
||||
* adm9240.c Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
*
|
||||
* Copyright (C) 1999 Frodo Looijaard <frodol@dds.nl>
|
||||
* Philip Edelbrock <phil@netroedge.com>
|
||||
* Copyright (C) 2003 Michiel Rook <michiel@grendelproject.nl>
|
||||
* Copyright (C) 2005 Grant Coady <gcoady@gmail.com> with valuable
|
||||
* guidance from Jean Delvare
|
||||
*
|
||||
* Driver supports Analog Devices ADM9240
|
||||
* Dallas Semiconductor DS1780
|
||||
* National Semiconductor LM81
|
||||
*
|
||||
* ADM9240 is the reference, DS1780 and LM81 are register compatibles
|
||||
*
|
||||
* Voltage Six inputs are scaled by chip, VID also reported
|
||||
* Temperature Chip temperature to 0.5'C, maximum and max_hysteris
|
||||
* Fans 2 fans, low speed alarm, automatic fan clock divider
|
||||
* Alarms 16-bit map of active alarms
|
||||
* Analog Out 0..1250 mV output
|
||||
*
|
||||
* Chassis Intrusion: clear CI latch with 'echo 1 > chassis_clear'
|
||||
*
|
||||
* Test hardware: Intel SE440BX-2 desktop motherboard --Grant
|
||||
*
|
||||
* LM81 extended temp reading not implemented
|
||||
*
|
||||
* 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/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
#include <linux/i2c-vid.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
I2C_CLIENT_END };
|
||||
|
||||
static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
|
||||
|
||||
/* Insmod parameters */
|
||||
SENSORS_INSMOD_3(adm9240, ds1780, lm81);
|
||||
|
||||
/* ADM9240 registers */
|
||||
#define ADM9240_REG_MAN_ID 0x3e
|
||||
#define ADM9240_REG_DIE_REV 0x3f
|
||||
#define ADM9240_REG_CONFIG 0x40
|
||||
|
||||
#define ADM9240_REG_IN(nr) (0x20 + (nr)) /* 0..5 */
|
||||
#define ADM9240_REG_IN_MAX(nr) (0x2b + (nr) * 2)
|
||||
#define ADM9240_REG_IN_MIN(nr) (0x2c + (nr) * 2)
|
||||
#define ADM9240_REG_FAN(nr) (0x28 + (nr)) /* 0..1 */
|
||||
#define ADM9240_REG_FAN_MIN(nr) (0x3b + (nr))
|
||||
#define ADM9240_REG_INT(nr) (0x41 + (nr))
|
||||
#define ADM9240_REG_INT_MASK(nr) (0x43 + (nr))
|
||||
#define ADM9240_REG_TEMP 0x27
|
||||
#define ADM9240_REG_TEMP_HIGH 0x39
|
||||
#define ADM9240_REG_TEMP_HYST 0x3a
|
||||
#define ADM9240_REG_ANALOG_OUT 0x19
|
||||
#define ADM9240_REG_CHASSIS_CLEAR 0x46
|
||||
#define ADM9240_REG_VID_FAN_DIV 0x47
|
||||
#define ADM9240_REG_I2C_ADDR 0x48
|
||||
#define ADM9240_REG_VID4 0x49
|
||||
#define ADM9240_REG_TEMP_CONF 0x4b
|
||||
|
||||
/* generalised scaling with integer rounding */
|
||||
static inline int SCALE(long val, int mul, int div)
|
||||
{
|
||||
if (val < 0)
|
||||
return (val * mul - div / 2) / div;
|
||||
else
|
||||
return (val * mul + div / 2) / div;
|
||||
}
|
||||
|
||||
/* adm9240 internally scales voltage measurements */
|
||||
static const u16 nom_mv[] = { 2500, 2700, 3300, 5000, 12000, 2700 };
|
||||
|
||||
static inline unsigned int IN_FROM_REG(u8 reg, int n)
|
||||
{
|
||||
return SCALE(reg, nom_mv[n], 192);
|
||||
}
|
||||
|
||||
static inline u8 IN_TO_REG(unsigned long val, int n)
|
||||
{
|
||||
return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255);
|
||||
}
|
||||
|
||||
/* temperature range: -40..125, 127 disables temperature alarm */
|
||||
static inline s8 TEMP_TO_REG(long val)
|
||||
{
|
||||
return SENSORS_LIMIT(SCALE(val, 1, 1000), -40, 127);
|
||||
}
|
||||
|
||||
/* two fans, each with low fan speed limit */
|
||||
static inline unsigned int FAN_FROM_REG(u8 reg, u8 div)
|
||||
{
|
||||
if (!reg) /* error */
|
||||
return -1;
|
||||
|
||||
if (reg == 255)
|
||||
return 0;
|
||||
|
||||
return SCALE(1350000, 1, reg * div);
|
||||
}
|
||||
|
||||
/* analog out 0..1250mV */
|
||||
static inline u8 AOUT_TO_REG(unsigned long val)
|
||||
{
|
||||
return SENSORS_LIMIT(SCALE(val, 255, 1250), 0, 255);
|
||||
}
|
||||
|
||||
static inline unsigned int AOUT_FROM_REG(u8 reg)
|
||||
{
|
||||
return SCALE(reg, 1250, 255);
|
||||
}
|
||||
|
||||
static int adm9240_attach_adapter(struct i2c_adapter *adapter);
|
||||
static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind);
|
||||
static void adm9240_init_client(struct i2c_client *client);
|
||||
static int adm9240_detach_client(struct i2c_client *client);
|
||||
static struct adm9240_data *adm9240_update_device(struct device *dev);
|
||||
|
||||
/* driver data */
|
||||
static struct i2c_driver adm9240_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "adm9240",
|
||||
.id = I2C_DRIVERID_ADM9240,
|
||||
.flags = I2C_DF_NOTIFY,
|
||||
.attach_adapter = adm9240_attach_adapter,
|
||||
.detach_client = adm9240_detach_client,
|
||||
};
|
||||
|
||||
/* per client data */
|
||||
struct adm9240_data {
|
||||
enum chips type;
|
||||
struct i2c_client client;
|
||||
struct semaphore update_lock;
|
||||
char valid;
|
||||
unsigned long last_updated_measure;
|
||||
unsigned long last_updated_config;
|
||||
|
||||
u8 in[6]; /* ro in0_input */
|
||||
u8 in_max[6]; /* rw in0_max */
|
||||
u8 in_min[6]; /* rw in0_min */
|
||||
u8 fan[2]; /* ro fan1_input */
|
||||
u8 fan_min[2]; /* rw fan1_min */
|
||||
u8 fan_div[2]; /* rw fan1_div, read-only accessor */
|
||||
s16 temp; /* ro temp1_input, 9-bit sign-extended */
|
||||
s8 temp_high; /* rw temp1_max */
|
||||
s8 temp_hyst; /* rw temp1_max_hyst */
|
||||
u16 alarms; /* ro alarms */
|
||||
u8 aout; /* rw aout_output */
|
||||
u8 vid; /* ro vid */
|
||||
u8 vrm; /* -- vrm set on startup, no accessor */
|
||||
};
|
||||
|
||||
/* i2c byte read/write interface */
|
||||
static int adm9240_read_value(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
/*** sysfs accessors ***/
|
||||
|
||||
/* temperature */
|
||||
#define show_temp(value, scale) \
|
||||
static ssize_t show_##value(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct adm9240_data *data = adm9240_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", data->value * scale); \
|
||||
}
|
||||
show_temp(temp_high, 1000);
|
||||
show_temp(temp_hyst, 1000);
|
||||
show_temp(temp, 500); /* 0.5'C per bit */
|
||||
|
||||
#define set_temp(value, reg) \
|
||||
static ssize_t set_##value(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct adm9240_data *data = adm9240_update_device(dev); \
|
||||
long temp = simple_strtoul(buf, NULL, 10); \
|
||||
\
|
||||
down(&data->update_lock); \
|
||||
data->value = TEMP_TO_REG(temp); \
|
||||
adm9240_write_value(client, reg, data->value); \
|
||||
up(&data->update_lock); \
|
||||
return count; \
|
||||
}
|
||||
|
||||
set_temp(temp_high, ADM9240_REG_TEMP_HIGH);
|
||||
set_temp(temp_hyst, ADM9240_REG_TEMP_HYST);
|
||||
|
||||
static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
|
||||
show_temp_high, set_temp_high);
|
||||
static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
|
||||
show_temp_hyst, set_temp_hyst);
|
||||
static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
|
||||
|
||||
/* voltage */
|
||||
static ssize_t show_in(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr));
|
||||
}
|
||||
|
||||
static ssize_t show_in_min(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr));
|
||||
}
|
||||
|
||||
static ssize_t show_in_max(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], 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 adm9240_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
down(&data->update_lock);
|
||||
data->in_min[nr] = IN_TO_REG(val, nr);
|
||||
adm9240_write_value(client, ADM9240_REG_IN_MIN(nr), data->in_min[nr]);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
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 adm9240_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
down(&data->update_lock);
|
||||
data->in_max[nr] = IN_TO_REG(val, nr);
|
||||
adm9240_write_value(client, ADM9240_REG_IN_MAX(nr), data->in_max[nr]);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
#define show_in_offset(offset) \
|
||||
static ssize_t show_in##offset(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_in(dev, buf, offset); \
|
||||
} \
|
||||
static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); \
|
||||
static ssize_t show_in##offset##_min(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_in_min(dev, buf, offset); \
|
||||
} \
|
||||
static ssize_t show_in##offset##_max(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_in_max(dev, buf, offset); \
|
||||
} \
|
||||
static ssize_t \
|
||||
set_in##offset##_min(struct device *dev, \
|
||||
struct device_attribute *attr, const char *buf, \
|
||||
size_t count) \
|
||||
{ \
|
||||
return set_in_min(dev, buf, count, offset); \
|
||||
} \
|
||||
static ssize_t \
|
||||
set_in##offset##_max(struct device *dev, \
|
||||
struct device_attribute *attr, const char *buf, \
|
||||
size_t count) \
|
||||
{ \
|
||||
return set_in_max(dev, buf, count, offset); \
|
||||
} \
|
||||
static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_in##offset##_min, set_in##offset##_min); \
|
||||
static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
|
||||
show_in##offset##_max, set_in##offset##_max);
|
||||
|
||||
show_in_offset(0);
|
||||
show_in_offset(1);
|
||||
show_in_offset(2);
|
||||
show_in_offset(3);
|
||||
show_in_offset(4);
|
||||
show_in_offset(5);
|
||||
|
||||
/* fans */
|
||||
static ssize_t show_fan(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
|
||||
1 << data->fan_div[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
|
||||
1 << data->fan_div[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%d\n", 1 << data->fan_div[nr]);
|
||||
}
|
||||
|
||||
/* write new fan div, callers must hold data->update_lock */
|
||||
static void adm9240_write_fan_div(struct i2c_client *client, int nr,
|
||||
u8 fan_div)
|
||||
{
|
||||
u8 reg, old, shift = (nr + 2) * 2;
|
||||
|
||||
reg = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV);
|
||||
old = (reg >> shift) & 3;
|
||||
reg &= ~(3 << shift);
|
||||
reg |= (fan_div << shift);
|
||||
adm9240_write_value(client, ADM9240_REG_VID_FAN_DIV, reg);
|
||||
dev_dbg(&client->dev, "fan%d clock divider changed from %u "
|
||||
"to %u\n", nr + 1, 1 << old, 1 << fan_div);
|
||||
}
|
||||
|
||||
/*
|
||||
* set fan speed low limit:
|
||||
*
|
||||
* - value is zero: disable fan speed low limit alarm
|
||||
*
|
||||
* - value is below fan speed measurement range: enable fan speed low
|
||||
* limit alarm to be asserted while fan speed too slow to measure
|
||||
*
|
||||
* - otherwise: select fan clock divider to suit fan speed low limit,
|
||||
* measurement code may adjust registers to ensure fan speed reading
|
||||
*/
|
||||
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 adm9240_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
u8 new_div;
|
||||
|
||||
down(&data->update_lock);
|
||||
|
||||
if (!val) {
|
||||
data->fan_min[nr] = 255;
|
||||
new_div = data->fan_div[nr];
|
||||
|
||||
dev_dbg(&client->dev, "fan%u low limit set disabled\n",
|
||||
nr + 1);
|
||||
|
||||
} else if (val < 1350000 / (8 * 254)) {
|
||||
new_div = 3;
|
||||
data->fan_min[nr] = 254;
|
||||
|
||||
dev_dbg(&client->dev, "fan%u low limit set minimum %u\n",
|
||||
nr + 1, FAN_FROM_REG(254, 1 << new_div));
|
||||
|
||||
} else {
|
||||
unsigned int new_min = 1350000 / val;
|
||||
|
||||
new_div = 0;
|
||||
while (new_min > 192 && new_div < 3) {
|
||||
new_div++;
|
||||
new_min /= 2;
|
||||
}
|
||||
if (!new_min) /* keep > 0 */
|
||||
new_min++;
|
||||
|
||||
data->fan_min[nr] = new_min;
|
||||
|
||||
dev_dbg(&client->dev, "fan%u low limit set fan speed %u\n",
|
||||
nr + 1, FAN_FROM_REG(new_min, 1 << new_div));
|
||||
}
|
||||
|
||||
if (new_div != data->fan_div[nr]) {
|
||||
data->fan_div[nr] = new_div;
|
||||
adm9240_write_fan_div(client, nr, new_div);
|
||||
}
|
||||
adm9240_write_value(client, ADM9240_REG_FAN_MIN(nr),
|
||||
data->fan_min[nr]);
|
||||
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
#define show_fan_offset(offset) \
|
||||
static ssize_t show_fan_##offset (struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_fan(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t show_fan_##offset##_div (struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_fan_div(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t show_fan_##offset##_min (struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_fan_min(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t set_fan_##offset##_min (struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_fan_min(dev, buf, count, offset - 1); \
|
||||
} \
|
||||
static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
|
||||
show_fan_##offset, NULL); \
|
||||
static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
|
||||
show_fan_##offset##_div, NULL); \
|
||||
static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_fan_##offset##_min, set_fan_##offset##_min);
|
||||
|
||||
show_fan_offset(1);
|
||||
show_fan_offset(2);
|
||||
|
||||
/* alarms */
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
/* vid */
|
||||
static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
|
||||
}
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
|
||||
|
||||
/* analog output */
|
||||
static ssize_t show_aout(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct adm9240_data *data = adm9240_update_device(dev);
|
||||
return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout));
|
||||
}
|
||||
|
||||
static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtol(buf, NULL, 10);
|
||||
|
||||
down(&data->update_lock);
|
||||
data->aout = AOUT_TO_REG(val);
|
||||
adm9240_write_value(client, ADM9240_REG_ANALOG_OUT, data->aout);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
|
||||
|
||||
/* chassis_clear */
|
||||
static ssize_t chassis_clear(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
unsigned long val = simple_strtol(buf, NULL, 10);
|
||||
|
||||
if (val == 1) {
|
||||
adm9240_write_value(client, ADM9240_REG_CHASSIS_CLEAR, 0x80);
|
||||
dev_dbg(&client->dev, "chassis intrusion latch cleared\n");
|
||||
}
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear);
|
||||
|
||||
|
||||
/*** sensor chip detect and driver install ***/
|
||||
|
||||
static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
struct i2c_client *new_client;
|
||||
struct adm9240_data *data;
|
||||
int err = 0;
|
||||
const char *name = "";
|
||||
u8 man_id, die_rev;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
goto exit;
|
||||
|
||||
if (!(data = kmalloc(sizeof(struct adm9240_data), GFP_KERNEL))) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
memset(data, 0, sizeof(struct adm9240_data));
|
||||
|
||||
new_client = &data->client;
|
||||
i2c_set_clientdata(new_client, data);
|
||||
new_client->addr = address;
|
||||
new_client->adapter = adapter;
|
||||
new_client->driver = &adm9240_driver;
|
||||
new_client->flags = 0;
|
||||
|
||||
if (kind == 0) {
|
||||
kind = adm9240;
|
||||
}
|
||||
|
||||
if (kind < 0) {
|
||||
|
||||
/* verify chip: reg address should match i2c address */
|
||||
if (adm9240_read_value(new_client, ADM9240_REG_I2C_ADDR)
|
||||
!= address) {
|
||||
dev_err(&adapter->dev, "detect fail: address match, "
|
||||
"0x%02x\n", address);
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
/* check known chip manufacturer */
|
||||
man_id = adm9240_read_value(new_client, ADM9240_REG_MAN_ID);
|
||||
|
||||
if (man_id == 0x23) {
|
||||
kind = adm9240;
|
||||
} else if (man_id == 0xda) {
|
||||
kind = ds1780;
|
||||
} else if (man_id == 0x01) {
|
||||
kind = lm81;
|
||||
} else {
|
||||
dev_err(&adapter->dev, "detect fail: unknown manuf, "
|
||||
"0x%02x\n", man_id);
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
/* successful detect, print chip info */
|
||||
die_rev = adm9240_read_value(new_client, ADM9240_REG_DIE_REV);
|
||||
dev_info(&adapter->dev, "found %s revision %u\n",
|
||||
man_id == 0x23 ? "ADM9240" :
|
||||
man_id == 0xda ? "DS1780" : "LM81", die_rev);
|
||||
}
|
||||
|
||||
/* either forced or detected chip kind */
|
||||
if (kind == adm9240) {
|
||||
name = "adm9240";
|
||||
} else if (kind == ds1780) {
|
||||
name = "ds1780";
|
||||
} else if (kind == lm81) {
|
||||
name = "lm81";
|
||||
}
|
||||
|
||||
/* fill in the remaining client fields and attach */
|
||||
strlcpy(new_client->name, name, I2C_NAME_SIZE);
|
||||
data->type = kind;
|
||||
init_MUTEX(&data->update_lock);
|
||||
|
||||
if ((err = i2c_attach_client(new_client)))
|
||||
goto exit_free;
|
||||
|
||||
adm9240_init_client(new_client);
|
||||
|
||||
/* populate sysfs filesystem */
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
device_create_file(&new_client->dev, &dev_attr_aout_output);
|
||||
device_create_file(&new_client->dev, &dev_attr_chassis_clear);
|
||||
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
|
||||
|
||||
return 0;
|
||||
exit_free:
|
||||
kfree(new_client);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adm9240_attach_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
||||
return 0;
|
||||
return i2c_detect(adapter, &addr_data, adm9240_detect);
|
||||
}
|
||||
|
||||
static int adm9240_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(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adm9240_init_client(struct i2c_client *client)
|
||||
{
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
u8 conf = adm9240_read_value(client, ADM9240_REG_CONFIG);
|
||||
u8 mode = adm9240_read_value(client, ADM9240_REG_TEMP_CONF) & 3;
|
||||
|
||||
data->vrm = i2c_which_vrm(); /* need this to report vid as mV */
|
||||
|
||||
dev_info(&client->dev, "Using VRM: %d.%d\n", data->vrm / 10,
|
||||
data->vrm % 10);
|
||||
|
||||
if (conf & 1) { /* measurement cycle running: report state */
|
||||
|
||||
dev_info(&client->dev, "status: config 0x%02x mode %u\n",
|
||||
conf, mode);
|
||||
|
||||
} else { /* cold start: open limits before starting chip */
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
adm9240_write_value(client,
|
||||
ADM9240_REG_IN_MIN(i), 0);
|
||||
adm9240_write_value(client,
|
||||
ADM9240_REG_IN_MAX(i), 255);
|
||||
}
|
||||
adm9240_write_value(client, ADM9240_REG_FAN_MIN(0), 255);
|
||||
adm9240_write_value(client, ADM9240_REG_FAN_MIN(1), 255);
|
||||
adm9240_write_value(client, ADM9240_REG_TEMP_HIGH, 127);
|
||||
adm9240_write_value(client, ADM9240_REG_TEMP_HYST, 127);
|
||||
|
||||
/* start measurement cycle */
|
||||
adm9240_write_value(client, ADM9240_REG_CONFIG, 1);
|
||||
|
||||
dev_info(&client->dev, "cold start: config was 0x%02x "
|
||||
"mode %u\n", conf, mode);
|
||||
}
|
||||
}
|
||||
|
||||
static struct adm9240_data *adm9240_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||
int i;
|
||||
|
||||
down(&data->update_lock);
|
||||
|
||||
/* minimum measurement cycle: 1.75 seconds */
|
||||
if (time_after(jiffies, data->last_updated_measure + (HZ * 7 / 4))
|
||||
|| !data->valid) {
|
||||
|
||||
for (i = 0; i < 6; i++) /* read voltages */
|
||||
{
|
||||
data->in[i] = adm9240_read_value(client,
|
||||
ADM9240_REG_IN(i));
|
||||
}
|
||||
data->alarms = adm9240_read_value(client,
|
||||
ADM9240_REG_INT(0)) |
|
||||
adm9240_read_value(client,
|
||||
ADM9240_REG_INT(1)) << 8;
|
||||
|
||||
/* read temperature: assume temperature changes less than
|
||||
* 0.5'C per two measurement cycles thus ignore possible
|
||||
* but unlikely aliasing error on lsb reading. --Grant */
|
||||
data->temp = ((adm9240_read_value(client,
|
||||
ADM9240_REG_TEMP) << 8) |
|
||||
adm9240_read_value(client,
|
||||
ADM9240_REG_TEMP_CONF)) / 128;
|
||||
|
||||
for (i = 0; i < 2; i++) /* read fans */
|
||||
{
|
||||
data->fan[i] = adm9240_read_value(client,
|
||||
ADM9240_REG_FAN(i));
|
||||
|
||||
/* adjust fan clock divider on overflow */
|
||||
if (data->valid && data->fan[i] == 255 &&
|
||||
data->fan_div[i] < 3) {
|
||||
|
||||
adm9240_write_fan_div(client, i,
|
||||
++data->fan_div[i]);
|
||||
|
||||
/* adjust fan_min if active, but not to 0 */
|
||||
if (data->fan_min[i] < 255 &&
|
||||
data->fan_min[i] >= 2)
|
||||
data->fan_min[i] /= 2;
|
||||
}
|
||||
}
|
||||
data->last_updated_measure = jiffies;
|
||||
}
|
||||
|
||||
/* minimum config reading cycle: 300 seconds */
|
||||
if (time_after(jiffies, data->last_updated_config + (HZ * 300))
|
||||
|| !data->valid) {
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
data->in_min[i] = adm9240_read_value(client,
|
||||
ADM9240_REG_IN_MIN(i));
|
||||
data->in_max[i] = adm9240_read_value(client,
|
||||
ADM9240_REG_IN_MAX(i));
|
||||
}
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
data->fan_min[i] = adm9240_read_value(client,
|
||||
ADM9240_REG_FAN_MIN(i));
|
||||
}
|
||||
data->temp_high = adm9240_read_value(client,
|
||||
ADM9240_REG_TEMP_HIGH);
|
||||
data->temp_hyst = adm9240_read_value(client,
|
||||
ADM9240_REG_TEMP_HYST);
|
||||
|
||||
/* read fan divs and 5-bit VID */
|
||||
i = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV);
|
||||
data->fan_div[0] = (i >> 4) & 3;
|
||||
data->fan_div[1] = (i >> 6) & 3;
|
||||
data->vid = i & 0x0f;
|
||||
data->vid |= (adm9240_read_value(client,
|
||||
ADM9240_REG_VID4) & 1) << 4;
|
||||
/* read analog out */
|
||||
data->aout = adm9240_read_value(client,
|
||||
ADM9240_REG_ANALOG_OUT);
|
||||
|
||||
data->last_updated_config = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
up(&data->update_lock);
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init sensors_adm9240_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adm9240_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_adm9240_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adm9240_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Michiel Rook <michiel@grendelproject.nl>, "
|
||||
"Grant Coady <gcoady@gmail.com> and others");
|
||||
MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_adm9240_init);
|
||||
module_exit(sensors_adm9240_exit);
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <linux/i2c-sensor.h>
|
||||
#include <linux/i2c-vid.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include "lm75.h"
|
||||
|
||||
/*
|
||||
@@ -168,8 +169,6 @@ static int ASB100_PWM_FROM_REG(u8 reg)
|
||||
return reg * 16;
|
||||
}
|
||||
|
||||
#define ALARMS_FROM_REG(val) (val)
|
||||
|
||||
#define DIV_FROM_REG(val) (1 << (val))
|
||||
|
||||
/* FAN DIV: 1, 2, 4, or 8 (defaults to 2)
|
||||
@@ -556,7 +555,7 @@ device_create_file(&client->dev, &dev_attr_vrm);
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct asb100_data *data = asb100_update_device(dev);
|
||||
return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms));
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
361
drivers/i2c/chips/atxp1.c
Normal file
361
drivers/i2c/chips/atxp1.c
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
atxp1.c - kernel module for setting CPU VID and general purpose
|
||||
I/Os using the Attansic ATXP1 chip.
|
||||
|
||||
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/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
#include <linux/i2c-vid.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
|
||||
MODULE_VERSION("0.6.2");
|
||||
MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
|
||||
|
||||
#define ATXP1_VID 0x00
|
||||
#define ATXP1_CVID 0x01
|
||||
#define ATXP1_GPIO1 0x06
|
||||
#define ATXP1_GPIO2 0x0a
|
||||
#define ATXP1_VIDENA 0x20
|
||||
#define ATXP1_VIDMASK 0x1f
|
||||
#define ATXP1_GPIO1MASK 0x0f
|
||||
|
||||
static unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END };
|
||||
static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
|
||||
|
||||
SENSORS_INSMOD_1(atxp1);
|
||||
|
||||
static int atxp1_attach_adapter(struct i2c_adapter * adapter);
|
||||
static int atxp1_detach_client(struct i2c_client * client);
|
||||
static struct atxp1_data * atxp1_update_device(struct device *dev);
|
||||
static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind);
|
||||
|
||||
static struct i2c_driver atxp1_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "atxp1",
|
||||
.flags = I2C_DF_NOTIFY,
|
||||
.attach_adapter = atxp1_attach_adapter,
|
||||
.detach_client = atxp1_detach_client,
|
||||
};
|
||||
|
||||
struct atxp1_data {
|
||||
struct i2c_client client;
|
||||
struct semaphore update_lock;
|
||||
unsigned long last_updated;
|
||||
u8 valid;
|
||||
struct {
|
||||
u8 vid; /* VID output register */
|
||||
u8 cpu_vid; /* VID input from CPU */
|
||||
u8 gpio1; /* General purpose I/O register 1 */
|
||||
u8 gpio2; /* General purpose I/O register 2 */
|
||||
} reg;
|
||||
u8 vrm; /* Detected CPU VRM */
|
||||
};
|
||||
|
||||
static struct atxp1_data * atxp1_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
struct atxp1_data *data;
|
||||
|
||||
client = to_i2c_client(dev);
|
||||
data = i2c_get_clientdata(client);
|
||||
|
||||
down(&data->update_lock);
|
||||
|
||||
if ((jiffies - data->last_updated > HZ) ||
|
||||
(jiffies < data->last_updated) ||
|
||||
!data->valid) {
|
||||
|
||||
/* Update local register data */
|
||||
data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID);
|
||||
data->reg.cpu_vid = i2c_smbus_read_byte_data(client, ATXP1_CVID);
|
||||
data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1);
|
||||
data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2);
|
||||
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
up(&data->update_lock);
|
||||
|
||||
return(data);
|
||||
}
|
||||
|
||||
/* sys file functions for cpu0_vid */
|
||||
static ssize_t atxp1_showvcore(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int size;
|
||||
struct atxp1_data *data;
|
||||
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK, data->vrm));
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct atxp1_data *data;
|
||||
struct i2c_client *client;
|
||||
char vid;
|
||||
char cvid;
|
||||
unsigned int vcore;
|
||||
|
||||
client = to_i2c_client(dev);
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
vcore = simple_strtoul(buf, NULL, 10);
|
||||
vcore /= 25;
|
||||
vcore *= 25;
|
||||
|
||||
/* Calculate VID */
|
||||
vid = vid_to_reg(vcore, data->vrm);
|
||||
|
||||
if (vid < 0) {
|
||||
dev_err(dev, "VID calculation failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If output enabled, use control register value. Otherwise original CPU VID */
|
||||
if (data->reg.vid & ATXP1_VIDENA)
|
||||
cvid = data->reg.vid & ATXP1_VIDMASK;
|
||||
else
|
||||
cvid = data->reg.cpu_vid;
|
||||
|
||||
/* Nothing changed, aborting */
|
||||
if (vid == cvid)
|
||||
return count;
|
||||
|
||||
dev_info(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid);
|
||||
|
||||
/* Write every 25 mV step to increase stability */
|
||||
if (cvid > vid) {
|
||||
for (; cvid >= vid; cvid--) {
|
||||
i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (; cvid <= vid; cvid++) {
|
||||
i2c_smbus_write_byte_data(client, ATXP1_VID, cvid | ATXP1_VIDENA);
|
||||
}
|
||||
}
|
||||
|
||||
data->valid = 0;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* CPU core reference voltage
|
||||
unit: millivolt
|
||||
*/
|
||||
static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, atxp1_storevcore);
|
||||
|
||||
/* sys file functions for GPIO1 */
|
||||
static ssize_t atxp1_showgpio1(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int size;
|
||||
struct atxp1_data *data;
|
||||
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
size = sprintf(buf, "0x%02x\n", data->reg.gpio1 & ATXP1_GPIO1MASK);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t atxp1_storegpio1(struct device *dev, struct device_attribute *attr, const char*buf, size_t count)
|
||||
{
|
||||
struct atxp1_data *data;
|
||||
struct i2c_client *client;
|
||||
unsigned int value;
|
||||
|
||||
client = to_i2c_client(dev);
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
value = simple_strtoul(buf, NULL, 16);
|
||||
|
||||
value &= ATXP1_GPIO1MASK;
|
||||
|
||||
if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) {
|
||||
dev_info(dev, "Writing 0x%x to GPIO1.\n", value);
|
||||
|
||||
i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value);
|
||||
|
||||
data->valid = 0;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* GPIO1 data register
|
||||
unit: Four bit as hex (e.g. 0x0f)
|
||||
*/
|
||||
static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1);
|
||||
|
||||
/* sys file functions for GPIO2 */
|
||||
static ssize_t atxp1_showgpio2(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int size;
|
||||
struct atxp1_data *data;
|
||||
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
size = sprintf(buf, "0x%02x\n", data->reg.gpio2);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct atxp1_data *data;
|
||||
struct i2c_client *client;
|
||||
unsigned int value;
|
||||
|
||||
client = to_i2c_client(dev);
|
||||
data = atxp1_update_device(dev);
|
||||
|
||||
value = simple_strtoul(buf, NULL, 16) & 0xff;
|
||||
|
||||
if (value != data->reg.gpio2) {
|
||||
dev_info(dev, "Writing 0x%x to GPIO1.\n", value);
|
||||
|
||||
i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value);
|
||||
|
||||
data->valid = 0;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* GPIO2 data register
|
||||
unit: Eight bit as hex (e.g. 0xff)
|
||||
*/
|
||||
static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2);
|
||||
|
||||
|
||||
static int atxp1_attach_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
return i2c_detect(adapter, &addr_data, &atxp1_detect);
|
||||
};
|
||||
|
||||
static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
struct i2c_client * new_client;
|
||||
struct atxp1_data * data;
|
||||
int err = 0;
|
||||
u8 temp;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
goto exit;
|
||||
|
||||
if (!(data = kmalloc(sizeof(struct atxp1_data), GFP_KERNEL))) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
memset(data, 0, sizeof(struct atxp1_data));
|
||||
new_client = &data->client;
|
||||
i2c_set_clientdata(new_client, data);
|
||||
|
||||
new_client->addr = address;
|
||||
new_client->adapter = adapter;
|
||||
new_client->driver = &atxp1_driver;
|
||||
new_client->flags = 0;
|
||||
|
||||
/* Detect ATXP1, checking if vendor ID registers are all zero */
|
||||
if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) &&
|
||||
(i2c_smbus_read_byte_data(new_client, 0x3f) == 0) &&
|
||||
(i2c_smbus_read_byte_data(new_client, 0xfe) == 0) &&
|
||||
(i2c_smbus_read_byte_data(new_client, 0xff) == 0) )) {
|
||||
|
||||
/* No vendor ID, now checking if registers 0x10,0x11 (non-existent)
|
||||
* showing the same as register 0x00 */
|
||||
temp = i2c_smbus_read_byte_data(new_client, 0x00);
|
||||
|
||||
if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) &&
|
||||
(i2c_smbus_read_byte_data(new_client, 0x11) == temp) ))
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
/* Get VRM */
|
||||
data->vrm = i2c_which_vrm();
|
||||
|
||||
if ((data->vrm != 90) && (data->vrm != 91)) {
|
||||
dev_err(&new_client->dev, "Not supporting VRM %d.%d\n",
|
||||
data->vrm / 10, data->vrm % 10);
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
strncpy(new_client->name, "atxp1", I2C_NAME_SIZE);
|
||||
|
||||
data->valid = 0;
|
||||
|
||||
init_MUTEX(&data->update_lock);
|
||||
|
||||
err = i2c_attach_client(new_client);
|
||||
|
||||
if (err)
|
||||
{
|
||||
dev_err(&new_client->dev, "Attach client error.\n");
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
device_create_file(&new_client->dev, &dev_attr_gpio1);
|
||||
device_create_file(&new_client->dev, &dev_attr_gpio2);
|
||||
device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
|
||||
|
||||
dev_info(&new_client->dev, "Using VRM: %d.%d\n",
|
||||
data->vrm / 10, data->vrm % 10);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_free:
|
||||
kfree(data);
|
||||
exit:
|
||||
return err;
|
||||
};
|
||||
|
||||
static int atxp1_detach_client(struct i2c_client * client)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
|
||||
if (err)
|
||||
dev_err(&client->dev, "Failed to detach client.\n");
|
||||
else
|
||||
kfree(i2c_get_clientdata(client));
|
||||
|
||||
return err;
|
||||
};
|
||||
|
||||
static int __init atxp1_init(void)
|
||||
{
|
||||
return i2c_add_driver(&atxp1_driver);
|
||||
};
|
||||
|
||||
static void __exit atxp1_exit(void)
|
||||
{
|
||||
i2c_del_driver(&atxp1_driver);
|
||||
};
|
||||
|
||||
module_init(atxp1_init);
|
||||
module_exit(atxp1_exit);
|
||||
@@ -3,17 +3,16 @@
|
||||
*
|
||||
* Copyright (C) 2005 James Chapman <jchapman@katalix.com>
|
||||
*
|
||||
* based on linux/drivers/acron/char/pcf8583.c
|
||||
* based on linux/drivers/acorn/char/pcf8583.c
|
||||
* Copyright (C) 2000 Russell King
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Driver for Dallas Semiconductor DS1337 real time clock chip
|
||||
* Driver for Dallas Semiconductor DS1337 and DS1339 real time clock chip
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -69,13 +68,11 @@ static struct i2c_driver ds1337_driver = {
|
||||
struct ds1337_data {
|
||||
struct i2c_client client;
|
||||
struct list_head list;
|
||||
int id;
|
||||
};
|
||||
|
||||
/*
|
||||
* Internal variables
|
||||
*/
|
||||
static int ds1337_id;
|
||||
static LIST_HEAD(ds1337_clients);
|
||||
|
||||
static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value)
|
||||
@@ -95,7 +92,6 @@ static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value)
|
||||
*/
|
||||
static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt)
|
||||
{
|
||||
struct ds1337_data *data = i2c_get_clientdata(client);
|
||||
int result;
|
||||
u8 buf[7];
|
||||
u8 val;
|
||||
@@ -103,9 +99,7 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt)
|
||||
u8 offs = 0;
|
||||
|
||||
if (!dt) {
|
||||
dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n",
|
||||
__FUNCTION__);
|
||||
|
||||
dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -119,98 +113,86 @@ static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt)
|
||||
msg[1].len = sizeof(buf);
|
||||
msg[1].buf = &buf[0];
|
||||
|
||||
result = client->adapter->algo->master_xfer(client->adapter,
|
||||
&msg[0], 2);
|
||||
result = i2c_transfer(client->adapter, msg, 2);
|
||||
|
||||
dev_dbg(&client->adapter->dev,
|
||||
"%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
dev_dbg(&client->dev, "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
__FUNCTION__, result, buf[0], buf[1], buf[2], buf[3],
|
||||
buf[4], buf[5], buf[6]);
|
||||
|
||||
if (result >= 0) {
|
||||
dt->tm_sec = BCD_TO_BIN(buf[0]);
|
||||
dt->tm_min = BCD_TO_BIN(buf[1]);
|
||||
if (result == 2) {
|
||||
dt->tm_sec = BCD2BIN(buf[0]);
|
||||
dt->tm_min = BCD2BIN(buf[1]);
|
||||
val = buf[2] & 0x3f;
|
||||
dt->tm_hour = BCD_TO_BIN(val);
|
||||
dt->tm_wday = BCD_TO_BIN(buf[3]) - 1;
|
||||
dt->tm_mday = BCD_TO_BIN(buf[4]);
|
||||
dt->tm_hour = BCD2BIN(val);
|
||||
dt->tm_wday = BCD2BIN(buf[3]) - 1;
|
||||
dt->tm_mday = BCD2BIN(buf[4]);
|
||||
val = buf[5] & 0x7f;
|
||||
dt->tm_mon = BCD_TO_BIN(val);
|
||||
dt->tm_year = 1900 + BCD_TO_BIN(buf[6]);
|
||||
dt->tm_mon = BCD2BIN(val) - 1;
|
||||
dt->tm_year = BCD2BIN(buf[6]);
|
||||
if (buf[5] & 0x80)
|
||||
dt->tm_year += 100;
|
||||
|
||||
dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, "
|
||||
dev_dbg(&client->dev, "%s: secs=%d, mins=%d, "
|
||||
"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
|
||||
__FUNCTION__, dt->tm_sec, dt->tm_min,
|
||||
dt->tm_hour, dt->tm_mday,
|
||||
dt->tm_mon, dt->tm_year, dt->tm_wday);
|
||||
} else {
|
||||
dev_err(&client->adapter->dev, "ds1337[%d]: error reading "
|
||||
"data! %d\n", data->id, result);
|
||||
result = -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
dev_err(&client->dev, "error reading data! %d\n", result);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt)
|
||||
{
|
||||
struct ds1337_data *data = i2c_get_clientdata(client);
|
||||
int result;
|
||||
u8 buf[8];
|
||||
u8 val;
|
||||
struct i2c_msg msg[1];
|
||||
|
||||
if (!dt) {
|
||||
dev_dbg(&client->adapter->dev, "%s: EINVAL: dt=NULL\n",
|
||||
__FUNCTION__);
|
||||
|
||||
dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(&client->adapter->dev, "%s: secs=%d, mins=%d, hours=%d, "
|
||||
dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
|
||||
"mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__,
|
||||
dt->tm_sec, dt->tm_min, dt->tm_hour,
|
||||
dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday);
|
||||
|
||||
buf[0] = 0; /* reg offset */
|
||||
buf[1] = BIN_TO_BCD(dt->tm_sec);
|
||||
buf[2] = BIN_TO_BCD(dt->tm_min);
|
||||
buf[3] = BIN_TO_BCD(dt->tm_hour) | (1 << 6);
|
||||
buf[4] = BIN_TO_BCD(dt->tm_wday) + 1;
|
||||
buf[5] = BIN_TO_BCD(dt->tm_mday);
|
||||
buf[6] = BIN_TO_BCD(dt->tm_mon);
|
||||
if (dt->tm_year >= 2000) {
|
||||
val = dt->tm_year - 2000;
|
||||
buf[1] = BIN2BCD(dt->tm_sec);
|
||||
buf[2] = BIN2BCD(dt->tm_min);
|
||||
buf[3] = BIN2BCD(dt->tm_hour) | (1 << 6);
|
||||
buf[4] = BIN2BCD(dt->tm_wday) + 1;
|
||||
buf[5] = BIN2BCD(dt->tm_mday);
|
||||
buf[6] = BIN2BCD(dt->tm_mon) + 1;
|
||||
val = dt->tm_year;
|
||||
if (val >= 100) {
|
||||
val -= 100;
|
||||
buf[6] |= (1 << 7);
|
||||
} else {
|
||||
val = dt->tm_year - 1900;
|
||||
}
|
||||
buf[7] = BIN_TO_BCD(val);
|
||||
buf[7] = BIN2BCD(val);
|
||||
|
||||
msg[0].addr = client->addr;
|
||||
msg[0].flags = 0;
|
||||
msg[0].len = sizeof(buf);
|
||||
msg[0].buf = &buf[0];
|
||||
|
||||
result = client->adapter->algo->master_xfer(client->adapter,
|
||||
&msg[0], 1);
|
||||
if (result < 0) {
|
||||
dev_err(&client->adapter->dev, "ds1337[%d]: error "
|
||||
"writing data! %d\n", data->id, result);
|
||||
result = -EIO;
|
||||
} else {
|
||||
result = 0;
|
||||
}
|
||||
result = i2c_transfer(client->adapter, msg, 1);
|
||||
if (result == 1)
|
||||
return 0;
|
||||
|
||||
return result;
|
||||
dev_err(&client->dev, "error writing data! %d\n", result);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int ds1337_command(struct i2c_client *client, unsigned int cmd,
|
||||
void *arg)
|
||||
{
|
||||
dev_dbg(&client->adapter->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);
|
||||
dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case DS1337_GET_DATE:
|
||||
@@ -228,7 +210,7 @@ static int ds1337_command(struct i2c_client *client, unsigned int cmd,
|
||||
* Public API for access to specific device. Useful for low-level
|
||||
* RTC access from kernel code.
|
||||
*/
|
||||
int ds1337_do_command(int id, int cmd, void *arg)
|
||||
int ds1337_do_command(int bus, int cmd, void *arg)
|
||||
{
|
||||
struct list_head *walk;
|
||||
struct list_head *tmp;
|
||||
@@ -236,7 +218,7 @@ int ds1337_do_command(int id, int cmd, void *arg)
|
||||
|
||||
list_for_each_safe(walk, tmp, &ds1337_clients) {
|
||||
data = list_entry(walk, struct ds1337_data, list);
|
||||
if (data->id == id)
|
||||
if (data->client.adapter->nr == bus)
|
||||
return ds1337_command(&data->client, cmd, arg);
|
||||
}
|
||||
|
||||
@@ -346,7 +328,6 @@ static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
ds1337_init_client(new_client);
|
||||
|
||||
/* Add client to local list */
|
||||
data->id = ds1337_id++;
|
||||
list_add(&data->list, &ds1337_clients);
|
||||
|
||||
return 0;
|
||||
@@ -398,5 +379,7 @@ MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
|
||||
MODULE_DESCRIPTION("DS1337 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
EXPORT_SYMBOL_GPL(ds1337_do_command);
|
||||
|
||||
module_init(ds1337_init);
|
||||
module_exit(ds1337_exit);
|
||||
|
||||
260
drivers/i2c/chips/ds1374.c
Normal file
260
drivers/i2c/chips/ds1374.c
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* drivers/i2c/chips/ds1374.c
|
||||
*
|
||||
* I2C client/driver for the Maxim/Dallas DS1374 Real-Time Clock
|
||||
*
|
||||
* Author: Randy Vinson <rvinson@mvista.com>
|
||||
*
|
||||
* Based on the m41t00.c by Mark Greer <mgreer@mvista.com>
|
||||
*
|
||||
* 2005 (c) MontaVista Software, Inc. This file is licensed under
|
||||
* the terms of the GNU General Public License version 2. This program
|
||||
* is licensed "as is" without any warranty of any kind, whether express
|
||||
* or implied.
|
||||
*/
|
||||
/*
|
||||
* This i2c client/driver wedges between the drivers/char/genrtc.c RTC
|
||||
* interface and the SMBus interface of the i2c subsystem.
|
||||
* It would be more efficient to use i2c msgs/i2c_transfer directly but, as
|
||||
* recommened in .../Documentation/i2c/writing-clients section
|
||||
* "Sending and receiving", using SMBus level communication is preferred.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/bcd.h>
|
||||
|
||||
#define DS1374_REG_TOD0 0x00
|
||||
#define DS1374_REG_TOD1 0x01
|
||||
#define DS1374_REG_TOD2 0x02
|
||||
#define DS1374_REG_TOD3 0x03
|
||||
#define DS1374_REG_WDALM0 0x04
|
||||
#define DS1374_REG_WDALM1 0x05
|
||||
#define DS1374_REG_WDALM2 0x06
|
||||
#define DS1374_REG_CR 0x07
|
||||
#define DS1374_REG_SR 0x08
|
||||
#define DS1374_REG_SR_OSF 0x80
|
||||
#define DS1374_REG_TCR 0x09
|
||||
|
||||
#define DS1374_DRV_NAME "ds1374"
|
||||
|
||||
static DECLARE_MUTEX(ds1374_mutex);
|
||||
|
||||
static struct i2c_driver ds1374_driver;
|
||||
static struct i2c_client *save_client;
|
||||
|
||||
static unsigned short ignore[] = { I2C_CLIENT_END };
|
||||
static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END };
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_addr,
|
||||
.probe = ignore,
|
||||
.ignore = ignore,
|
||||
.force = ignore,
|
||||
};
|
||||
|
||||
static ulong ds1374_read_rtc(void)
|
||||
{
|
||||
ulong time = 0;
|
||||
int reg = DS1374_REG_WDALM0;
|
||||
|
||||
while (reg--) {
|
||||
s32 tmp;
|
||||
if ((tmp = i2c_smbus_read_byte_data(save_client, reg)) < 0) {
|
||||
dev_warn(&save_client->dev,
|
||||
"can't read from rtc chip\n");
|
||||
return 0;
|
||||
}
|
||||
time = (time << 8) | (tmp & 0xff);
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
static void ds1374_write_rtc(ulong time)
|
||||
{
|
||||
int reg;
|
||||
|
||||
for (reg = DS1374_REG_TOD0; reg < DS1374_REG_WDALM0; reg++) {
|
||||
if (i2c_smbus_write_byte_data(save_client, reg, time & 0xff)
|
||||
< 0) {
|
||||
dev_warn(&save_client->dev,
|
||||
"can't write to rtc chip\n");
|
||||
break;
|
||||
}
|
||||
time = time >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void ds1374_check_rtc_status(void)
|
||||
{
|
||||
s32 tmp;
|
||||
|
||||
tmp = i2c_smbus_read_byte_data(save_client, DS1374_REG_SR);
|
||||
if (tmp < 0) {
|
||||
dev_warn(&save_client->dev,
|
||||
"can't read status from rtc chip\n");
|
||||
return;
|
||||
}
|
||||
if (tmp & DS1374_REG_SR_OSF) {
|
||||
dev_warn(&save_client->dev,
|
||||
"oscillator discontinuity flagged, time unreliable\n");
|
||||
tmp &= ~DS1374_REG_SR_OSF;
|
||||
tmp = i2c_smbus_write_byte_data(save_client, DS1374_REG_SR,
|
||||
tmp & 0xff);
|
||||
if (tmp < 0)
|
||||
dev_warn(&save_client->dev,
|
||||
"can't clear discontinuity notification\n");
|
||||
}
|
||||
}
|
||||
|
||||
ulong ds1374_get_rtc_time(void)
|
||||
{
|
||||
ulong t1, t2;
|
||||
int limit = 10; /* arbitrary retry limit */
|
||||
|
||||
down(&ds1374_mutex);
|
||||
|
||||
/*
|
||||
* Since the reads are being performed one byte at a time using
|
||||
* the SMBus vs a 4-byte i2c transfer, there is a chance that a
|
||||
* carry will occur during the read. To detect this, 2 reads are
|
||||
* performed and compared.
|
||||
*/
|
||||
do {
|
||||
t1 = ds1374_read_rtc();
|
||||
t2 = ds1374_read_rtc();
|
||||
} while (t1 != t2 && limit--);
|
||||
|
||||
up(&ds1374_mutex);
|
||||
|
||||
if (t1 != t2) {
|
||||
dev_warn(&save_client->dev,
|
||||
"can't get consistent time from rtc chip\n");
|
||||
t1 = 0;
|
||||
}
|
||||
|
||||
return t1;
|
||||
}
|
||||
|
||||
static void ds1374_set_tlet(ulong arg)
|
||||
{
|
||||
ulong t1, t2;
|
||||
int limit = 10; /* arbitrary retry limit */
|
||||
|
||||
t1 = *(ulong *) arg;
|
||||
|
||||
down(&ds1374_mutex);
|
||||
|
||||
/*
|
||||
* Since the writes are being performed one byte at a time using
|
||||
* the SMBus vs a 4-byte i2c transfer, there is a chance that a
|
||||
* carry will occur during the write. To detect this, the write
|
||||
* value is read back and compared.
|
||||
*/
|
||||
do {
|
||||
ds1374_write_rtc(t1);
|
||||
t2 = ds1374_read_rtc();
|
||||
} while (t1 != t2 && limit--);
|
||||
|
||||
up(&ds1374_mutex);
|
||||
|
||||
if (t1 != t2)
|
||||
dev_warn(&save_client->dev,
|
||||
"can't confirm time set from rtc chip\n");
|
||||
}
|
||||
|
||||
ulong new_time;
|
||||
|
||||
DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, (ulong) & new_time);
|
||||
|
||||
int ds1374_set_rtc_time(ulong nowtime)
|
||||
{
|
||||
new_time = nowtime;
|
||||
|
||||
if (in_interrupt())
|
||||
tasklet_schedule(&ds1374_tasklet);
|
||||
else
|
||||
ds1374_set_tlet((ulong) & new_time);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*****************************************************************************
|
||||
*
|
||||
* Driver Interface
|
||||
*
|
||||
*****************************************************************************
|
||||
*/
|
||||
static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
int rc;
|
||||
|
||||
client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
||||
if (!client)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(client, 0, sizeof(struct i2c_client));
|
||||
strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE);
|
||||
client->flags = I2C_DF_NOTIFY;
|
||||
client->addr = addr;
|
||||
client->adapter = adap;
|
||||
client->driver = &ds1374_driver;
|
||||
|
||||
if ((rc = i2c_attach_client(client)) != 0) {
|
||||
kfree(client);
|
||||
return rc;
|
||||
}
|
||||
|
||||
save_client = client;
|
||||
|
||||
ds1374_check_rtc_status();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ds1374_attach(struct i2c_adapter *adap)
|
||||
{
|
||||
return i2c_probe(adap, &addr_data, ds1374_probe);
|
||||
}
|
||||
|
||||
static int ds1374_detach(struct i2c_client *client)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if ((rc = i2c_detach_client(client)) == 0) {
|
||||
kfree(i2c_get_clientdata(client));
|
||||
tasklet_kill(&ds1374_tasklet);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct i2c_driver ds1374_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DS1374_DRV_NAME,
|
||||
.id = I2C_DRIVERID_DS1374,
|
||||
.flags = I2C_DF_NOTIFY,
|
||||
.attach_adapter = ds1374_attach,
|
||||
.detach_client = ds1374_detach,
|
||||
};
|
||||
|
||||
static int __init ds1374_init(void)
|
||||
{
|
||||
return i2c_add_driver(&ds1374_driver);
|
||||
}
|
||||
|
||||
static void __exit ds1374_exit(void)
|
||||
{
|
||||
i2c_del_driver(&ds1374_driver);
|
||||
}
|
||||
|
||||
module_init(ds1374_init);
|
||||
module_exit(ds1374_exit);
|
||||
|
||||
MODULE_AUTHOR("Randy Vinson <rvinson@mvista.com>");
|
||||
MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC I2C Client Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -121,7 +121,7 @@ static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value)
|
||||
static void ds1621_init_client(struct i2c_client *client)
|
||||
{
|
||||
int reg = ds1621_read_value(client, DS1621_REG_CONF);
|
||||
/* switch to continous conversion mode */
|
||||
/* switch to continuous conversion mode */
|
||||
reg &= ~ DS1621_REG_CONFIG_1SHOT;
|
||||
|
||||
/* setup output polarity */
|
||||
@@ -303,7 +303,7 @@ static struct ds1621_data *ds1621_update_client(struct device *dev)
|
||||
data->temp_max = ds1621_read_value(client,
|
||||
DS1621_REG_TEMP_MAX);
|
||||
|
||||
/* reset alarms if neccessary */
|
||||
/* reset alarms if necessary */
|
||||
new_conf = data->conf;
|
||||
if (data->temp < data->temp_min)
|
||||
new_conf &= ~DS1621_ALARM_TEMP_LOW;
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
* and Philip Edelbrock <phil@netroedge.com>
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
* 2004-01-31 Code review and approval. (Jean Delvare)
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -145,7 +145,6 @@ static inline void notresponding(struct isp1301 *isp)
|
||||
static unsigned short normal_i2c[] = {
|
||||
ISP_BASE, ISP_BASE + 1,
|
||||
I2C_CLIENT_END };
|
||||
static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
|
||||
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
type at module load time.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -39,6 +38,7 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
#include <linux/i2c-vid.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
|
||||
@@ -173,8 +173,6 @@ static inline u8 FAN_TO_REG(long rpm, int div)
|
||||
((val)+500)/1000),-128,127))
|
||||
#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000)
|
||||
|
||||
#define ALARMS_FROM_REG(val) (val)
|
||||
|
||||
#define PWM_TO_REG(val) ((val) >> 1)
|
||||
#define PWM_FROM_REG(val) (((val)&0x7f) << 1)
|
||||
|
||||
@@ -241,27 +239,42 @@ static struct i2c_driver it87_driver = {
|
||||
.detach_client = it87_detach_client,
|
||||
};
|
||||
|
||||
static ssize_t show_in(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_in(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_in_min(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
|
||||
}
|
||||
|
||||
static ssize_t show_in_max(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
|
||||
}
|
||||
|
||||
static ssize_t set_in_min(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
@@ -273,9 +286,12 @@ static ssize_t set_in_min(struct device *dev, const char *buf,
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_in_max(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
@@ -289,38 +305,14 @@ static ssize_t set_in_max(struct device *dev, const char *buf,
|
||||
}
|
||||
|
||||
#define show_in_offset(offset) \
|
||||
static ssize_t \
|
||||
show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_in(dev, buf, offset); \
|
||||
} \
|
||||
static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);
|
||||
static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
|
||||
show_in, NULL, offset);
|
||||
|
||||
#define limit_in_offset(offset) \
|
||||
static ssize_t \
|
||||
show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_in_min(dev, buf, offset); \
|
||||
} \
|
||||
static ssize_t \
|
||||
show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_in_max(dev, buf, offset); \
|
||||
} \
|
||||
static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_in_min(dev, buf, count, offset); \
|
||||
} \
|
||||
static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_in_max(dev, buf, count, offset); \
|
||||
} \
|
||||
static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_in##offset##_min, set_in##offset##_min); \
|
||||
static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
|
||||
show_in##offset##_max, set_in##offset##_max);
|
||||
static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_in_min, set_in_min, offset); \
|
||||
static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
|
||||
show_in_max, set_in_max, offset);
|
||||
|
||||
show_in_offset(0);
|
||||
limit_in_offset(0);
|
||||
@@ -341,24 +333,39 @@ limit_in_offset(7);
|
||||
show_in_offset(8);
|
||||
|
||||
/* 3 temperatures */
|
||||
static ssize_t show_temp(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
|
||||
}
|
||||
static ssize_t show_temp_max(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr]));
|
||||
}
|
||||
static ssize_t show_temp_min(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr]));
|
||||
}
|
||||
static ssize_t set_temp_max(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
@@ -369,9 +376,12 @@ static ssize_t set_temp_max(struct device *dev, const char *buf,
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_temp_min(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
@@ -383,42 +393,23 @@ static ssize_t set_temp_min(struct device *dev, const char *buf,
|
||||
return count;
|
||||
}
|
||||
#define show_temp_offset(offset) \
|
||||
static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_temp(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t \
|
||||
show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_temp_max(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t \
|
||||
show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_temp_min(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_temp_max(dev, buf, count, offset - 1); \
|
||||
} \
|
||||
static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_temp_min(dev, buf, count, offset - 1); \
|
||||
} \
|
||||
static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL); \
|
||||
static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
|
||||
show_temp_##offset##_max, set_temp_##offset##_max); \
|
||||
static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_temp_##offset##_min, set_temp_##offset##_min);
|
||||
static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
|
||||
show_temp, NULL, offset - 1); \
|
||||
static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
|
||||
show_temp_max, set_temp_max, offset - 1); \
|
||||
static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_temp_min, set_temp_min, offset - 1);
|
||||
|
||||
show_temp_offset(1);
|
||||
show_temp_offset(2);
|
||||
show_temp_offset(3);
|
||||
|
||||
static ssize_t show_sensor(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_sensor(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
u8 reg = data->sensor; /* In case the value is updated while we use it */
|
||||
|
||||
@@ -428,9 +419,12 @@ static ssize_t show_sensor(struct device *dev, char *buf, int nr)
|
||||
return sprintf(buf, "2\n"); /* thermistor */
|
||||
return sprintf(buf, "0\n"); /* disabled */
|
||||
}
|
||||
static ssize_t set_sensor(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_sensor(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
@@ -453,53 +447,67 @@ static ssize_t set_sensor(struct device *dev, const char *buf,
|
||||
return count;
|
||||
}
|
||||
#define show_sensor_offset(offset) \
|
||||
static ssize_t show_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_sensor(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t set_sensor_##offset (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_sensor(dev, buf, count, offset - 1); \
|
||||
} \
|
||||
static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
|
||||
show_sensor_##offset, set_sensor_##offset);
|
||||
static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
|
||||
show_sensor, set_sensor, offset - 1);
|
||||
|
||||
show_sensor_offset(1);
|
||||
show_sensor_offset(2);
|
||||
show_sensor_offset(3);
|
||||
|
||||
/* 3 Fans */
|
||||
static ssize_t show_fan(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr],
|
||||
DIV_FROM_REG(data->fan_div[nr])));
|
||||
}
|
||||
static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf,"%d\n",
|
||||
FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])));
|
||||
}
|
||||
static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
|
||||
}
|
||||
static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_pwm_enable(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf,"%d\n", (data->fan_main_ctrl & (1 << nr)) ? 1 : 0);
|
||||
}
|
||||
static ssize_t show_pwm(struct device *dev, char *buf, int nr)
|
||||
static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf,"%d\n", data->manual_pwm_ctl[nr]);
|
||||
}
|
||||
static ssize_t set_fan_min(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
@@ -510,9 +518,12 @@ static ssize_t set_fan_min(struct device *dev, const char *buf,
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_fan_div(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
@@ -550,9 +561,12 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_pwm_enable(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_pwm_enable(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
@@ -581,9 +595,12 @@ static ssize_t set_pwm_enable(struct device *dev, const char *buf,
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_pwm(struct device *dev, const char *buf,
|
||||
size_t count, int nr)
|
||||
static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct it87_data *data = i2c_get_clientdata(client);
|
||||
int val = simple_strtol(buf, NULL, 10);
|
||||
@@ -599,64 +616,23 @@ static ssize_t set_pwm(struct device *dev, const char *buf,
|
||||
return count;
|
||||
}
|
||||
|
||||
#define show_fan_offset(offset) \
|
||||
static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_fan(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_fan_min(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_fan_div(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_fan_min(dev, buf, count, offset - 1); \
|
||||
} \
|
||||
static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_fan_div(dev, buf, count, offset - 1); \
|
||||
} \
|
||||
static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL); \
|
||||
static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_fan_##offset##_min, set_fan_##offset##_min); \
|
||||
static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
|
||||
show_fan_##offset##_div, set_fan_##offset##_div);
|
||||
#define show_fan_offset(offset) \
|
||||
static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
|
||||
show_fan, NULL, offset - 1); \
|
||||
static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_fan_min, set_fan_min, offset - 1); \
|
||||
static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
|
||||
show_fan_div, set_fan_div, offset - 1);
|
||||
|
||||
show_fan_offset(1);
|
||||
show_fan_offset(2);
|
||||
show_fan_offset(3);
|
||||
|
||||
#define show_pwm_offset(offset) \
|
||||
static ssize_t show_pwm##offset##_enable (struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_pwm_enable(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t show_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
return show_pwm(dev, buf, offset - 1); \
|
||||
} \
|
||||
static ssize_t set_pwm##offset##_enable (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_pwm_enable(dev, buf, count, offset - 1); \
|
||||
} \
|
||||
static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return set_pwm(dev, buf, count, offset - 1); \
|
||||
} \
|
||||
static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
|
||||
show_pwm##offset##_enable, \
|
||||
set_pwm##offset##_enable); \
|
||||
static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
|
||||
show_pwm##offset , set_pwm##offset );
|
||||
static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
|
||||
show_pwm_enable, set_pwm_enable, offset - 1); \
|
||||
static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
|
||||
show_pwm, set_pwm, offset - 1);
|
||||
|
||||
show_pwm_offset(1);
|
||||
show_pwm_offset(2);
|
||||
@@ -666,7 +642,7 @@ show_pwm_offset(3);
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms));
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
@@ -864,60 +840,60 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
it87_init_client(new_client, data);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in6_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in7_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in8_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in6_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in7_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_in0_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in4_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in5_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in6_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_in7_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_type);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_type);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_type);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan3_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan2_div);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan3_div);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
if (enable_pwm_interface) {
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm3_enable);
|
||||
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, &sensor_dev_attr_pwm1_enable.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm2_enable.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm3_enable.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr);
|
||||
device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr);
|
||||
}
|
||||
|
||||
if (data->type == it8712) {
|
||||
@@ -954,7 +930,7 @@ static int it87_detach_client(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The SMBus locks itself, but ISA access must be locked explicitely!
|
||||
/* The SMBus locks itself, but ISA access must be locked explicitly!
|
||||
We don't want to lock the whole ISA bus, so we lock each client
|
||||
separately.
|
||||
We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
|
||||
@@ -974,7 +950,7 @@ static int it87_read_value(struct i2c_client *client, u8 reg)
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
/* The SMBus locks itself, but ISA access muse be locked explicitely!
|
||||
/* The SMBus locks itself, but ISA access muse be locked explicitly!
|
||||
We don't want to lock the whole ISA bus, so we lock each client
|
||||
separately.
|
||||
We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* lm63.c - driver for the National Semiconductor LM63 temperature sensor
|
||||
* with integrated fan control
|
||||
* Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
|
||||
* Copyright (C) 2004-2005 Jean Delvare <khali@linux-fr.org>
|
||||
* Based on the lm90 driver.
|
||||
*
|
||||
* The LM63 is a sensor chip made by National Semiconductor. It measures
|
||||
@@ -37,13 +37,13 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
|
||||
/*
|
||||
* Addresses to scan
|
||||
@@ -99,9 +99,9 @@ SENSORS_INSMOD_1(lm63);
|
||||
* Conversions and various macros
|
||||
* For tachometer counts, the LM63 uses 16-bit values.
|
||||
* For local temperature and high limit, remote critical limit and hysteresis
|
||||
* value, it uses signed 8-bit values with LSB = 1 degree Celcius.
|
||||
* value, it uses signed 8-bit values with LSB = 1 degree Celsius.
|
||||
* For remote temperature, low and high limits, it uses signed 11-bit values
|
||||
* with LSB = 0.125 degree Celcius, left-justified in 16-bit registers.
|
||||
* with LSB = 0.125 degree Celsius, left-justified in 16-bit registers.
|
||||
*/
|
||||
|
||||
#define FAN_FROM_REG(reg) ((reg) == 0xFFFC || (reg) == 0 ? 0 : \
|
||||
@@ -158,16 +158,16 @@ struct lm63_data {
|
||||
|
||||
/* registers values */
|
||||
u8 config, config_fan;
|
||||
u16 fan1_input;
|
||||
u16 fan1_low;
|
||||
u16 fan[2]; /* 0: input
|
||||
1: low limit */
|
||||
u8 pwm1_freq;
|
||||
u8 pwm1_value;
|
||||
s8 temp1_input;
|
||||
s8 temp1_high;
|
||||
s16 temp2_input;
|
||||
s16 temp2_high;
|
||||
s16 temp2_low;
|
||||
s8 temp2_crit;
|
||||
s8 temp8[3]; /* 0: local input
|
||||
1: local high limit
|
||||
2: remote critical limit */
|
||||
s16 temp11[3]; /* 0: remote input
|
||||
1: remote low limit
|
||||
2: remote high limit */
|
||||
u8 temp2_crit_hyst;
|
||||
u8 alarms;
|
||||
};
|
||||
@@ -176,33 +176,33 @@ struct lm63_data {
|
||||
* Sysfs callback functions and files
|
||||
*/
|
||||
|
||||
#define show_fan(value) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct lm63_data *data = lm63_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", FAN_FROM_REG(data->value)); \
|
||||
static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm63_data *data = lm63_update_device(dev);
|
||||
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index]));
|
||||
}
|
||||
show_fan(fan1_input);
|
||||
show_fan(fan1_low);
|
||||
|
||||
static ssize_t set_fan1_low(struct device *dev, struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
static ssize_t set_fan(struct device *dev, struct device_attribute *dummy,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm63_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
down(&data->update_lock);
|
||||
data->fan1_low = FAN_TO_REG(val);
|
||||
data->fan[1] = FAN_TO_REG(val);
|
||||
i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_LSB,
|
||||
data->fan1_low & 0xFF);
|
||||
data->fan[1] & 0xFF);
|
||||
i2c_smbus_write_byte_data(client, LM63_REG_TACH_LIMIT_MSB,
|
||||
data->fan1_low >> 8);
|
||||
data->fan[1] >> 8);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy,
|
||||
char *buf)
|
||||
{
|
||||
struct lm63_data *data = lm63_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ?
|
||||
@@ -210,7 +210,8 @@ static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char
|
||||
(2 * data->pwm1_freq));
|
||||
}
|
||||
|
||||
static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm63_data *data = i2c_get_clientdata(client);
|
||||
@@ -229,77 +230,83 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, const
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy,
|
||||
char *buf)
|
||||
{
|
||||
struct lm63_data *data = lm63_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2);
|
||||
}
|
||||
|
||||
#define show_temp8(value) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct lm63_data *data = lm63_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->value)); \
|
||||
static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm63_data *data = lm63_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index]));
|
||||
}
|
||||
#define show_temp11(value) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct lm63_data *data = lm63_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->value)); \
|
||||
}
|
||||
show_temp8(temp1_input);
|
||||
show_temp8(temp1_high);
|
||||
show_temp11(temp2_input);
|
||||
show_temp11(temp2_high);
|
||||
show_temp11(temp2_low);
|
||||
show_temp8(temp2_crit);
|
||||
|
||||
#define set_temp8(value, reg) \
|
||||
static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \
|
||||
size_t count) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct lm63_data *data = i2c_get_clientdata(client); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
\
|
||||
down(&data->update_lock); \
|
||||
data->value = TEMP8_TO_REG(val); \
|
||||
i2c_smbus_write_byte_data(client, reg, data->value); \
|
||||
up(&data->update_lock); \
|
||||
return count; \
|
||||
static ssize_t set_temp8(struct device *dev, struct device_attribute *dummy,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm63_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
|
||||
down(&data->update_lock);
|
||||
data->temp8[1] = TEMP8_TO_REG(val);
|
||||
i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
#define set_temp11(value, reg_msb, reg_lsb) \
|
||||
static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \
|
||||
size_t count) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct lm63_data *data = i2c_get_clientdata(client); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
\
|
||||
down(&data->update_lock); \
|
||||
data->value = TEMP11_TO_REG(val); \
|
||||
i2c_smbus_write_byte_data(client, reg_msb, data->value >> 8); \
|
||||
i2c_smbus_write_byte_data(client, reg_lsb, data->value & 0xff); \
|
||||
up(&data->update_lock); \
|
||||
return count; \
|
||||
|
||||
static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm63_data *data = lm63_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index]));
|
||||
}
|
||||
|
||||
static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
static const u8 reg[4] = {
|
||||
LM63_REG_REMOTE_LOW_MSB,
|
||||
LM63_REG_REMOTE_LOW_LSB,
|
||||
LM63_REG_REMOTE_HIGH_MSB,
|
||||
LM63_REG_REMOTE_HIGH_LSB,
|
||||
};
|
||||
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm63_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
int nr = attr->index;
|
||||
|
||||
down(&data->update_lock);
|
||||
data->temp11[nr] = TEMP11_TO_REG(val);
|
||||
i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
|
||||
data->temp11[nr] >> 8);
|
||||
i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
|
||||
data->temp11[nr] & 0xff);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
set_temp8(temp1_high, LM63_REG_LOCAL_HIGH);
|
||||
set_temp11(temp2_high, LM63_REG_REMOTE_HIGH_MSB, LM63_REG_REMOTE_HIGH_LSB);
|
||||
set_temp11(temp2_low, LM63_REG_REMOTE_LOW_MSB, LM63_REG_REMOTE_LOW_LSB);
|
||||
|
||||
/* Hysteresis register holds a relative value, while we want to present
|
||||
an absolute to user-space */
|
||||
static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy,
|
||||
char *buf)
|
||||
{
|
||||
struct lm63_data *data = lm63_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp2_crit)
|
||||
return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2])
|
||||
- TEMP8_FROM_REG(data->temp2_crit_hyst));
|
||||
}
|
||||
|
||||
/* And now the other way around, user-space provides an absolute
|
||||
hysteresis value and we have to store a relative one */
|
||||
static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm63_data *data = i2c_get_clientdata(client);
|
||||
@@ -307,36 +314,37 @@ static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *
|
||||
long hyst;
|
||||
|
||||
down(&data->update_lock);
|
||||
hyst = TEMP8_FROM_REG(data->temp2_crit) - val;
|
||||
hyst = TEMP8_FROM_REG(data->temp8[2]) - val;
|
||||
i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
|
||||
HYST_TO_REG(hyst));
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
|
||||
char *buf)
|
||||
{
|
||||
struct lm63_data *data = lm63_update_device(dev);
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan1_input, NULL);
|
||||
static DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan1_low,
|
||||
set_fan1_low);
|
||||
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
|
||||
set_fan, 1);
|
||||
|
||||
static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1);
|
||||
static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL);
|
||||
|
||||
static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL);
|
||||
static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_high,
|
||||
set_temp1_high);
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8,
|
||||
set_temp8, 1);
|
||||
|
||||
static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp2_input, NULL);
|
||||
static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp2_low,
|
||||
set_temp2_low);
|
||||
static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp2_high,
|
||||
set_temp2_high);
|
||||
static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp2_crit, NULL);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
|
||||
set_temp11, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
|
||||
set_temp11, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2);
|
||||
static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
|
||||
set_temp2_crit_hyst);
|
||||
|
||||
@@ -430,17 +438,25 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
|
||||
/* Register sysfs hooks */
|
||||
if (data->config & 0x04) { /* tachometer enabled */
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_fan1_min);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan1_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_fan1_min.dev_attr);
|
||||
}
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1);
|
||||
device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_crit);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_min.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_crit.dev_attr);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
|
||||
@@ -511,14 +527,14 @@ static struct lm63_data *lm63_update_device(struct device *dev)
|
||||
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
|
||||
if (data->config & 0x04) { /* tachometer enabled */
|
||||
/* order matters for fan1_input */
|
||||
data->fan1_input = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_TACH_COUNT_LSB) & 0xFC;
|
||||
data->fan1_input |= i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_TACH_COUNT_MSB) << 8;
|
||||
data->fan1_low = (i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_TACH_LIMIT_LSB) & 0xFC)
|
||||
| (i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_TACH_LIMIT_MSB) << 8);
|
||||
data->fan[0] = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_TACH_COUNT_LSB) & 0xFC;
|
||||
data->fan[0] |= i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_TACH_COUNT_MSB) << 8;
|
||||
data->fan[1] = (i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_TACH_LIMIT_LSB) & 0xFC)
|
||||
| (i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_TACH_LIMIT_MSB) << 8);
|
||||
}
|
||||
|
||||
data->pwm1_freq = i2c_smbus_read_byte_data(client,
|
||||
@@ -528,26 +544,26 @@ static struct lm63_data *lm63_update_device(struct device *dev)
|
||||
data->pwm1_value = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_PWM_VALUE);
|
||||
|
||||
data->temp1_input = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_LOCAL_TEMP);
|
||||
data->temp1_high = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_LOCAL_HIGH);
|
||||
data->temp8[0] = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_LOCAL_TEMP);
|
||||
data->temp8[1] = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_LOCAL_HIGH);
|
||||
|
||||
/* order matters for temp2_input */
|
||||
data->temp2_input = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_TEMP_MSB) << 8;
|
||||
data->temp2_input |= i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_TEMP_LSB);
|
||||
data->temp2_high = (i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_HIGH_MSB) << 8)
|
||||
| i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_HIGH_LSB);
|
||||
data->temp2_low = (i2c_smbus_read_byte_data(client,
|
||||
data->temp11[0] = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_TEMP_MSB) << 8;
|
||||
data->temp11[0] |= i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_TEMP_LSB);
|
||||
data->temp11[1] = (i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_LOW_MSB) << 8)
|
||||
| i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_LOW_LSB);
|
||||
data->temp2_crit = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_TCRIT);
|
||||
data->temp11[2] = (i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_HIGH_MSB) << 8)
|
||||
| i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_HIGH_LSB);
|
||||
data->temp8[2] = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_TCRIT);
|
||||
data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
|
||||
LM63_REG_REMOTE_TCRIT_HYST);
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -671,7 +670,7 @@ static int lm78_detach_client(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The SMBus locks itself, but ISA access must be locked explicitely!
|
||||
/* The SMBus locks itself, but ISA access must be locked explicitly!
|
||||
We don't want to lock the whole ISA bus, so we lock each client
|
||||
separately.
|
||||
We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
|
||||
@@ -690,7 +689,7 @@ static int lm78_read_value(struct i2c_client *client, u8 reg)
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
/* The SMBus locks itself, but ISA access muse be locked explicitely!
|
||||
/* The SMBus locks itself, but ISA access muse be locked explicitly!
|
||||
We don't want to lock the whole ISA bus, so we lock each client
|
||||
separately.
|
||||
We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* lm83.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
* Copyright (C) 2003 Jean Delvare <khali@linux-fr.org>
|
||||
* Copyright (C) 2003-2005 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
|
||||
@@ -27,13 +27,13 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
|
||||
/*
|
||||
* Addresses to scan
|
||||
@@ -81,7 +81,7 @@ SENSORS_INSMOD_1(lm83);
|
||||
|
||||
/*
|
||||
* Conversions and various macros
|
||||
* The LM83 uses signed 8-bit values with LSB = 1 degree Celcius.
|
||||
* The LM83 uses signed 8-bit values with LSB = 1 degree Celsius.
|
||||
*/
|
||||
|
||||
#define TEMP_FROM_REG(val) ((val) * 1000)
|
||||
@@ -94,21 +94,20 @@ 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_REMOTE3_TEMP,
|
||||
LM83_REG_R_LOCAL_HIGH,
|
||||
LM83_REG_R_REMOTE1_HIGH,
|
||||
LM83_REG_R_REMOTE2_HIGH,
|
||||
LM83_REG_R_REMOTE3_HIGH
|
||||
LM83_REG_R_REMOTE3_HIGH,
|
||||
LM83_REG_R_TCRIT,
|
||||
};
|
||||
|
||||
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
|
||||
LM83_REG_W_REMOTE3_HIGH,
|
||||
LM83_REG_W_TCRIT,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -144,9 +143,9 @@ struct lm83_data {
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
|
||||
/* registers values */
|
||||
s8 temp_input[4];
|
||||
s8 temp_high[4];
|
||||
s8 temp_crit;
|
||||
s8 temp[9]; /* 0..3: input 1-4,
|
||||
4..7: high limit 1-4,
|
||||
8 : critical limit */
|
||||
u16 alarms; /* bitvector, combined */
|
||||
};
|
||||
|
||||
@@ -154,65 +153,55 @@ struct lm83_data {
|
||||
* Sysfs stuff
|
||||
*/
|
||||
|
||||
#define show_temp(suffix, value) \
|
||||
static ssize_t show_temp_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct lm83_data *data = lm83_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \
|
||||
static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm83_data *data = lm83_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
|
||||
}
|
||||
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, struct device_attribute *attr, const char *buf, \
|
||||
size_t count) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct lm83_data *data = i2c_get_clientdata(client); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
\
|
||||
down(&data->update_lock); \
|
||||
data->value = TEMP_TO_REG(val); \
|
||||
i2c_smbus_write_byte_data(client, reg, data->value); \
|
||||
up(&data->update_lock); \
|
||||
return count; \
|
||||
static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm83_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
int nr = attr->index;
|
||||
|
||||
down(&data->update_lock);
|
||||
data->temp[nr] = TEMP_TO_REG(val);
|
||||
i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr - 4],
|
||||
data->temp[nr]);
|
||||
up(&data->update_lock);
|
||||
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, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
|
||||
char *buf)
|
||||
{
|
||||
struct lm83_data *data = lm83_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->alarms);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
|
||||
static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL);
|
||||
static DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input3, NULL);
|
||||
static DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input4, NULL);
|
||||
static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_high1,
|
||||
set_temp_high1);
|
||||
static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2,
|
||||
set_temp_high2);
|
||||
static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_high3,
|
||||
set_temp_high3);
|
||||
static DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_high4,
|
||||
set_temp_high4);
|
||||
static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL);
|
||||
static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL);
|
||||
static DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp_crit,
|
||||
set_temp_crit);
|
||||
static DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL);
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp,
|
||||
set_temp, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp,
|
||||
set_temp, 5);
|
||||
static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp,
|
||||
set_temp, 6);
|
||||
static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp,
|
||||
set_temp, 7);
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, 8);
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp, NULL, 8);
|
||||
static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp,
|
||||
set_temp, 8);
|
||||
static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8);
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
/*
|
||||
@@ -323,18 +312,30 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
*/
|
||||
|
||||
/* Register sysfs hooks */
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp4_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp4_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_crit);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_crit);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp3_crit);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp4_crit);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp3_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp4_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp3_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp4_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_crit.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_crit.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp3_crit.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp4_crit.dev_attr);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
|
||||
return 0;
|
||||
@@ -370,16 +371,11 @@ static struct lm83_data *lm83_update_device(struct device *dev)
|
||||
int nr;
|
||||
|
||||
dev_dbg(&client->dev, "Updating lm83 data.\n");
|
||||
for (nr = 0; nr < 4 ; nr++) {
|
||||
data->temp_input[nr] =
|
||||
for (nr = 0; nr < 9; nr++) {
|
||||
data->temp[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)
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -285,8 +284,6 @@ static int ZONE_TO_REG( int zone )
|
||||
/* 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
|
||||
@@ -481,7 +478,7 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
|
||||
static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct lm85_data *data = lm85_update_device(dev);
|
||||
return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms));
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* lm90.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
* Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
|
||||
* Copyright (C) 2003-2005 Jean Delvare <khali@linux-fr.org>
|
||||
*
|
||||
* Based on the lm83 driver. The LM90 is a sensor chip made by National
|
||||
* Semiconductor. It reports up to two temperatures (its own plus up to
|
||||
@@ -19,7 +19,7 @@
|
||||
* Complete datasheets can be obtained from National's website at:
|
||||
* http://www.national.com/pf/LM/LM89.html
|
||||
* http://www.national.com/pf/LM/LM99.html
|
||||
* Note that there is no way to differenciate between both chips.
|
||||
* Note that there is no way to differentiate between both chips.
|
||||
*
|
||||
* This driver also supports the LM86, another sensor chip made by
|
||||
* National Semiconductor. It is exactly similar to the LM90 except it
|
||||
@@ -39,7 +39,7 @@
|
||||
* chips made by Maxim. These chips are similar to the LM86. Complete
|
||||
* datasheet can be obtained at Maxim's website at:
|
||||
* http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
|
||||
* Note that there is no easy way to differenciate between the three
|
||||
* Note that there is no easy way to differentiate between the three
|
||||
* variants. The extra address and features of the MAX6659 are not
|
||||
* supported by this driver.
|
||||
*
|
||||
@@ -70,13 +70,13 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
|
||||
/*
|
||||
* Addresses to scan
|
||||
@@ -139,9 +139,9 @@ SENSORS_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461);
|
||||
/*
|
||||
* Conversions and various macros
|
||||
* For local temperatures and limits, critical limits and the hysteresis
|
||||
* value, the LM90 uses signed 8-bit values with LSB = 1 degree Celcius.
|
||||
* value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius.
|
||||
* For remote temperatures and limits, it uses signed 11-bit values with
|
||||
* LSB = 0.125 degree Celcius, left-justified in 16-bit registers.
|
||||
* LSB = 0.125 degree Celsius, left-justified in 16-bit registers.
|
||||
*/
|
||||
|
||||
#define TEMP1_FROM_REG(val) ((val) * 1000)
|
||||
@@ -206,9 +206,14 @@ struct lm90_data {
|
||||
int kind;
|
||||
|
||||
/* registers values */
|
||||
s8 temp_input1, temp_low1, temp_high1; /* local */
|
||||
s16 temp_input2, temp_low2, temp_high2; /* remote, combined */
|
||||
s8 temp_crit1, temp_crit2;
|
||||
s8 temp8[5]; /* 0: local input
|
||||
1: local low limit
|
||||
2: local high limit
|
||||
3: local critical limit
|
||||
4: remote critical limit */
|
||||
s16 temp11[3]; /* 0: remote input
|
||||
1: remote low limit
|
||||
2: remote high limit */
|
||||
u8 temp_hyst;
|
||||
u8 alarms; /* bitvector */
|
||||
};
|
||||
@@ -217,75 +222,88 @@ struct lm90_data {
|
||||
* Sysfs stuff
|
||||
*/
|
||||
|
||||
#define show_temp(value, converter) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct lm90_data *data = lm90_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", converter(data->value)); \
|
||||
static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm90_data *data = lm90_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index]));
|
||||
}
|
||||
show_temp(temp_input1, TEMP1_FROM_REG);
|
||||
show_temp(temp_input2, TEMP2_FROM_REG);
|
||||
show_temp(temp_low1, TEMP1_FROM_REG);
|
||||
show_temp(temp_low2, TEMP2_FROM_REG);
|
||||
show_temp(temp_high1, TEMP1_FROM_REG);
|
||||
show_temp(temp_high2, TEMP2_FROM_REG);
|
||||
show_temp(temp_crit1, TEMP1_FROM_REG);
|
||||
show_temp(temp_crit2, TEMP1_FROM_REG);
|
||||
|
||||
#define set_temp1(value, reg) \
|
||||
static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \
|
||||
size_t count) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct lm90_data *data = i2c_get_clientdata(client); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
\
|
||||
down(&data->update_lock); \
|
||||
if (data->kind == adt7461) \
|
||||
data->value = TEMP1_TO_REG_ADT7461(val); \
|
||||
else \
|
||||
data->value = TEMP1_TO_REG(val); \
|
||||
i2c_smbus_write_byte_data(client, reg, data->value); \
|
||||
up(&data->update_lock); \
|
||||
return count; \
|
||||
}
|
||||
#define set_temp2(value, regh, regl) \
|
||||
static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \
|
||||
size_t count) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct lm90_data *data = i2c_get_clientdata(client); \
|
||||
long val = simple_strtol(buf, NULL, 10); \
|
||||
\
|
||||
down(&data->update_lock); \
|
||||
if (data->kind == adt7461) \
|
||||
data->value = TEMP2_TO_REG_ADT7461(val); \
|
||||
else \
|
||||
data->value = TEMP2_TO_REG(val); \
|
||||
i2c_smbus_write_byte_data(client, regh, data->value >> 8); \
|
||||
i2c_smbus_write_byte_data(client, regl, data->value & 0xff); \
|
||||
up(&data->update_lock); \
|
||||
return count; \
|
||||
}
|
||||
set_temp1(temp_low1, LM90_REG_W_LOCAL_LOW);
|
||||
set_temp2(temp_low2, LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL);
|
||||
set_temp1(temp_high1, LM90_REG_W_LOCAL_HIGH);
|
||||
set_temp2(temp_high2, LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL);
|
||||
set_temp1(temp_crit1, LM90_REG_W_LOCAL_CRIT);
|
||||
set_temp1(temp_crit2, LM90_REG_W_REMOTE_CRIT);
|
||||
static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
static const u8 reg[4] = {
|
||||
LM90_REG_W_LOCAL_LOW,
|
||||
LM90_REG_W_LOCAL_HIGH,
|
||||
LM90_REG_W_LOCAL_CRIT,
|
||||
LM90_REG_W_REMOTE_CRIT,
|
||||
};
|
||||
|
||||
#define show_temp_hyst(value, basereg) \
|
||||
static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct lm90_data *data = lm90_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->basereg) \
|
||||
- TEMP1_FROM_REG(data->temp_hyst)); \
|
||||
}
|
||||
show_temp_hyst(temp_hyst1, temp_crit1);
|
||||
show_temp_hyst(temp_hyst2, temp_crit2);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm90_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
int nr = attr->index;
|
||||
|
||||
static ssize_t set_temp_hyst1(struct device *dev, struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
down(&data->update_lock);
|
||||
if (data->kind == adt7461)
|
||||
data->temp8[nr] = TEMP1_TO_REG_ADT7461(val);
|
||||
else
|
||||
data->temp8[nr] = TEMP1_TO_REG(val);
|
||||
i2c_smbus_write_byte_data(client, reg[nr - 1], data->temp8[nr]);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm90_data *data = lm90_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP2_FROM_REG(data->temp11[attr->index]));
|
||||
}
|
||||
|
||||
static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
static const u8 reg[4] = {
|
||||
LM90_REG_W_REMOTE_LOWH,
|
||||
LM90_REG_W_REMOTE_LOWL,
|
||||
LM90_REG_W_REMOTE_HIGHH,
|
||||
LM90_REG_W_REMOTE_HIGHL,
|
||||
};
|
||||
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm90_data *data = i2c_get_clientdata(client);
|
||||
long val = simple_strtol(buf, NULL, 10);
|
||||
int nr = attr->index;
|
||||
|
||||
down(&data->update_lock);
|
||||
if (data->kind == adt7461)
|
||||
data->temp11[nr] = TEMP2_TO_REG_ADT7461(val);
|
||||
else
|
||||
data->temp11[nr] = TEMP2_TO_REG(val);
|
||||
i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
|
||||
data->temp11[nr] >> 8);
|
||||
i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
|
||||
data->temp11[nr] & 0xff);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_temphyst(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct lm90_data *data = lm90_update_device(dev);
|
||||
return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp8[attr->index])
|
||||
- TEMP1_FROM_REG(data->temp_hyst));
|
||||
}
|
||||
|
||||
static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct lm90_data *data = i2c_get_clientdata(client);
|
||||
@@ -293,36 +311,37 @@ static ssize_t set_temp_hyst1(struct device *dev, struct device_attribute *attr,
|
||||
long hyst;
|
||||
|
||||
down(&data->update_lock);
|
||||
hyst = TEMP1_FROM_REG(data->temp_crit1) - val;
|
||||
hyst = TEMP1_FROM_REG(data->temp8[3]) - val;
|
||||
i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST,
|
||||
HYST_TO_REG(hyst));
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
|
||||
char *buf)
|
||||
{
|
||||
struct lm90_data *data = lm90_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->alarms);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
|
||||
static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL);
|
||||
static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_low1,
|
||||
set_temp_low1);
|
||||
static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_low2,
|
||||
set_temp_low2);
|
||||
static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_high1,
|
||||
set_temp_high1);
|
||||
static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_high2,
|
||||
set_temp_high2);
|
||||
static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_crit1,
|
||||
set_temp_crit1);
|
||||
static DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit2,
|
||||
set_temp_crit2);
|
||||
static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst1,
|
||||
set_temp_hyst1);
|
||||
static DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_hyst2, NULL);
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8,
|
||||
set_temp8, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
|
||||
set_temp11, 1);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8,
|
||||
set_temp8, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
|
||||
set_temp11, 2);
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8,
|
||||
set_temp8, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8,
|
||||
set_temp8, 4);
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst,
|
||||
set_temphyst, 3);
|
||||
static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4);
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
/*
|
||||
@@ -481,16 +500,26 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
lm90_init_client(new_client);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_min);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_max);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_crit);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_crit);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
|
||||
device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_input.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_min.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_min.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_max.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_crit.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_crit.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp1_crit_hyst.dev_attr);
|
||||
device_create_file(&new_client->dev,
|
||||
&sensor_dev_attr_temp2_crit_hyst.dev_attr);
|
||||
device_create_file(&new_client->dev, &dev_attr_alarms);
|
||||
|
||||
return 0;
|
||||
@@ -541,16 +570,16 @@ static struct lm90_data *lm90_update_device(struct device *dev)
|
||||
u8 oldh, newh;
|
||||
|
||||
dev_dbg(&client->dev, "Updating lm90 data.\n");
|
||||
data->temp_input1 = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_LOCAL_TEMP);
|
||||
data->temp_high1 = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_LOCAL_HIGH);
|
||||
data->temp_low1 = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_LOCAL_LOW);
|
||||
data->temp_crit1 = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_LOCAL_CRIT);
|
||||
data->temp_crit2 = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_REMOTE_CRIT);
|
||||
data->temp8[0] = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_LOCAL_TEMP);
|
||||
data->temp8[1] = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_LOCAL_LOW);
|
||||
data->temp8[2] = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_LOCAL_HIGH);
|
||||
data->temp8[3] = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_LOCAL_CRIT);
|
||||
data->temp8[4] = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_REMOTE_CRIT);
|
||||
data->temp_hyst = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_TCRIT_HYST);
|
||||
|
||||
@@ -570,13 +599,13 @@ static struct lm90_data *lm90_update_device(struct device *dev)
|
||||
*/
|
||||
oldh = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_REMOTE_TEMPH);
|
||||
data->temp_input2 = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_REMOTE_TEMPL);
|
||||
data->temp11[0] = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_REMOTE_TEMPL);
|
||||
newh = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_REMOTE_TEMPH);
|
||||
if (newh != oldh) {
|
||||
data->temp_input2 = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_REMOTE_TEMPL);
|
||||
data->temp11[0] = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_REMOTE_TEMPL);
|
||||
#ifdef DEBUG
|
||||
oldh = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_REMOTE_TEMPH);
|
||||
@@ -586,16 +615,16 @@ static struct lm90_data *lm90_update_device(struct device *dev)
|
||||
"wrong.\n");
|
||||
#endif
|
||||
}
|
||||
data->temp_input2 |= (newh << 8);
|
||||
data->temp11[0] |= (newh << 8);
|
||||
|
||||
data->temp_high2 = (i2c_smbus_read_byte_data(client,
|
||||
data->temp11[1] = (i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_REMOTE_LOWH) << 8) +
|
||||
i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_REMOTE_LOWL);
|
||||
data->temp11[2] = (i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_REMOTE_HIGHH) << 8) +
|
||||
i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_REMOTE_HIGHL);
|
||||
data->temp_low2 = (i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_REMOTE_LOWH) << 8) +
|
||||
i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_REMOTE_LOWL);
|
||||
data->alarms = i2c_smbus_read_byte_data(client,
|
||||
LM90_REG_R_STATUS);
|
||||
|
||||
|
||||
@@ -40,11 +40,8 @@ static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END };
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_addr,
|
||||
.normal_i2c_range = ignore,
|
||||
.probe = ignore,
|
||||
.probe_range = ignore,
|
||||
.ignore = ignore,
|
||||
.ignore_range = ignore,
|
||||
.force = ignore,
|
||||
};
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
473
drivers/i2c/chips/max6875.c
Normal file
473
drivers/i2c/chips/max6875.c
Normal file
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
max6875.c - driver for MAX6874/MAX6875
|
||||
|
||||
Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
|
||||
|
||||
Based on i2c/chips/eeprom.c
|
||||
|
||||
The MAX6875 has two EEPROM sections: config and user.
|
||||
At reset, the config EEPROM is read into the registers.
|
||||
|
||||
This driver make 3 binary files available in sysfs:
|
||||
reg_config - direct access to the registers
|
||||
eeprom_config - acesses configuration eeprom space
|
||||
eeprom_user - free for application use
|
||||
|
||||
In our application, we put device serial & model numbers in user eeprom.
|
||||
|
||||
Notes:
|
||||
1) The datasheet says that register 0x44 / EEPROM 0x8044 should NOT
|
||||
be overwritten, so the driver explicitly prevents that.
|
||||
2) It's a good idea to keep the config (0x45) locked in config EEPROM.
|
||||
You can temporarily enable config writes by changing register 0x45.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = {0x50, 0x52, I2C_CLIENT_END};
|
||||
static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END};
|
||||
|
||||
/* Insmod parameters */
|
||||
SENSORS_INSMOD_1(max6875);
|
||||
|
||||
/* this param will prevent 'accidental' writes to the eeprom */
|
||||
static int allow_write = 0;
|
||||
module_param(allow_write, int, 0);
|
||||
MODULE_PARM_DESC(allow_write,
|
||||
"Enable write access:\n"
|
||||
"*0: Read only\n"
|
||||
" 1: Read/Write access");
|
||||
|
||||
/* The MAX6875 can only read/write 16 bytes at a time */
|
||||
#define SLICE_SIZE 16
|
||||
#define SLICE_BITS 4
|
||||
|
||||
/* CONFIG EEPROM is at addresses 0x8000 - 0x8045, registers are at 0 - 0x45 */
|
||||
#define CONFIG_EEPROM_BASE 0x8000
|
||||
#define CONFIG_EEPROM_SIZE 0x0046
|
||||
#define CONFIG_EEPROM_SLICES 5
|
||||
|
||||
/* USER EEPROM is at addresses 0x8100 - 0x82FF */
|
||||
#define USER_EEPROM_BASE 0x8100
|
||||
#define USER_EEPROM_SIZE 0x0200
|
||||
#define USER_EEPROM_SLICES 32
|
||||
|
||||
/* MAX6875 commands */
|
||||
#define MAX6875_CMD_BLOCK_WRITE 0x83
|
||||
#define MAX6875_CMD_BLOCK_READ 0x84
|
||||
#define MAX6875_CMD_REBOOT 0x88
|
||||
|
||||
enum max6875_area_type {
|
||||
max6875_register_config=0,
|
||||
max6875_eeprom_config,
|
||||
max6875_eeprom_user,
|
||||
max6857_max
|
||||
};
|
||||
|
||||
struct eeprom_block {
|
||||
enum max6875_area_type type;
|
||||
u8 slices;
|
||||
u32 size;
|
||||
u32 valid;
|
||||
u32 base;
|
||||
unsigned long *updated;
|
||||
u8 *data;
|
||||
};
|
||||
|
||||
/* Each client has this additional data */
|
||||
struct max6875_data {
|
||||
struct i2c_client client;
|
||||
struct semaphore update_lock;
|
||||
struct eeprom_block blocks[max6857_max];
|
||||
/* the above structs point into the arrays below */
|
||||
u8 data[USER_EEPROM_SIZE + (CONFIG_EEPROM_SIZE*2)];
|
||||
unsigned long last_updated[USER_EEPROM_SLICES + (CONFIG_EEPROM_SLICES*2)];
|
||||
};
|
||||
|
||||
static int max6875_attach_adapter(struct i2c_adapter *adapter);
|
||||
static int max6875_detect(struct i2c_adapter *adapter, int address, int kind);
|
||||
static int max6875_detach_client(struct i2c_client *client);
|
||||
|
||||
/* This is the driver that will be inserted */
|
||||
static struct i2c_driver max6875_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "max6875",
|
||||
.flags = I2C_DF_NOTIFY,
|
||||
.attach_adapter = max6875_attach_adapter,
|
||||
.detach_client = max6875_detach_client,
|
||||
};
|
||||
|
||||
static int max6875_update_slice(struct i2c_client *client,
|
||||
struct eeprom_block *blk,
|
||||
int slice)
|
||||
{
|
||||
struct max6875_data *data = i2c_get_clientdata(client);
|
||||
int i, j, addr, count;
|
||||
u8 rdbuf[SLICE_SIZE];
|
||||
int retval = 0;
|
||||
|
||||
if (slice >= blk->slices)
|
||||
return -1;
|
||||
|
||||
down(&data->update_lock);
|
||||
|
||||
if (!(blk->valid & (1 << slice)) ||
|
||||
(jiffies - blk->updated[slice] > 300 * HZ) ||
|
||||
(jiffies < blk->updated[slice])) {
|
||||
dev_dbg(&client->dev, "Starting eeprom update, slice %u, base %u\n",
|
||||
slice, blk->base);
|
||||
|
||||
addr = blk->base + (slice << SLICE_BITS);
|
||||
count = blk->size - (slice << SLICE_BITS);
|
||||
if (count > SLICE_SIZE) {
|
||||
count = SLICE_SIZE;
|
||||
}
|
||||
|
||||
/* Preset the read address */
|
||||
if (addr < 0x100) {
|
||||
/* select the register */
|
||||
if (i2c_smbus_write_byte(client, addr & 0xFF)) {
|
||||
dev_dbg(&client->dev, "max6875 register select has failed!\n");
|
||||
retval = -1;
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
/* select the eeprom */
|
||||
if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) {
|
||||
dev_dbg(&client->dev, "max6875 address set has failed!\n");
|
||||
retval = -1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
|
||||
if (i2c_smbus_read_i2c_block_data(client, MAX6875_CMD_BLOCK_READ,
|
||||
rdbuf) != SLICE_SIZE)
|
||||
{
|
||||
retval = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
memcpy(&blk->data[slice << SLICE_BITS], rdbuf, count);
|
||||
} else {
|
||||
for (i = 0; i < count; i++) {
|
||||
j = i2c_smbus_read_byte(client);
|
||||
if (j < 0)
|
||||
{
|
||||
retval = -1;
|
||||
goto exit;
|
||||
}
|
||||
blk->data[(slice << SLICE_BITS) + i] = (u8) j;
|
||||
}
|
||||
}
|
||||
blk->updated[slice] = jiffies;
|
||||
blk->valid |= (1 << slice);
|
||||
}
|
||||
exit:
|
||||
up(&data->update_lock);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off, size_t count,
|
||||
enum max6875_area_type area_type)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
|
||||
struct max6875_data *data = i2c_get_clientdata(client);
|
||||
struct eeprom_block *blk;
|
||||
int slice;
|
||||
|
||||
blk = &data->blocks[area_type];
|
||||
|
||||
if (off > blk->size)
|
||||
return 0;
|
||||
if (off + count > blk->size)
|
||||
count = blk->size - off;
|
||||
|
||||
/* Only refresh slices which contain requested bytes */
|
||||
for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++)
|
||||
max6875_update_slice(client, blk, slice);
|
||||
|
||||
memcpy(buf, &blk->data[off], count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t max6875_user_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
{
|
||||
return max6875_read(kobj, buf, off, count, max6875_eeprom_user);
|
||||
}
|
||||
|
||||
static ssize_t max6875_config_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
{
|
||||
return max6875_read(kobj, buf, off, count, max6875_eeprom_config);
|
||||
}
|
||||
|
||||
static ssize_t max6875_cfgreg_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
{
|
||||
return max6875_read(kobj, buf, off, count, max6875_register_config);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t max6875_write(struct kobject *kobj, char *buf, loff_t off, size_t count,
|
||||
enum max6875_area_type area_type)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
|
||||
struct max6875_data *data = i2c_get_clientdata(client);
|
||||
struct eeprom_block *blk;
|
||||
int slice, addr, retval;
|
||||
ssize_t sent = 0;
|
||||
|
||||
blk = &data->blocks[area_type];
|
||||
|
||||
if (off > blk->size)
|
||||
return 0;
|
||||
if ((off + count) > blk->size)
|
||||
count = blk->size - off;
|
||||
|
||||
if (down_interruptible(&data->update_lock))
|
||||
return -EAGAIN;
|
||||
|
||||
/* writing to a register is done with i2c_smbus_write_byte_data() */
|
||||
if (blk->type == max6875_register_config) {
|
||||
for (sent = 0; sent < count; sent++) {
|
||||
addr = off + sent;
|
||||
if (addr == 0x44)
|
||||
continue;
|
||||
|
||||
retval = i2c_smbus_write_byte_data(client, addr, buf[sent]);
|
||||
}
|
||||
} else {
|
||||
int cmd, val;
|
||||
|
||||
/* We are writing to EEPROM */
|
||||
for (sent = 0; sent < count; sent++) {
|
||||
addr = blk->base + off + sent;
|
||||
cmd = addr >> 8;
|
||||
val = (addr & 0xff) | (buf[sent] << 8); // reversed
|
||||
|
||||
if (addr == 0x8044)
|
||||
continue;
|
||||
|
||||
retval = i2c_smbus_write_word_data(client, cmd, val);
|
||||
|
||||
if (retval) {
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
/* A write takes up to 11 ms */
|
||||
msleep(11);
|
||||
}
|
||||
}
|
||||
|
||||
/* Invalidate the scratch buffer */
|
||||
for (slice = (off >> SLICE_BITS); slice <= ((off + count - 1) >> SLICE_BITS); slice++)
|
||||
blk->valid &= ~(1 << slice);
|
||||
|
||||
error_exit:
|
||||
up(&data->update_lock);
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
static ssize_t max6875_user_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
{
|
||||
return max6875_write(kobj, buf, off, count, max6875_eeprom_user);
|
||||
}
|
||||
|
||||
static ssize_t max6875_config_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
{
|
||||
return max6875_write(kobj, buf, off, count, max6875_eeprom_config);
|
||||
}
|
||||
|
||||
static ssize_t max6875_cfgreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
|
||||
{
|
||||
return max6875_write(kobj, buf, off, count, max6875_register_config);
|
||||
}
|
||||
|
||||
static struct bin_attribute user_eeprom_attr = {
|
||||
.attr = {
|
||||
.name = "eeprom_user",
|
||||
.mode = S_IRUGO | S_IWUSR | S_IWGRP,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = USER_EEPROM_SIZE,
|
||||
.read = max6875_user_read,
|
||||
.write = max6875_user_write,
|
||||
};
|
||||
|
||||
static struct bin_attribute config_eeprom_attr = {
|
||||
.attr = {
|
||||
.name = "eeprom_config",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = CONFIG_EEPROM_SIZE,
|
||||
.read = max6875_config_read,
|
||||
.write = max6875_config_write,
|
||||
};
|
||||
|
||||
static struct bin_attribute config_register_attr = {
|
||||
.attr = {
|
||||
.name = "reg_config",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.size = CONFIG_EEPROM_SIZE,
|
||||
.read = max6875_cfgreg_read,
|
||||
.write = max6875_cfgreg_write,
|
||||
};
|
||||
|
||||
static int max6875_attach_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
return i2c_detect(adapter, &addr_data, max6875_detect);
|
||||
}
|
||||
|
||||
/* This function is called by i2c_detect */
|
||||
static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
struct i2c_client *new_client;
|
||||
struct max6875_data *data;
|
||||
int err = 0;
|
||||
|
||||
/* There are three ways we can read the EEPROM data:
|
||||
(1) I2C block reads (faster, but unsupported by most adapters)
|
||||
(2) Consecutive byte reads (100% overhead)
|
||||
(3) Regular byte data reads (200% overhead)
|
||||
The third method is not implemented by this driver because all
|
||||
known adapters support at least the second. */
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_BYTE |
|
||||
I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
|
||||
goto exit;
|
||||
|
||||
/* 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 eeprom_{read,write}_value. */
|
||||
if (!(data = kmalloc(sizeof(struct max6875_data), GFP_KERNEL))) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
memset(data, 0, sizeof(struct max6875_data));
|
||||
|
||||
new_client = &data->client;
|
||||
i2c_set_clientdata(new_client, data);
|
||||
new_client->addr = address;
|
||||
new_client->adapter = adapter;
|
||||
new_client->driver = &max6875_driver;
|
||||
new_client->flags = 0;
|
||||
|
||||
/* Setup the user section */
|
||||
data->blocks[max6875_eeprom_user].type = max6875_eeprom_user;
|
||||
data->blocks[max6875_eeprom_user].slices = USER_EEPROM_SLICES;
|
||||
data->blocks[max6875_eeprom_user].size = USER_EEPROM_SIZE;
|
||||
data->blocks[max6875_eeprom_user].base = USER_EEPROM_BASE;
|
||||
data->blocks[max6875_eeprom_user].data = data->data;
|
||||
data->blocks[max6875_eeprom_user].updated = data->last_updated;
|
||||
|
||||
/* Setup the config section */
|
||||
data->blocks[max6875_eeprom_config].type = max6875_eeprom_config;
|
||||
data->blocks[max6875_eeprom_config].slices = CONFIG_EEPROM_SLICES;
|
||||
data->blocks[max6875_eeprom_config].size = CONFIG_EEPROM_SIZE;
|
||||
data->blocks[max6875_eeprom_config].base = CONFIG_EEPROM_BASE;
|
||||
data->blocks[max6875_eeprom_config].data = &data->data[USER_EEPROM_SIZE];
|
||||
data->blocks[max6875_eeprom_config].updated = &data->last_updated[USER_EEPROM_SLICES];
|
||||
|
||||
/* Setup the register section */
|
||||
data->blocks[max6875_register_config].type = max6875_register_config;
|
||||
data->blocks[max6875_register_config].slices = CONFIG_EEPROM_SLICES;
|
||||
data->blocks[max6875_register_config].size = CONFIG_EEPROM_SIZE;
|
||||
data->blocks[max6875_register_config].base = 0;
|
||||
data->blocks[max6875_register_config].data = &data->data[USER_EEPROM_SIZE+CONFIG_EEPROM_SIZE];
|
||||
data->blocks[max6875_register_config].updated = &data->last_updated[USER_EEPROM_SLICES+CONFIG_EEPROM_SLICES];
|
||||
|
||||
/* Init the data */
|
||||
memset(data->data, 0xff, sizeof(data->data));
|
||||
|
||||
/* Fill in the remaining client fields */
|
||||
strlcpy(new_client->name, "max6875", I2C_NAME_SIZE);
|
||||
init_MUTEX(&data->update_lock);
|
||||
|
||||
/* Verify that the chip is really what we think it is */
|
||||
if ((max6875_update_slice(new_client, &data->blocks[max6875_eeprom_config], 4) < 0) ||
|
||||
(max6875_update_slice(new_client, &data->blocks[max6875_register_config], 4) < 0))
|
||||
goto exit_kfree;
|
||||
|
||||
/* 0x41,0x42 must be zero and 0x40 must match in eeprom and registers */
|
||||
if ((data->blocks[max6875_eeprom_config].data[0x41] != 0) ||
|
||||
(data->blocks[max6875_eeprom_config].data[0x42] != 0) ||
|
||||
(data->blocks[max6875_register_config].data[0x41] != 0) ||
|
||||
(data->blocks[max6875_register_config].data[0x42] != 0) ||
|
||||
(data->blocks[max6875_eeprom_config].data[0x40] !=
|
||||
data->blocks[max6875_register_config].data[0x40]))
|
||||
goto exit_kfree;
|
||||
|
||||
/* Tell the I2C layer a new client has arrived */
|
||||
if ((err = i2c_attach_client(new_client)))
|
||||
goto exit_kfree;
|
||||
|
||||
/* create the sysfs eeprom files with the correct permissions */
|
||||
if (allow_write == 0) {
|
||||
user_eeprom_attr.attr.mode &= ~S_IWUGO;
|
||||
user_eeprom_attr.write = NULL;
|
||||
config_eeprom_attr.attr.mode &= ~S_IWUGO;
|
||||
config_eeprom_attr.write = NULL;
|
||||
config_register_attr.attr.mode &= ~S_IWUGO;
|
||||
config_register_attr.write = NULL;
|
||||
}
|
||||
sysfs_create_bin_file(&new_client->dev.kobj, &user_eeprom_attr);
|
||||
sysfs_create_bin_file(&new_client->dev.kobj, &config_eeprom_attr);
|
||||
sysfs_create_bin_file(&new_client->dev.kobj, &config_register_attr);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_kfree:
|
||||
kfree(data);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int max6875_detach_client(struct i2c_client *client)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = i2c_detach_client(client);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "Client deregistration failed, client not detached.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree(i2c_get_clientdata(client));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init max6875_init(void)
|
||||
{
|
||||
return i2c_add_driver(&max6875_driver);
|
||||
}
|
||||
|
||||
static void __exit max6875_exit(void)
|
||||
{
|
||||
i2c_del_driver(&max6875_driver);
|
||||
}
|
||||
|
||||
|
||||
MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
|
||||
MODULE_DESCRIPTION("MAX6875 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(max6875_init);
|
||||
module_exit(max6875_exit);
|
||||
@@ -33,7 +33,6 @@
|
||||
* the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F).
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
192
drivers/i2c/chips/pca9539.c
Normal file
192
drivers/i2c/chips/pca9539.c
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
pca9539.c - 16-bit I/O port with interrupt and reset
|
||||
|
||||
Copyright (C) 2005 Ben Gardner <bgardner@wabtec.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 of the License.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = {0x74, 0x75, 0x76, 0x77, I2C_CLIENT_END};
|
||||
static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END};
|
||||
|
||||
/* Insmod parameters */
|
||||
SENSORS_INSMOD_1(pca9539);
|
||||
|
||||
enum pca9539_cmd
|
||||
{
|
||||
PCA9539_INPUT_0 = 0,
|
||||
PCA9539_INPUT_1 = 1,
|
||||
PCA9539_OUTPUT_0 = 2,
|
||||
PCA9539_OUTPUT_1 = 3,
|
||||
PCA9539_INVERT_0 = 4,
|
||||
PCA9539_INVERT_1 = 5,
|
||||
PCA9539_DIRECTION_0 = 6,
|
||||
PCA9539_DIRECTION_1 = 7,
|
||||
};
|
||||
|
||||
static int pca9539_attach_adapter(struct i2c_adapter *adapter);
|
||||
static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind);
|
||||
static int pca9539_detach_client(struct i2c_client *client);
|
||||
|
||||
/* This is the driver that will be inserted */
|
||||
static struct i2c_driver pca9539_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "pca9539",
|
||||
.flags = I2C_DF_NOTIFY,
|
||||
.attach_adapter = pca9539_attach_adapter,
|
||||
.detach_client = pca9539_detach_client,
|
||||
};
|
||||
|
||||
struct pca9539_data {
|
||||
struct i2c_client client;
|
||||
};
|
||||
|
||||
/* following are the sysfs callback functions */
|
||||
static ssize_t pca9539_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *psa = to_sensor_dev_attr(attr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
return sprintf(buf, "%d\n", i2c_smbus_read_byte_data(client,
|
||||
psa->index));
|
||||
}
|
||||
|
||||
static ssize_t pca9539_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *psa = to_sensor_dev_attr(attr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 0);
|
||||
if (val > 0xff)
|
||||
return -EINVAL;
|
||||
i2c_smbus_write_byte_data(client, psa->index, val);
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Define the device attributes */
|
||||
|
||||
#define PCA9539_ENTRY_RO(name, cmd_idx) \
|
||||
static SENSOR_DEVICE_ATTR(name, S_IRUGO, pca9539_show, NULL, cmd_idx)
|
||||
|
||||
#define PCA9539_ENTRY_RW(name, cmd_idx) \
|
||||
static SENSOR_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, pca9539_show, \
|
||||
pca9539_store, cmd_idx)
|
||||
|
||||
PCA9539_ENTRY_RO(input0, PCA9539_INPUT_0);
|
||||
PCA9539_ENTRY_RO(input1, PCA9539_INPUT_1);
|
||||
PCA9539_ENTRY_RW(output0, PCA9539_OUTPUT_0);
|
||||
PCA9539_ENTRY_RW(output1, PCA9539_OUTPUT_1);
|
||||
PCA9539_ENTRY_RW(invert0, PCA9539_INVERT_0);
|
||||
PCA9539_ENTRY_RW(invert1, PCA9539_INVERT_1);
|
||||
PCA9539_ENTRY_RW(direction0, PCA9539_DIRECTION_0);
|
||||
PCA9539_ENTRY_RW(direction1, PCA9539_DIRECTION_1);
|
||||
|
||||
static struct attribute *pca9539_attributes[] = {
|
||||
&sensor_dev_attr_input0.dev_attr.attr,
|
||||
&sensor_dev_attr_input1.dev_attr.attr,
|
||||
&sensor_dev_attr_output0.dev_attr.attr,
|
||||
&sensor_dev_attr_output1.dev_attr.attr,
|
||||
&sensor_dev_attr_invert0.dev_attr.attr,
|
||||
&sensor_dev_attr_invert1.dev_attr.attr,
|
||||
&sensor_dev_attr_direction0.dev_attr.attr,
|
||||
&sensor_dev_attr_direction1.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group pca9539_defattr_group = {
|
||||
.attrs = pca9539_attributes,
|
||||
};
|
||||
|
||||
static int pca9539_attach_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
return i2c_detect(adapter, &addr_data, pca9539_detect);
|
||||
}
|
||||
|
||||
/* This function is called by i2c_detect */
|
||||
static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
struct i2c_client *new_client;
|
||||
struct pca9539_data *data;
|
||||
int err = 0;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
goto exit;
|
||||
|
||||
/* OK. For now, we presume we have a valid client. We now create the
|
||||
client structure, even though we cannot fill it completely yet. */
|
||||
if (!(data = kmalloc(sizeof(struct pca9539_data), GFP_KERNEL))) {
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
memset(data, 0, sizeof(struct pca9539_data));
|
||||
|
||||
new_client = &data->client;
|
||||
i2c_set_clientdata(new_client, data);
|
||||
new_client->addr = address;
|
||||
new_client->adapter = adapter;
|
||||
new_client->driver = &pca9539_driver;
|
||||
new_client->flags = 0;
|
||||
|
||||
/* Detection: the pca9539 only has 8 registers (0-7).
|
||||
A read of 7 should succeed, but a read of 8 should fail. */
|
||||
if ((i2c_smbus_read_byte_data(new_client, 7) < 0) ||
|
||||
(i2c_smbus_read_byte_data(new_client, 8) >= 0))
|
||||
goto exit_kfree;
|
||||
|
||||
strlcpy(new_client->name, "pca9539", I2C_NAME_SIZE);
|
||||
|
||||
/* Tell the I2C layer a new client has arrived */
|
||||
if ((err = i2c_attach_client(new_client)))
|
||||
goto exit_kfree;
|
||||
|
||||
/* Register sysfs hooks (don't care about failure) */
|
||||
sysfs_create_group(&new_client->dev.kobj, &pca9539_defattr_group);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_kfree:
|
||||
kfree(data);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int pca9539_detach_client(struct i2c_client *client)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = i2c_detach_client(client))) {
|
||||
dev_err(&client->dev, "Client deregistration failed.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init pca9539_init(void)
|
||||
{
|
||||
return i2c_add_driver(&pca9539_driver);
|
||||
}
|
||||
|
||||
static void __exit pca9539_exit(void)
|
||||
{
|
||||
i2c_del_driver(&pca9539_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
|
||||
MODULE_DESCRIPTION("PCA9539 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(pca9539_init);
|
||||
module_exit(pca9539_exit);
|
||||
|
||||
@@ -57,7 +57,7 @@ SENSORS_INSMOD_2(pcf8574, pcf8574a);
|
||||
struct pcf8574_data {
|
||||
struct i2c_client client;
|
||||
|
||||
u8 read, write; /* Register values */
|
||||
u8 write; /* Remember last written value */
|
||||
};
|
||||
|
||||
static int pcf8574_attach_adapter(struct i2c_adapter *adapter);
|
||||
@@ -79,9 +79,7 @@ static struct i2c_driver pcf8574_driver = {
|
||||
static ssize_t show_read(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pcf8574_data *data = i2c_get_clientdata(client);
|
||||
data->read = i2c_smbus_read_byte(client);
|
||||
return sprintf(buf, "%u\n", data->read);
|
||||
return sprintf(buf, "%u\n", i2c_smbus_read_byte(client));
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(read, S_IRUGO, show_read, NULL);
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/rtc.h> /* get the user-level API */
|
||||
#include <linux/init.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include "rtc8564.h"
|
||||
|
||||
@@ -66,11 +65,8 @@ static unsigned short normal_addr[] = { 0x51, I2C_CLIENT_END };
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_addr,
|
||||
.normal_i2c_range = ignore,
|
||||
.probe = ignore,
|
||||
.probe_range = ignore,
|
||||
.ignore = ignore,
|
||||
.ignore_range = ignore,
|
||||
.force = ignore,
|
||||
};
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
|
||||
|
||||
@@ -372,14 +372,16 @@ static int smsc47m1_find(int *address)
|
||||
* SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id
|
||||
* 0x5F) and LPC47B27x (device id 0x51) have fan control.
|
||||
* The LPC47M15x and LPC47M192 chips "with hardware monitoring block"
|
||||
* can do much more besides (device id 0x60, unsupported).
|
||||
* can do much more besides (device id 0x60).
|
||||
*/
|
||||
if (val == 0x51)
|
||||
printk(KERN_INFO "smsc47m1: Found SMSC47B27x\n");
|
||||
printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n");
|
||||
else if (val == 0x59)
|
||||
printk(KERN_INFO "smsc47m1: Found SMSC47M10x/SMSC47M13x\n");
|
||||
printk(KERN_INFO "smsc47m1: Found SMSC LPC47M10x/LPC47M13x\n");
|
||||
else if (val == 0x5F)
|
||||
printk(KERN_INFO "smsc47m1: Found SMSC47M14x\n");
|
||||
printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n");
|
||||
else if (val == 0x60)
|
||||
printk(KERN_INFO "smsc47m1: Found SMSC LPC47M15x/LPC47M192\n");
|
||||
else {
|
||||
superio_exit();
|
||||
return -ENODEV;
|
||||
|
||||
1072
drivers/i2c/chips/tps65010.c
Normal file
1072
drivers/i2c/chips/tps65010.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
via686a.c - Part of lm_sensors, Linux kernel modules
|
||||
for hardware monitoring
|
||||
|
||||
|
||||
Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
|
||||
Ky<4B>sti M<>lkki <kmalkki@cc.hut.fi>,
|
||||
Mark Studebaker <mdsxyz123@yahoo.com>,
|
||||
and Bob Dougherty <bobd@stanford.edu>
|
||||
(Some conversion-factor data were contributed by Jonathan Teh Soon Yew
|
||||
(Some conversion-factor data were contributed by Jonathan Teh Soon Yew
|
||||
<j.teh@iname.com> and Alex van Kaam <darkside@chello.nl>.)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
@@ -30,11 +30,9 @@
|
||||
Warning - only supports a single device.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
@@ -66,49 +64,46 @@ SENSORS_INSMOD_1(via686a);
|
||||
/* Many VIA686A constants specified below */
|
||||
|
||||
/* Length of ISA address segment */
|
||||
#define VIA686A_EXTENT 0x80
|
||||
#define VIA686A_BASE_REG 0x70
|
||||
#define VIA686A_ENABLE_REG 0x74
|
||||
#define VIA686A_EXTENT 0x80
|
||||
#define VIA686A_BASE_REG 0x70
|
||||
#define VIA686A_ENABLE_REG 0x74
|
||||
|
||||
/* The VIA686A registers */
|
||||
/* ins numbered 0-4 */
|
||||
#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2))
|
||||
#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2))
|
||||
#define VIA686A_REG_IN(nr) (0x22 + (nr))
|
||||
#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2))
|
||||
#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2))
|
||||
#define VIA686A_REG_IN(nr) (0x22 + (nr))
|
||||
|
||||
/* fans numbered 1-2 */
|
||||
#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr))
|
||||
#define VIA686A_REG_FAN(nr) (0x28 + (nr))
|
||||
|
||||
/* the following values are as speced by VIA: */
|
||||
static const u8 regtemp[] = { 0x20, 0x21, 0x1f };
|
||||
static const u8 regover[] = { 0x39, 0x3d, 0x1d };
|
||||
static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e };
|
||||
#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr))
|
||||
#define VIA686A_REG_FAN(nr) (0x28 + (nr))
|
||||
|
||||
/* temps numbered 1-3 */
|
||||
#define VIA686A_REG_TEMP(nr) (regtemp[nr])
|
||||
#define VIA686A_REG_TEMP_OVER(nr) (regover[nr])
|
||||
#define VIA686A_REG_TEMP_HYST(nr) (reghyst[nr])
|
||||
#define VIA686A_REG_TEMP_LOW1 0x4b // bits 7-6
|
||||
#define VIA686A_REG_TEMP_LOW23 0x49 // 2 = bits 5-4, 3 = bits 7-6
|
||||
static const u8 VIA686A_REG_TEMP[] = { 0x20, 0x21, 0x1f };
|
||||
static const u8 VIA686A_REG_TEMP_OVER[] = { 0x39, 0x3d, 0x1d };
|
||||
static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e };
|
||||
/* bits 7-6 */
|
||||
#define VIA686A_REG_TEMP_LOW1 0x4b
|
||||
/* 2 = bits 5-4, 3 = bits 7-6 */
|
||||
#define VIA686A_REG_TEMP_LOW23 0x49
|
||||
|
||||
#define VIA686A_REG_ALARM1 0x41
|
||||
#define VIA686A_REG_ALARM2 0x42
|
||||
#define VIA686A_REG_FANDIV 0x47
|
||||
#define VIA686A_REG_CONFIG 0x40
|
||||
/* The following register sets temp interrupt mode (bits 1-0 for temp1,
|
||||
#define VIA686A_REG_ALARM1 0x41
|
||||
#define VIA686A_REG_ALARM2 0x42
|
||||
#define VIA686A_REG_FANDIV 0x47
|
||||
#define VIA686A_REG_CONFIG 0x40
|
||||
/* The following register sets temp interrupt mode (bits 1-0 for temp1,
|
||||
3-2 for temp2, 5-4 for temp3). Modes are:
|
||||
00 interrupt stays as long as value is out-of-range
|
||||
01 interrupt is cleared once register is read (default)
|
||||
10 comparator mode- like 00, but ignores hysteresis
|
||||
11 same as 00 */
|
||||
#define VIA686A_REG_TEMP_MODE 0x4b
|
||||
#define VIA686A_REG_TEMP_MODE 0x4b
|
||||
/* We'll just assume that you want to set all 3 simultaneously: */
|
||||
#define VIA686A_TEMP_MODE_MASK 0x3F
|
||||
#define VIA686A_TEMP_MODE_CONTINUOUS (0x00)
|
||||
#define VIA686A_TEMP_MODE_MASK 0x3F
|
||||
#define VIA686A_TEMP_MODE_CONTINUOUS 0x00
|
||||
|
||||
/* Conversions. Limit checking is only done on the TO_REG
|
||||
variants.
|
||||
variants.
|
||||
|
||||
********* VOLTAGE CONVERSIONS (Bob Dougherty) ********
|
||||
From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew):
|
||||
@@ -121,7 +116,7 @@ static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e };
|
||||
That is:
|
||||
volts = (25*regVal+133)*factor
|
||||
regVal = (volts/factor-133)/25
|
||||
(These conversions were contributed by Jonathan Teh Soon Yew
|
||||
(These conversions were contributed by Jonathan Teh Soon Yew
|
||||
<j.teh@iname.com>) */
|
||||
static inline u8 IN_TO_REG(long val, int inNum)
|
||||
{
|
||||
@@ -182,55 +177,55 @@ static inline u8 FAN_TO_REG(long rpm, int div)
|
||||
else
|
||||
return double(temp)*0.924-127.33;
|
||||
|
||||
A fifth-order polynomial fits the unofficial data (provided by Alex van
|
||||
Kaam <darkside@chello.nl>) a bit better. It also give more reasonable
|
||||
numbers on my machine (ie. they agree with what my BIOS tells me).
|
||||
A fifth-order polynomial fits the unofficial data (provided by Alex van
|
||||
Kaam <darkside@chello.nl>) a bit better. It also give more reasonable
|
||||
numbers on my machine (ie. they agree with what my BIOS tells me).
|
||||
Here's the fifth-order fit to the 8-bit data:
|
||||
temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 -
|
||||
temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 -
|
||||
2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0.
|
||||
|
||||
(2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for
|
||||
(2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for
|
||||
finding my typos in this formula!)
|
||||
|
||||
Alas, none of the elegant function-fit solutions will work because we
|
||||
aren't allowed to use floating point in the kernel and doing it with
|
||||
integers doesn't rpovide enough precision. So we'll do boring old
|
||||
look-up table stuff. The unofficial data (see below) have effectively
|
||||
7-bit resolution (they are rounded to the nearest degree). I'm assuming
|
||||
that the transfer function of the device is monotonic and smooth, so a
|
||||
smooth function fit to the data will allow us to get better precision.
|
||||
Alas, none of the elegant function-fit solutions will work because we
|
||||
aren't allowed to use floating point in the kernel and doing it with
|
||||
integers doesn't provide enough precision. So we'll do boring old
|
||||
look-up table stuff. The unofficial data (see below) have effectively
|
||||
7-bit resolution (they are rounded to the nearest degree). I'm assuming
|
||||
that the transfer function of the device is monotonic and smooth, so a
|
||||
smooth function fit to the data will allow us to get better precision.
|
||||
I used the 5th-order poly fit described above and solved for
|
||||
VIA register values 0-255. I *10 before rounding, so we get tenth-degree
|
||||
precision. (I could have done all 1024 values for our 10-bit readings,
|
||||
but the function is very linear in the useful range (0-80 deg C), so
|
||||
we'll just use linear interpolation for 10-bit readings.) So, tempLUT
|
||||
VIA register values 0-255. I *10 before rounding, so we get tenth-degree
|
||||
precision. (I could have done all 1024 values for our 10-bit readings,
|
||||
but the function is very linear in the useful range (0-80 deg C), so
|
||||
we'll just use linear interpolation for 10-bit readings.) So, tempLUT
|
||||
is the temp at via register values 0-255: */
|
||||
static const long tempLUT[] =
|
||||
{ -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
|
||||
-503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
|
||||
-362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
|
||||
-255, -246, -237, -229, -220, -212, -204, -196, -188, -180,
|
||||
-173, -166, -159, -152, -145, -139, -132, -126, -120, -114,
|
||||
-108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49,
|
||||
-44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16,
|
||||
20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84,
|
||||
88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138,
|
||||
142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189,
|
||||
193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241,
|
||||
245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294,
|
||||
299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348,
|
||||
353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404,
|
||||
409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464,
|
||||
469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532,
|
||||
538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614,
|
||||
621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718,
|
||||
728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856,
|
||||
870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044,
|
||||
1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252,
|
||||
1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462
|
||||
{ -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
|
||||
-503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
|
||||
-362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
|
||||
-255, -246, -237, -229, -220, -212, -204, -196, -188, -180,
|
||||
-173, -166, -159, -152, -145, -139, -132, -126, -120, -114,
|
||||
-108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49,
|
||||
-44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16,
|
||||
20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84,
|
||||
88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138,
|
||||
142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189,
|
||||
193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241,
|
||||
245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294,
|
||||
299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348,
|
||||
353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404,
|
||||
409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464,
|
||||
469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532,
|
||||
538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614,
|
||||
621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718,
|
||||
728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856,
|
||||
870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044,
|
||||
1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252,
|
||||
1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462
|
||||
};
|
||||
|
||||
/* the original LUT values from Alex van Kaam <darkside@chello.nl>
|
||||
/* the original LUT values from Alex van Kaam <darkside@chello.nl>
|
||||
(for via register values 12-240):
|
||||
{-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31,
|
||||
-30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15,
|
||||
@@ -245,26 +240,26 @@ static const long tempLUT[] =
|
||||
|
||||
|
||||
Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed
|
||||
an extra term for a good fit to these inverse data!) and then
|
||||
solving for each temp value from -50 to 110 (the useable range for
|
||||
this chip). Here's the fit:
|
||||
viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4
|
||||
an extra term for a good fit to these inverse data!) and then
|
||||
solving for each temp value from -50 to 110 (the useable range for
|
||||
this chip). Here's the fit:
|
||||
viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4
|
||||
- 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
|
||||
Note that n=161: */
|
||||
static const u8 viaLUT[] =
|
||||
{ 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
|
||||
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
|
||||
41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
|
||||
69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100,
|
||||
103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129,
|
||||
131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156,
|
||||
158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180,
|
||||
182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199,
|
||||
200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213,
|
||||
214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224,
|
||||
225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232,
|
||||
233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
|
||||
239, 240
|
||||
{ 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
|
||||
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
|
||||
41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
|
||||
69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100,
|
||||
103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129,
|
||||
131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156,
|
||||
158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180,
|
||||
182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199,
|
||||
200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213,
|
||||
214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224,
|
||||
225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232,
|
||||
233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
|
||||
239, 240
|
||||
};
|
||||
|
||||
/* Converting temps to (8-bit) hyst and over registers
|
||||
@@ -272,7 +267,7 @@ static const u8 viaLUT[] =
|
||||
The +50 is because the temps start at -50 */
|
||||
static inline u8 TEMP_TO_REG(long val)
|
||||
{
|
||||
return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 :
|
||||
return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 :
|
||||
(val < 0 ? val - 500 : val + 500) / 1000 + 50];
|
||||
}
|
||||
|
||||
@@ -291,11 +286,9 @@ static inline long TEMP_FROM_REG10(u16 val)
|
||||
|
||||
/* do some linear interpolation */
|
||||
return (tempLUT[eightBits] * (4 - twoBits) +
|
||||
tempLUT[eightBits + 1] * twoBits) * 25;
|
||||
tempLUT[eightBits + 1] * twoBits) * 25;
|
||||
}
|
||||
|
||||
#define ALARMS_FROM_REG(val) (val)
|
||||
|
||||
#define DIV_FROM_REG(val) (1 << (val))
|
||||
#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
|
||||
|
||||
@@ -358,28 +351,28 @@ static ssize_t show_in_max(struct device *dev, char *buf, int nr) {
|
||||
return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));
|
||||
}
|
||||
|
||||
static ssize_t set_in_min(struct device *dev, const char *buf,
|
||||
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 via686a_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
down(&data->update_lock);
|
||||
data->in_min[nr] = IN_TO_REG(val,nr);
|
||||
via686a_write_value(client, VIA686A_REG_IN_MIN(nr),
|
||||
data->in_min[nr] = IN_TO_REG(val, nr);
|
||||
via686a_write_value(client, VIA686A_REG_IN_MIN(nr),
|
||||
data->in_min[nr]);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_in_max(struct device *dev, const char *buf,
|
||||
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 via686a_data *data = i2c_get_clientdata(client);
|
||||
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
down(&data->update_lock);
|
||||
data->in_max[nr] = IN_TO_REG(val,nr);
|
||||
via686a_write_value(client, VIA686A_REG_IN_MAX(nr),
|
||||
data->in_max[nr] = IN_TO_REG(val, nr);
|
||||
via686a_write_value(client, VIA686A_REG_IN_MAX(nr),
|
||||
data->in_max[nr]);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
@@ -435,7 +428,7 @@ static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) {
|
||||
struct via686a_data *data = via686a_update_device(dev);
|
||||
return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
|
||||
}
|
||||
static ssize_t set_temp_over(struct device *dev, const char *buf,
|
||||
static ssize_t set_temp_over(struct device *dev, const char *buf,
|
||||
size_t count, int nr) {
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct via686a_data *data = i2c_get_clientdata(client);
|
||||
@@ -443,11 +436,12 @@ static ssize_t set_temp_over(struct device *dev, const char *buf,
|
||||
|
||||
down(&data->update_lock);
|
||||
data->temp_over[nr] = TEMP_TO_REG(val);
|
||||
via686a_write_value(client, VIA686A_REG_TEMP_OVER(nr), data->temp_over[nr]);
|
||||
via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr],
|
||||
data->temp_over[nr]);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_temp_hyst(struct device *dev, const char *buf,
|
||||
static ssize_t set_temp_hyst(struct device *dev, const char *buf,
|
||||
size_t count, int nr) {
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct via686a_data *data = i2c_get_clientdata(client);
|
||||
@@ -455,7 +449,8 @@ static ssize_t set_temp_hyst(struct device *dev, const char *buf,
|
||||
|
||||
down(&data->update_lock);
|
||||
data->temp_hyst[nr] = TEMP_TO_REG(val);
|
||||
via686a_write_value(client, VIA686A_REG_TEMP_HYST(nr), data->temp_hyst[nr]);
|
||||
via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr],
|
||||
data->temp_hyst[nr]);
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
@@ -488,7 +483,7 @@ static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\
|
||||
static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
|
||||
show_temp_##offset##_over, set_temp_##offset##_over); \
|
||||
static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
|
||||
show_temp_##offset##_hyst, set_temp_##offset##_hyst);
|
||||
show_temp_##offset##_hyst, set_temp_##offset##_hyst);
|
||||
|
||||
show_temp_offset(1);
|
||||
show_temp_offset(2);
|
||||
@@ -497,19 +492,19 @@ show_temp_offset(3);
|
||||
/* 2 Fans */
|
||||
static ssize_t show_fan(struct device *dev, char *buf, int nr) {
|
||||
struct via686a_data *data = via686a_update_device(dev);
|
||||
return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr],
|
||||
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
|
||||
DIV_FROM_REG(data->fan_div[nr])) );
|
||||
}
|
||||
static ssize_t show_fan_min(struct device *dev, char *buf, int nr) {
|
||||
struct via686a_data *data = via686a_update_device(dev);
|
||||
return sprintf(buf,"%d\n",
|
||||
return sprintf(buf, "%d\n",
|
||||
FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) );
|
||||
}
|
||||
static ssize_t show_fan_div(struct device *dev, char *buf, int nr) {
|
||||
struct via686a_data *data = via686a_update_device(dev);
|
||||
return sprintf(buf,"%d\n", DIV_FROM_REG(data->fan_div[nr]) );
|
||||
return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
|
||||
}
|
||||
static ssize_t set_fan_min(struct device *dev, const char *buf,
|
||||
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 via686a_data *data = i2c_get_clientdata(client);
|
||||
@@ -521,7 +516,7 @@ static ssize_t set_fan_min(struct device *dev, const char *buf,
|
||||
up(&data->update_lock);
|
||||
return count;
|
||||
}
|
||||
static ssize_t set_fan_div(struct device *dev, const char *buf,
|
||||
static ssize_t set_fan_div(struct device *dev, const char *buf,
|
||||
size_t count, int nr) {
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct via686a_data *data = i2c_get_clientdata(client);
|
||||
@@ -572,7 +567,7 @@ show_fan_offset(2);
|
||||
/* Alarms */
|
||||
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) {
|
||||
struct via686a_data *data = via686a_update_device(dev);
|
||||
return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms));
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||
|
||||
@@ -612,11 +607,12 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
}
|
||||
|
||||
/* 8231 requires multiple of 256, we enforce that on 686 as well */
|
||||
if(force_addr)
|
||||
if (force_addr)
|
||||
address = force_addr & 0xFF00;
|
||||
|
||||
if(force_addr) {
|
||||
dev_warn(&adapter->dev,"forcing ISA address 0x%04X\n", address);
|
||||
if (force_addr) {
|
||||
dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n",
|
||||
address);
|
||||
if (PCIBIOS_SUCCESSFUL !=
|
||||
pci_write_config_word(s_bridge, VIA686A_BASE_REG, address))
|
||||
return -ENODEV;
|
||||
@@ -625,17 +621,17 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val))
|
||||
return -ENODEV;
|
||||
if (!(val & 0x0001)) {
|
||||
dev_warn(&adapter->dev,"enabling sensors\n");
|
||||
dev_warn(&adapter->dev, "enabling sensors\n");
|
||||
if (PCIBIOS_SUCCESSFUL !=
|
||||
pci_write_config_word(s_bridge, VIA686A_ENABLE_REG,
|
||||
val | 0x0001))
|
||||
val | 0x0001))
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Reserve the ISA region */
|
||||
if (!request_region(address, VIA686A_EXTENT, via686a_driver.name)) {
|
||||
dev_err(&adapter->dev,"region 0x%x already in use!\n",
|
||||
address);
|
||||
dev_err(&adapter->dev, "region 0x%x already in use!\n",
|
||||
address);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -660,7 +656,7 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
/* Tell the I2C layer a new client has arrived */
|
||||
if ((err = i2c_attach_client(new_client)))
|
||||
goto ERROR3;
|
||||
|
||||
|
||||
/* Initialize the VIA686A chip */
|
||||
via686a_init_client(new_client);
|
||||
|
||||
@@ -699,9 +695,9 @@ static int via686a_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
|
||||
return 0;
|
||||
|
||||
ERROR3:
|
||||
ERROR3:
|
||||
kfree(data);
|
||||
ERROR0:
|
||||
ERROR0:
|
||||
release_region(address, VIA686A_EXTENT);
|
||||
return err;
|
||||
}
|
||||
@@ -732,7 +728,7 @@ static void via686a_init_client(struct i2c_client *client)
|
||||
via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F);
|
||||
|
||||
/* Configure temp interrupt mode for continuous-interrupt operation */
|
||||
via686a_write_value(client, VIA686A_REG_TEMP_MODE,
|
||||
via686a_write_value(client, VIA686A_REG_TEMP_MODE,
|
||||
via686a_read_value(client, VIA686A_REG_TEMP_MODE) &
|
||||
!(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS));
|
||||
}
|
||||
@@ -764,15 +760,15 @@ static struct via686a_data *via686a_update_device(struct device *dev)
|
||||
}
|
||||
for (i = 0; i <= 2; i++) {
|
||||
data->temp[i] = via686a_read_value(client,
|
||||
VIA686A_REG_TEMP(i)) << 2;
|
||||
VIA686A_REG_TEMP[i]) << 2;
|
||||
data->temp_over[i] =
|
||||
via686a_read_value(client,
|
||||
VIA686A_REG_TEMP_OVER(i));
|
||||
VIA686A_REG_TEMP_OVER[i]);
|
||||
data->temp_hyst[i] =
|
||||
via686a_read_value(client,
|
||||
VIA686A_REG_TEMP_HYST(i));
|
||||
VIA686A_REG_TEMP_HYST[i]);
|
||||
}
|
||||
/* add in lower 2 bits
|
||||
/* add in lower 2 bits
|
||||
temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1
|
||||
temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
|
||||
temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
|
||||
@@ -804,35 +800,36 @@ static struct via686a_data *via686a_update_device(struct device *dev)
|
||||
}
|
||||
|
||||
static struct pci_device_id via686a_pci_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
|
||||
{ 0, }
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
|
||||
|
||||
static int __devinit via686a_pci_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
u16 val;
|
||||
int addr = 0;
|
||||
u16 val;
|
||||
int addr = 0;
|
||||
|
||||
if (PCIBIOS_SUCCESSFUL !=
|
||||
pci_read_config_word(dev, VIA686A_BASE_REG, &val))
|
||||
return -ENODEV;
|
||||
if (PCIBIOS_SUCCESSFUL !=
|
||||
pci_read_config_word(dev, VIA686A_BASE_REG, &val))
|
||||
return -ENODEV;
|
||||
|
||||
addr = val & ~(VIA686A_EXTENT - 1);
|
||||
if (addr == 0 && force_addr == 0) {
|
||||
dev_err(&dev->dev,"base address not set - upgrade BIOS or use force_addr=0xaddr\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (force_addr)
|
||||
addr = force_addr; /* so detect will get called */
|
||||
addr = val & ~(VIA686A_EXTENT - 1);
|
||||
if (addr == 0 && force_addr == 0) {
|
||||
dev_err(&dev->dev, "base address not set - upgrade BIOS "
|
||||
"or use force_addr=0xaddr\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (force_addr)
|
||||
addr = force_addr; /* so detect will get called */
|
||||
|
||||
if (!addr) {
|
||||
dev_err(&dev->dev,"No Via 686A sensors found.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
normal_isa[0] = addr;
|
||||
if (!addr) {
|
||||
dev_err(&dev->dev, "No Via 686A sensors found.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
normal_isa[0] = addr;
|
||||
|
||||
s_bridge = pci_dev_get(dev);
|
||||
if (i2c_add_driver(&via686a_driver)) {
|
||||
@@ -848,14 +845,14 @@ static int __devinit via686a_pci_probe(struct pci_dev *dev,
|
||||
}
|
||||
|
||||
static struct pci_driver via686a_pci_driver = {
|
||||
.name = "via686a",
|
||||
.id_table = via686a_pci_ids,
|
||||
.probe = via686a_pci_probe,
|
||||
.name = "via686a",
|
||||
.id_table = via686a_pci_ids,
|
||||
.probe = via686a_pci_probe,
|
||||
};
|
||||
|
||||
static int __init sm_via686a_init(void)
|
||||
{
|
||||
return pci_register_driver(&via686a_pci_driver);
|
||||
return pci_register_driver(&via686a_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit sm_via686a_exit(void)
|
||||
@@ -869,8 +866,8 @@ static void __exit sm_via686a_exit(void)
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Ky<EFBFBD>sti M<>lkki <kmalkki@cc.hut.fi>, "
|
||||
"Mark Studebaker <mdsxyz123@yahoo.com> "
|
||||
"and Bob Dougherty <bobd@stanford.edu>");
|
||||
"Mark Studebaker <mdsxyz123@yahoo.com> "
|
||||
"and Bob Dougherty <bobd@stanford.edu>");
|
||||
MODULE_DESCRIPTION("VIA 686A Sensor device");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
846
drivers/i2c/chips/w83627ehf.c
Normal file
846
drivers/i2c/chips/w83627ehf.c
Normal file
@@ -0,0 +1,846 @@
|
||||
/*
|
||||
w83627ehf - Driver for the hardware monitoring functionality of
|
||||
the Winbond W83627EHF Super-I/O chip
|
||||
Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
Shamelessly ripped from the w83627hf driver
|
||||
Copyright (C) 2003 Mark Studebaker
|
||||
|
||||
Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
|
||||
in testing and debugging this driver.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Supports the following chips:
|
||||
|
||||
Chip #vin #fan #pwm #temp chip_id man_id
|
||||
w83627ehf - 5 - 3 0x88 0x5ca3
|
||||
|
||||
This is a preliminary version of the driver, only supporting the
|
||||
fan and temperature inputs. The chip does much more than that.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-sensor.h>
|
||||
#include <asm/io.h>
|
||||
#include "lm75.h"
|
||||
|
||||
/* Addresses to scan
|
||||
The actual ISA address is read from Super-I/O configuration space */
|
||||
static unsigned short normal_i2c[] = { I2C_CLIENT_END };
|
||||
static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END };
|
||||
|
||||
/* Insmod parameters */
|
||||
SENSORS_INSMOD_1(w83627ehf);
|
||||
|
||||
/*
|
||||
* Super-I/O constants and functions
|
||||
*/
|
||||
|
||||
static int REG; /* The register to read/write */
|
||||
static int VAL; /* The value to read/write */
|
||||
|
||||
#define W83627EHF_LD_HWM 0x0b
|
||||
|
||||
#define SIO_REG_LDSEL 0x07 /* Logical device select */
|
||||
#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
|
||||
#define SIO_REG_ENABLE 0x30 /* Logical device enable */
|
||||
#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
|
||||
|
||||
#define SIO_W83627EHF_ID 0x8840
|
||||
#define SIO_ID_MASK 0xFFC0
|
||||
|
||||
static inline void
|
||||
superio_outb(int reg, int val)
|
||||
{
|
||||
outb(reg, REG);
|
||||
outb(val, VAL);
|
||||
}
|
||||
|
||||
static inline int
|
||||
superio_inb(int reg)
|
||||
{
|
||||
outb(reg, REG);
|
||||
return inb(VAL);
|
||||
}
|
||||
|
||||
static inline void
|
||||
superio_select(int ld)
|
||||
{
|
||||
outb(SIO_REG_LDSEL, REG);
|
||||
outb(ld, VAL);
|
||||
}
|
||||
|
||||
static inline void
|
||||
superio_enter(void)
|
||||
{
|
||||
outb(0x87, REG);
|
||||
outb(0x87, REG);
|
||||
}
|
||||
|
||||
static inline void
|
||||
superio_exit(void)
|
||||
{
|
||||
outb(0x02, REG);
|
||||
outb(0x02, VAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* ISA constants
|
||||
*/
|
||||
|
||||
#define REGION_LENGTH 8
|
||||
#define ADDR_REG_OFFSET 5
|
||||
#define DATA_REG_OFFSET 6
|
||||
|
||||
#define W83627EHF_REG_BANK 0x4E
|
||||
#define W83627EHF_REG_CONFIG 0x40
|
||||
#define W83627EHF_REG_CHIP_ID 0x49
|
||||
#define W83627EHF_REG_MAN_ID 0x4F
|
||||
|
||||
static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
|
||||
static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
|
||||
|
||||
#define W83627EHF_REG_TEMP1 0x27
|
||||
#define W83627EHF_REG_TEMP1_HYST 0x3a
|
||||
#define W83627EHF_REG_TEMP1_OVER 0x39
|
||||
static const u16 W83627EHF_REG_TEMP[] = { 0x150, 0x250 };
|
||||
static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x153, 0x253 };
|
||||
static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x155, 0x255 };
|
||||
static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
|
||||
|
||||
/* Fan clock dividers are spread over the following five registers */
|
||||
#define W83627EHF_REG_FANDIV1 0x47
|
||||
#define W83627EHF_REG_FANDIV2 0x4B
|
||||
#define W83627EHF_REG_VBAT 0x5D
|
||||
#define W83627EHF_REG_DIODE 0x59
|
||||
#define W83627EHF_REG_SMI_OVT 0x4C
|
||||
|
||||
/*
|
||||
* Conversions
|
||||
*/
|
||||
|
||||
static inline unsigned int
|
||||
fan_from_reg(u8 reg, unsigned int div)
|
||||
{
|
||||
if (reg == 0 || reg == 255)
|
||||
return 0;
|
||||
return 1350000U / (reg * div);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
div_from_reg(u8 reg)
|
||||
{
|
||||
return 1 << reg;
|
||||
}
|
||||
|
||||
static inline int
|
||||
temp1_from_reg(s8 reg)
|
||||
{
|
||||
return reg * 1000;
|
||||
}
|
||||
|
||||
static inline s8
|
||||
temp1_to_reg(int temp)
|
||||
{
|
||||
if (temp <= -128000)
|
||||
return -128;
|
||||
if (temp >= 127000)
|
||||
return 127;
|
||||
if (temp < 0)
|
||||
return (temp - 500) / 1000;
|
||||
return (temp + 500) / 1000;
|
||||
}
|
||||
|
||||
/*
|
||||
* Data structures and manipulation thereof
|
||||
*/
|
||||
|
||||
struct w83627ehf_data {
|
||||
struct i2c_client client;
|
||||
struct semaphore lock;
|
||||
|
||||
struct semaphore update_lock;
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
|
||||
/* Register values */
|
||||
u8 fan[5];
|
||||
u8 fan_min[5];
|
||||
u8 fan_div[5];
|
||||
u8 has_fan; /* some fan inputs can be disabled */
|
||||
s8 temp1;
|
||||
s8 temp1_max;
|
||||
s8 temp1_max_hyst;
|
||||
s16 temp[2];
|
||||
s16 temp_max[2];
|
||||
s16 temp_max_hyst[2];
|
||||
};
|
||||
|
||||
static inline int is_word_sized(u16 reg)
|
||||
{
|
||||
return (((reg & 0xff00) == 0x100
|
||||
|| (reg & 0xff00) == 0x200)
|
||||
&& ((reg & 0x00ff) == 0x50
|
||||
|| (reg & 0x00ff) == 0x53
|
||||
|| (reg & 0x00ff) == 0x55));
|
||||
}
|
||||
|
||||
/* We assume that the default bank is 0, thus the following two functions do
|
||||
nothing for registers which live in bank 0. For others, they respectively
|
||||
set the bank register to the correct value (before the register is
|
||||
accessed), and back to 0 (afterwards). */
|
||||
static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg)
|
||||
{
|
||||
if (reg & 0xff00) {
|
||||
outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
|
||||
outb_p(reg >> 8, client->addr + DATA_REG_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg)
|
||||
{
|
||||
if (reg & 0xff00) {
|
||||
outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
|
||||
outb_p(0, client->addr + DATA_REG_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg)
|
||||
{
|
||||
struct w83627ehf_data *data = i2c_get_clientdata(client);
|
||||
int res, word_sized = is_word_sized(reg);
|
||||
|
||||
down(&data->lock);
|
||||
|
||||
w83627ehf_set_bank(client, reg);
|
||||
outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
|
||||
res = inb_p(client->addr + DATA_REG_OFFSET);
|
||||
if (word_sized) {
|
||||
outb_p((reg & 0xff) + 1,
|
||||
client->addr + ADDR_REG_OFFSET);
|
||||
res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET);
|
||||
}
|
||||
w83627ehf_reset_bank(client, reg);
|
||||
|
||||
up(&data->lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value)
|
||||
{
|
||||
struct w83627ehf_data *data = i2c_get_clientdata(client);
|
||||
int word_sized = is_word_sized(reg);
|
||||
|
||||
down(&data->lock);
|
||||
|
||||
w83627ehf_set_bank(client, reg);
|
||||
outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
|
||||
if (word_sized) {
|
||||
outb_p(value >> 8, client->addr + DATA_REG_OFFSET);
|
||||
outb_p((reg & 0xff) + 1,
|
||||
client->addr + ADDR_REG_OFFSET);
|
||||
}
|
||||
outb_p(value & 0xff, client->addr + DATA_REG_OFFSET);
|
||||
w83627ehf_reset_bank(client, reg);
|
||||
|
||||
up(&data->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function assumes that the caller holds data->update_lock */
|
||||
static void w83627ehf_write_fan_div(struct i2c_client *client, int nr)
|
||||
{
|
||||
struct w83627ehf_data *data = i2c_get_clientdata(client);
|
||||
u8 reg;
|
||||
|
||||
switch (nr) {
|
||||
case 0:
|
||||
reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf)
|
||||
| ((data->fan_div[0] & 0x03) << 4);
|
||||
w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
|
||||
reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf)
|
||||
| ((data->fan_div[0] & 0x04) << 3);
|
||||
w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
|
||||
break;
|
||||
case 1:
|
||||
reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f)
|
||||
| ((data->fan_div[1] & 0x03) << 6);
|
||||
w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
|
||||
reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf)
|
||||
| ((data->fan_div[1] & 0x04) << 4);
|
||||
w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
|
||||
break;
|
||||
case 2:
|
||||
reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f)
|
||||
| ((data->fan_div[2] & 0x03) << 6);
|
||||
w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg);
|
||||
reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f)
|
||||
| ((data->fan_div[2] & 0x04) << 5);
|
||||
w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
|
||||
break;
|
||||
case 3:
|
||||
reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc)
|
||||
| (data->fan_div[3] & 0x03);
|
||||
w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
|
||||
reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f)
|
||||
| ((data->fan_div[3] & 0x04) << 5);
|
||||
w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg);
|
||||
break;
|
||||
case 4:
|
||||
reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73)
|
||||
| ((data->fan_div[4] & 0x03) << 3)
|
||||
| ((data->fan_div[4] & 0x04) << 5);
|
||||
w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83627ehf_data *data = i2c_get_clientdata(client);
|
||||
int i;
|
||||
|
||||
down(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ)
|
||||
|| !data->valid) {
|
||||
/* Fan clock dividers */
|
||||
i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
|
||||
data->fan_div[0] = (i >> 4) & 0x03;
|
||||
data->fan_div[1] = (i >> 6) & 0x03;
|
||||
i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2);
|
||||
data->fan_div[2] = (i >> 6) & 0x03;
|
||||
i = w83627ehf_read_value(client, W83627EHF_REG_VBAT);
|
||||
data->fan_div[0] |= (i >> 3) & 0x04;
|
||||
data->fan_div[1] |= (i >> 4) & 0x04;
|
||||
data->fan_div[2] |= (i >> 5) & 0x04;
|
||||
if (data->has_fan & ((1 << 3) | (1 << 4))) {
|
||||
i = w83627ehf_read_value(client, W83627EHF_REG_DIODE);
|
||||
data->fan_div[3] = i & 0x03;
|
||||
data->fan_div[4] = ((i >> 2) & 0x03)
|
||||
| ((i >> 5) & 0x04);
|
||||
}
|
||||
if (data->has_fan & (1 << 3)) {
|
||||
i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT);
|
||||
data->fan_div[3] |= (i >> 5) & 0x04;
|
||||
}
|
||||
|
||||
/* Measured fan speeds and limits */
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (!(data->has_fan & (1 << i)))
|
||||
continue;
|
||||
|
||||
data->fan[i] = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_FAN[i]);
|
||||
data->fan_min[i] = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_FAN_MIN[i]);
|
||||
|
||||
/* If we failed to measure the fan speed and clock
|
||||
divider can be increased, let's try that for next
|
||||
time */
|
||||
if (data->fan[i] == 0xff
|
||||
&& data->fan_div[i] < 0x07) {
|
||||
dev_dbg(&client->dev, "Increasing fan %d "
|
||||
"clock divider from %u to %u\n",
|
||||
i, div_from_reg(data->fan_div[i]),
|
||||
div_from_reg(data->fan_div[i] + 1));
|
||||
data->fan_div[i]++;
|
||||
w83627ehf_write_fan_div(client, i);
|
||||
/* Preserve min limit if possible */
|
||||
if (data->fan_min[i] >= 2
|
||||
&& data->fan_min[i] != 255)
|
||||
w83627ehf_write_value(client,
|
||||
W83627EHF_REG_FAN_MIN[i],
|
||||
(data->fan_min[i] /= 2));
|
||||
}
|
||||
}
|
||||
|
||||
/* Measured temperatures and limits */
|
||||
data->temp1 = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_TEMP1);
|
||||
data->temp1_max = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_TEMP1_OVER);
|
||||
data->temp1_max_hyst = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_TEMP1_HYST);
|
||||
for (i = 0; i < 2; i++) {
|
||||
data->temp[i] = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_TEMP[i]);
|
||||
data->temp_max[i] = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_TEMP_OVER[i]);
|
||||
data->temp_max_hyst[i] = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_TEMP_HYST[i]);
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
up(&data->update_lock);
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sysfs callback functions
|
||||
*/
|
||||
|
||||
#define show_fan_reg(reg) \
|
||||
static ssize_t \
|
||||
show_##reg(struct device *dev, char *buf, int nr) \
|
||||
{ \
|
||||
struct w83627ehf_data *data = w83627ehf_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", \
|
||||
fan_from_reg(data->reg[nr], \
|
||||
div_from_reg(data->fan_div[nr]))); \
|
||||
}
|
||||
show_fan_reg(fan);
|
||||
show_fan_reg(fan_min);
|
||||
|
||||
static ssize_t
|
||||
show_fan_div(struct device *dev, char *buf, int nr)
|
||||
{
|
||||
struct w83627ehf_data *data = w83627ehf_update_device(dev);
|
||||
return sprintf(buf, "%u\n",
|
||||
div_from_reg(data->fan_div[nr]));
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct w83627ehf_data *data = i2c_get_clientdata(client);
|
||||
unsigned int val = simple_strtoul(buf, NULL, 10);
|
||||
unsigned int reg;
|
||||
u8 new_div;
|
||||
|
||||
down(&data->update_lock);
|
||||
if (!val) {
|
||||
/* No min limit, alarm disabled */
|
||||
data->fan_min[nr] = 255;
|
||||
new_div = data->fan_div[nr]; /* No change */
|
||||
dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
|
||||
} else if ((reg = 1350000U / val) >= 128 * 255) {
|
||||
/* Speed below this value cannot possibly be represented,
|
||||
even with the highest divider (128) */
|
||||
data->fan_min[nr] = 254;
|
||||
new_div = 7; /* 128 == (1 << 7) */
|
||||
dev_warn(dev, "fan%u low limit %u below minimum %u, set to "
|
||||
"minimum\n", nr + 1, val, fan_from_reg(254, 128));
|
||||
} else if (!reg) {
|
||||
/* Speed above this value cannot possibly be represented,
|
||||
even with the lowest divider (1) */
|
||||
data->fan_min[nr] = 1;
|
||||
new_div = 0; /* 1 == (1 << 0) */
|
||||
dev_warn(dev, "fan%u low limit %u above maximum %u, set to "
|
||||
"maximum\n", nr + 1, val, fan_from_reg(1, 1));
|
||||
} else {
|
||||
/* Automatically pick the best divider, i.e. the one such
|
||||
that the min limit will correspond to a register value
|
||||
in the 96..192 range */
|
||||
new_div = 0;
|
||||
while (reg > 192 && new_div < 7) {
|
||||
reg >>= 1;
|
||||
new_div++;
|
||||
}
|
||||
data->fan_min[nr] = reg;
|
||||
}
|
||||
|
||||
/* Write both the fan clock divider (if it changed) and the new
|
||||
fan min (unconditionally) */
|
||||
if (new_div != data->fan_div[nr]) {
|
||||
if (new_div > data->fan_div[nr])
|
||||
data->fan[nr] >>= (data->fan_div[nr] - new_div);
|
||||
else
|
||||
data->fan[nr] <<= (new_div - data->fan_div[nr]);
|
||||
|
||||
dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
|
||||
nr + 1, div_from_reg(data->fan_div[nr]),
|
||||
div_from_reg(new_div));
|
||||
data->fan_div[nr] = new_div;
|
||||
w83627ehf_write_fan_div(client, nr);
|
||||
}
|
||||
w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr],
|
||||
data->fan_min[nr]);
|
||||
up(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#define sysfs_fan_offset(offset) \
|
||||
static ssize_t \
|
||||
show_reg_fan_##offset(struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_fan(dev, buf, offset-1); \
|
||||
} \
|
||||
static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
|
||||
show_reg_fan_##offset, NULL);
|
||||
|
||||
#define sysfs_fan_min_offset(offset) \
|
||||
static ssize_t \
|
||||
show_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_fan_min(dev, buf, offset-1); \
|
||||
} \
|
||||
static ssize_t \
|
||||
store_reg_fan##offset##_min(struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return store_fan_min(dev, buf, count, offset-1); \
|
||||
} \
|
||||
static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
show_reg_fan##offset##_min, \
|
||||
store_reg_fan##offset##_min);
|
||||
|
||||
#define sysfs_fan_div_offset(offset) \
|
||||
static ssize_t \
|
||||
show_reg_fan##offset##_div(struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_fan_div(dev, buf, offset - 1); \
|
||||
} \
|
||||
static DEVICE_ATTR(fan##offset##_div, S_IRUGO, \
|
||||
show_reg_fan##offset##_div, NULL);
|
||||
|
||||
sysfs_fan_offset(1);
|
||||
sysfs_fan_min_offset(1);
|
||||
sysfs_fan_div_offset(1);
|
||||
sysfs_fan_offset(2);
|
||||
sysfs_fan_min_offset(2);
|
||||
sysfs_fan_div_offset(2);
|
||||
sysfs_fan_offset(3);
|
||||
sysfs_fan_min_offset(3);
|
||||
sysfs_fan_div_offset(3);
|
||||
sysfs_fan_offset(4);
|
||||
sysfs_fan_min_offset(4);
|
||||
sysfs_fan_div_offset(4);
|
||||
sysfs_fan_offset(5);
|
||||
sysfs_fan_min_offset(5);
|
||||
sysfs_fan_div_offset(5);
|
||||
|
||||
#define show_temp1_reg(reg) \
|
||||
static ssize_t \
|
||||
show_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct w83627ehf_data *data = w83627ehf_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", temp1_from_reg(data->reg)); \
|
||||
}
|
||||
show_temp1_reg(temp1);
|
||||
show_temp1_reg(temp1_max);
|
||||
show_temp1_reg(temp1_max_hyst);
|
||||
|
||||
#define store_temp1_reg(REG, reg) \
|
||||
static ssize_t \
|
||||
store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct w83627ehf_data *data = i2c_get_clientdata(client); \
|
||||
u32 val = simple_strtoul(buf, NULL, 10); \
|
||||
\
|
||||
down(&data->update_lock); \
|
||||
data->temp1_##reg = temp1_to_reg(val); \
|
||||
w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \
|
||||
data->temp1_##reg); \
|
||||
up(&data->update_lock); \
|
||||
return count; \
|
||||
}
|
||||
store_temp1_reg(OVER, max);
|
||||
store_temp1_reg(HYST, max_hyst);
|
||||
|
||||
static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL);
|
||||
static DEVICE_ATTR(temp1_max, S_IRUGO| S_IWUSR,
|
||||
show_temp1_max, store_temp1_max);
|
||||
static DEVICE_ATTR(temp1_max_hyst, S_IRUGO| S_IWUSR,
|
||||
show_temp1_max_hyst, store_temp1_max_hyst);
|
||||
|
||||
#define show_temp_reg(reg) \
|
||||
static ssize_t \
|
||||
show_##reg (struct device *dev, char *buf, int nr) \
|
||||
{ \
|
||||
struct w83627ehf_data *data = w83627ehf_update_device(dev); \
|
||||
return sprintf(buf, "%d\n", \
|
||||
LM75_TEMP_FROM_REG(data->reg[nr])); \
|
||||
}
|
||||
show_temp_reg(temp);
|
||||
show_temp_reg(temp_max);
|
||||
show_temp_reg(temp_max_hyst);
|
||||
|
||||
#define store_temp_reg(REG, reg) \
|
||||
static ssize_t \
|
||||
store_##reg (struct device *dev, const char *buf, size_t count, int nr) \
|
||||
{ \
|
||||
struct i2c_client *client = to_i2c_client(dev); \
|
||||
struct w83627ehf_data *data = i2c_get_clientdata(client); \
|
||||
u32 val = simple_strtoul(buf, NULL, 10); \
|
||||
\
|
||||
down(&data->update_lock); \
|
||||
data->reg[nr] = LM75_TEMP_TO_REG(val); \
|
||||
w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \
|
||||
data->reg[nr]); \
|
||||
up(&data->update_lock); \
|
||||
return count; \
|
||||
}
|
||||
store_temp_reg(OVER, temp_max);
|
||||
store_temp_reg(HYST, temp_max_hyst);
|
||||
|
||||
#define sysfs_temp_offset(offset) \
|
||||
static ssize_t \
|
||||
show_reg_temp##offset (struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_temp(dev, buf, offset - 2); \
|
||||
} \
|
||||
static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
|
||||
show_reg_temp##offset, NULL);
|
||||
|
||||
#define sysfs_temp_reg_offset(reg, offset) \
|
||||
static ssize_t \
|
||||
show_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
return show_temp_##reg(dev, buf, offset - 2); \
|
||||
} \
|
||||
static ssize_t \
|
||||
store_reg_temp##offset##_##reg(struct device *dev, struct device_attribute *attr, \
|
||||
const char *buf, size_t count) \
|
||||
{ \
|
||||
return store_temp_##reg(dev, buf, count, offset - 2); \
|
||||
} \
|
||||
static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \
|
||||
show_reg_temp##offset##_##reg, \
|
||||
store_reg_temp##offset##_##reg);
|
||||
|
||||
sysfs_temp_offset(2);
|
||||
sysfs_temp_reg_offset(max, 2);
|
||||
sysfs_temp_reg_offset(max_hyst, 2);
|
||||
sysfs_temp_offset(3);
|
||||
sysfs_temp_reg_offset(max, 3);
|
||||
sysfs_temp_reg_offset(max_hyst, 3);
|
||||
|
||||
/*
|
||||
* Driver and client management
|
||||
*/
|
||||
|
||||
static struct i2c_driver w83627ehf_driver;
|
||||
|
||||
static void w83627ehf_init_client(struct i2c_client *client)
|
||||
{
|
||||
int i;
|
||||
u8 tmp;
|
||||
|
||||
/* Start monitoring is needed */
|
||||
tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG);
|
||||
if (!(tmp & 0x01))
|
||||
w83627ehf_write_value(client, W83627EHF_REG_CONFIG,
|
||||
tmp | 0x01);
|
||||
|
||||
/* Enable temp2 and temp3 if needed */
|
||||
for (i = 0; i < 2; i++) {
|
||||
tmp = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_TEMP_CONFIG[i]);
|
||||
if (tmp & 0x01)
|
||||
w83627ehf_write_value(client,
|
||||
W83627EHF_REG_TEMP_CONFIG[i],
|
||||
tmp & 0xfe);
|
||||
}
|
||||
}
|
||||
|
||||
static int w83627ehf_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
struct w83627ehf_data *data;
|
||||
int i, err = 0;
|
||||
|
||||
if (!i2c_is_isa_adapter(adapter))
|
||||
return 0;
|
||||
|
||||
if (!request_region(address, REGION_LENGTH, w83627ehf_driver.name)) {
|
||||
err = -EBUSY;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!(data = kmalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {
|
||||
err = -ENOMEM;
|
||||
goto exit_release;
|
||||
}
|
||||
memset(data, 0, sizeof(struct w83627ehf_data));
|
||||
|
||||
client = &data->client;
|
||||
i2c_set_clientdata(client, data);
|
||||
client->addr = address;
|
||||
init_MUTEX(&data->lock);
|
||||
client->adapter = adapter;
|
||||
client->driver = &w83627ehf_driver;
|
||||
client->flags = 0;
|
||||
|
||||
strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE);
|
||||
data->valid = 0;
|
||||
init_MUTEX(&data->update_lock);
|
||||
|
||||
/* Tell the i2c layer a new client has arrived */
|
||||
if ((err = i2c_attach_client(client)))
|
||||
goto exit_free;
|
||||
|
||||
/* Initialize the chip */
|
||||
w83627ehf_init_client(client);
|
||||
|
||||
/* A few vars need to be filled upon startup */
|
||||
for (i = 0; i < 5; i++)
|
||||
data->fan_min[i] = w83627ehf_read_value(client,
|
||||
W83627EHF_REG_FAN_MIN[i]);
|
||||
|
||||
/* It looks like fan4 and fan5 pins can be alternatively used
|
||||
as fan on/off switches */
|
||||
data->has_fan = 0x07; /* fan1, fan2 and fan3 */
|
||||
i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
|
||||
if (i & (1 << 2))
|
||||
data->has_fan |= (1 << 3);
|
||||
if (i & (1 << 0))
|
||||
data->has_fan |= (1 << 4);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
device_create_file(&client->dev, &dev_attr_fan1_input);
|
||||
device_create_file(&client->dev, &dev_attr_fan1_min);
|
||||
device_create_file(&client->dev, &dev_attr_fan1_div);
|
||||
device_create_file(&client->dev, &dev_attr_fan2_input);
|
||||
device_create_file(&client->dev, &dev_attr_fan2_min);
|
||||
device_create_file(&client->dev, &dev_attr_fan2_div);
|
||||
device_create_file(&client->dev, &dev_attr_fan3_input);
|
||||
device_create_file(&client->dev, &dev_attr_fan3_min);
|
||||
device_create_file(&client->dev, &dev_attr_fan3_div);
|
||||
|
||||
if (data->has_fan & (1 << 3)) {
|
||||
device_create_file(&client->dev, &dev_attr_fan4_input);
|
||||
device_create_file(&client->dev, &dev_attr_fan4_min);
|
||||
device_create_file(&client->dev, &dev_attr_fan4_div);
|
||||
}
|
||||
if (data->has_fan & (1 << 4)) {
|
||||
device_create_file(&client->dev, &dev_attr_fan5_input);
|
||||
device_create_file(&client->dev, &dev_attr_fan5_min);
|
||||
device_create_file(&client->dev, &dev_attr_fan5_div);
|
||||
}
|
||||
|
||||
device_create_file(&client->dev, &dev_attr_temp1_input);
|
||||
device_create_file(&client->dev, &dev_attr_temp1_max);
|
||||
device_create_file(&client->dev, &dev_attr_temp1_max_hyst);
|
||||
device_create_file(&client->dev, &dev_attr_temp2_input);
|
||||
device_create_file(&client->dev, &dev_attr_temp2_max);
|
||||
device_create_file(&client->dev, &dev_attr_temp2_max_hyst);
|
||||
device_create_file(&client->dev, &dev_attr_temp3_input);
|
||||
device_create_file(&client->dev, &dev_attr_temp3_max);
|
||||
device_create_file(&client->dev, &dev_attr_temp3_max_hyst);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_free:
|
||||
kfree(data);
|
||||
exit_release:
|
||||
release_region(address, REGION_LENGTH);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int w83627ehf_attach_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
||||
return 0;
|
||||
return i2c_detect(adapter, &addr_data, w83627ehf_detect);
|
||||
}
|
||||
|
||||
static int w83627ehf_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;
|
||||
}
|
||||
release_region(client->addr, REGION_LENGTH);
|
||||
kfree(i2c_get_clientdata(client));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver w83627ehf_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "w83627ehf",
|
||||
.flags = I2C_DF_NOTIFY,
|
||||
.attach_adapter = w83627ehf_attach_adapter,
|
||||
.detach_client = w83627ehf_detach_client,
|
||||
};
|
||||
|
||||
static int __init w83627ehf_find(int sioaddr, int *address)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
REG = sioaddr;
|
||||
VAL = sioaddr + 1;
|
||||
superio_enter();
|
||||
|
||||
val = (superio_inb(SIO_REG_DEVID) << 8)
|
||||
| superio_inb(SIO_REG_DEVID + 1);
|
||||
if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) {
|
||||
superio_exit();
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
superio_select(W83627EHF_LD_HWM);
|
||||
val = (superio_inb(SIO_REG_ADDR) << 8)
|
||||
| superio_inb(SIO_REG_ADDR + 1);
|
||||
*address = val & ~(REGION_LENGTH - 1);
|
||||
if (*address == 0) {
|
||||
superio_exit();
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Activate logical device if needed */
|
||||
val = superio_inb(SIO_REG_ENABLE);
|
||||
if (!(val & 0x01))
|
||||
superio_outb(SIO_REG_ENABLE, val | 0x01);
|
||||
|
||||
superio_exit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init sensors_w83627ehf_init(void)
|
||||
{
|
||||
if (w83627ehf_find(0x2e, &normal_isa[0])
|
||||
&& w83627ehf_find(0x4e, &normal_isa[0]))
|
||||
return -ENODEV;
|
||||
|
||||
return i2c_add_driver(&w83627ehf_driver);
|
||||
}
|
||||
|
||||
static void __exit sensors_w83627ehf_exit(void)
|
||||
{
|
||||
i2c_del_driver(&w83627ehf_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
|
||||
MODULE_DESCRIPTION("W83627EHF driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_w83627ehf_init);
|
||||
module_exit(sensors_w83627ehf_exit);
|
||||
@@ -264,7 +264,7 @@ static inline u8 DIV_TO_REG(long val)
|
||||
{
|
||||
int i;
|
||||
val = SENSORS_LIMIT(val, 1, 128) >> 1;
|
||||
for (i = 0; i < 6; i++) {
|
||||
for (i = 0; i < 7; i++) {
|
||||
if (val == 0)
|
||||
break;
|
||||
val >>= 1;
|
||||
|
||||
@@ -28,14 +28,11 @@
|
||||
as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no
|
||||
w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes
|
||||
w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC)
|
||||
w83627thf 9 3 2 3 0x90 0x5ca3 no yes(LPC)
|
||||
w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes
|
||||
w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no
|
||||
w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC)
|
||||
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -53,7 +50,7 @@ static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
|
||||
static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END };
|
||||
|
||||
/* Insmod parameters */
|
||||
SENSORS_INSMOD_6(w83781d, w83782d, w83783s, w83627hf, as99127f, w83697hf);
|
||||
SENSORS_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f);
|
||||
I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
|
||||
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
|
||||
|
||||
@@ -173,7 +170,6 @@ FAN_TO_REG(long rpm, int div)
|
||||
: (val)) / 1000, 0, 0xff))
|
||||
#define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000)
|
||||
|
||||
#define ALARMS_FROM_REG(val) (val)
|
||||
#define PWM_FROM_REG(val) (val)
|
||||
#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
|
||||
#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \
|
||||
@@ -193,7 +189,7 @@ DIV_TO_REG(long val, enum chips type)
|
||||
val = SENSORS_LIMIT(val, 1,
|
||||
((type == w83781d
|
||||
|| type == as99127f) ? 8 : 128)) >> 1;
|
||||
for (i = 0; i < 6; i++) {
|
||||
for (i = 0; i < 7; i++) {
|
||||
if (val == 0)
|
||||
break;
|
||||
val >>= 1;
|
||||
@@ -524,7 +520,7 @@ static ssize_t
|
||||
show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct w83781d_data *data = w83781d_update_device(dev);
|
||||
return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms));
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
|
||||
static
|
||||
@@ -1000,13 +996,6 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
err = -EINVAL;
|
||||
goto ERROR0;
|
||||
}
|
||||
if (!is_isa && kind == w83697hf) {
|
||||
dev_err(&adapter->dev,
|
||||
"Cannot force ISA-only chip for I2C address 0x%02x.\n",
|
||||
address);
|
||||
err = -EINVAL;
|
||||
goto ERROR0;
|
||||
}
|
||||
|
||||
if (is_isa)
|
||||
if (!request_region(address, W83781D_EXTENT,
|
||||
@@ -1139,12 +1128,10 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
else if (val1 == 0x40 && vendid == winbond && !is_isa
|
||||
&& address == 0x2d)
|
||||
kind = w83783s;
|
||||
else if ((val1 == 0x21 || val1 == 0x90) && vendid == winbond)
|
||||
else if (val1 == 0x21 && vendid == winbond)
|
||||
kind = w83627hf;
|
||||
else if (val1 == 0x31 && !is_isa && address >= 0x28)
|
||||
kind = as99127f;
|
||||
else if (val1 == 0x60 && vendid == winbond && is_isa)
|
||||
kind = w83697hf;
|
||||
else {
|
||||
if (kind == 0)
|
||||
dev_warn(&new_client->dev, "Ignoring 'force' "
|
||||
@@ -1163,14 +1150,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
} else if (kind == w83783s) {
|
||||
client_name = "w83783s";
|
||||
} else if (kind == w83627hf) {
|
||||
if (val1 == 0x90)
|
||||
client_name = "w83627thf";
|
||||
else
|
||||
client_name = "w83627hf";
|
||||
client_name = "w83627hf";
|
||||
} else if (kind == as99127f) {
|
||||
client_name = "as99127f";
|
||||
} else if (kind == w83697hf) {
|
||||
client_name = "w83697hf";
|
||||
}
|
||||
|
||||
/* Fill in the remaining client fields and put into the global list */
|
||||
@@ -1208,7 +1190,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
|
||||
/* Register sysfs hooks */
|
||||
device_create_file_in(new_client, 0);
|
||||
if (kind != w83783s && kind != w83697hf)
|
||||
if (kind != w83783s)
|
||||
device_create_file_in(new_client, 1);
|
||||
device_create_file_in(new_client, 2);
|
||||
device_create_file_in(new_client, 3);
|
||||
@@ -1222,24 +1204,19 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
|
||||
device_create_file_fan(new_client, 1);
|
||||
device_create_file_fan(new_client, 2);
|
||||
if (kind != w83697hf)
|
||||
device_create_file_fan(new_client, 3);
|
||||
device_create_file_fan(new_client, 3);
|
||||
|
||||
device_create_file_temp(new_client, 1);
|
||||
device_create_file_temp(new_client, 2);
|
||||
if (kind != w83783s && kind != w83697hf)
|
||||
if (kind != w83783s)
|
||||
device_create_file_temp(new_client, 3);
|
||||
|
||||
if (kind != w83697hf)
|
||||
device_create_file_vid(new_client);
|
||||
|
||||
if (kind != w83697hf)
|
||||
device_create_file_vrm(new_client);
|
||||
device_create_file_vid(new_client);
|
||||
device_create_file_vrm(new_client);
|
||||
|
||||
device_create_file_fan_div(new_client, 1);
|
||||
device_create_file_fan_div(new_client, 2);
|
||||
if (kind != w83697hf)
|
||||
device_create_file_fan_div(new_client, 3);
|
||||
device_create_file_fan_div(new_client, 3);
|
||||
|
||||
device_create_file_alarms(new_client);
|
||||
|
||||
@@ -1258,7 +1235,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
|
||||
if (kind != as99127f && kind != w83781d) {
|
||||
device_create_file_sensor(new_client, 1);
|
||||
device_create_file_sensor(new_client, 2);
|
||||
if (kind != w83783s && kind != w83697hf)
|
||||
if (kind != w83783s)
|
||||
device_create_file_sensor(new_client, 3);
|
||||
}
|
||||
|
||||
@@ -1481,7 +1458,7 @@ w83781d_init_client(struct i2c_client *client)
|
||||
else
|
||||
data->sens[i - 1] = 2;
|
||||
}
|
||||
if ((type == w83783s || type == w83697hf) && (i == 2))
|
||||
if (type == w83783s && i == 2)
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1497,7 +1474,7 @@ w83781d_init_client(struct i2c_client *client)
|
||||
}
|
||||
|
||||
/* Enable temp3 */
|
||||
if (type != w83783s && type != w83697hf) {
|
||||
if (type != w83783s) {
|
||||
tmp = w83781d_read_value(client,
|
||||
W83781D_REG_TEMP3_CONFIG);
|
||||
if (tmp & 0x01) {
|
||||
@@ -1538,8 +1515,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev)
|
||||
dev_dbg(dev, "Starting device update\n");
|
||||
|
||||
for (i = 0; i <= 8; i++) {
|
||||
if ((data->type == w83783s || data->type == w83697hf)
|
||||
&& (i == 1))
|
||||
if (data->type == w83783s && i == 1)
|
||||
continue; /* 783S has no in1 */
|
||||
data->in[i] =
|
||||
w83781d_read_value(client, W83781D_REG_IN(i));
|
||||
@@ -1547,7 +1523,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev)
|
||||
w83781d_read_value(client, W83781D_REG_IN_MIN(i));
|
||||
data->in_max[i] =
|
||||
w83781d_read_value(client, W83781D_REG_IN_MAX(i));
|
||||
if ((data->type != w83782d) && (data->type != w83697hf)
|
||||
if ((data->type != w83782d)
|
||||
&& (data->type != w83627hf) && (i == 6))
|
||||
break;
|
||||
}
|
||||
@@ -1583,7 +1559,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev)
|
||||
w83781d_read_value(client, W83781D_REG_TEMP_OVER(2));
|
||||
data->temp_max_hyst_add[0] =
|
||||
w83781d_read_value(client, W83781D_REG_TEMP_HYST(2));
|
||||
if (data->type != w83783s && data->type != w83697hf) {
|
||||
if (data->type != w83783s) {
|
||||
data->temp_add[1] =
|
||||
w83781d_read_value(client, W83781D_REG_TEMP(3));
|
||||
data->temp_max_add[1] =
|
||||
@@ -1594,26 +1570,18 @@ static struct w83781d_data *w83781d_update_device(struct device *dev)
|
||||
W83781D_REG_TEMP_HYST(3));
|
||||
}
|
||||
i = w83781d_read_value(client, W83781D_REG_VID_FANDIV);
|
||||
if (data->type != w83697hf) {
|
||||
data->vid = i & 0x0f;
|
||||
data->vid |=
|
||||
(w83781d_read_value(client, W83781D_REG_CHIPID) &
|
||||
0x01)
|
||||
<< 4;
|
||||
}
|
||||
data->vid = i & 0x0f;
|
||||
data->vid |= (w83781d_read_value(client,
|
||||
W83781D_REG_CHIPID) & 0x01) << 4;
|
||||
data->fan_div[0] = (i >> 4) & 0x03;
|
||||
data->fan_div[1] = (i >> 6) & 0x03;
|
||||
if (data->type != w83697hf) {
|
||||
data->fan_div[2] = (w83781d_read_value(client,
|
||||
W83781D_REG_PIN)
|
||||
>> 6) & 0x03;
|
||||
}
|
||||
data->fan_div[2] = (w83781d_read_value(client,
|
||||
W83781D_REG_PIN) >> 6) & 0x03;
|
||||
if ((data->type != w83781d) && (data->type != as99127f)) {
|
||||
i = w83781d_read_value(client, W83781D_REG_VBAT);
|
||||
data->fan_div[0] |= (i >> 3) & 0x04;
|
||||
data->fan_div[1] |= (i >> 4) & 0x04;
|
||||
if (data->type != w83697hf)
|
||||
data->fan_div[2] |= (i >> 5) & 0x04;
|
||||
data->fan_div[2] |= (i >> 5) & 0x04;
|
||||
}
|
||||
data->alarms =
|
||||
w83781d_read_value(client,
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl>
|
||||
SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
@@ -239,7 +238,7 @@ int i2c_del_adapter(struct i2c_adapter *adap)
|
||||
}
|
||||
|
||||
/* detach any active clients. This must be done first, because
|
||||
* it can fail; in which case we give upp. */
|
||||
* it can fail; in which case we give up. */
|
||||
list_for_each_safe(item, _n, &adap->clients) {
|
||||
client = list_entry(item, struct i2c_client, list);
|
||||
|
||||
@@ -612,27 +611,16 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
|
||||
struct i2c_adapter *adap=client->adapter;
|
||||
struct i2c_msg msg;
|
||||
|
||||
if (client->adapter->algo->master_xfer) {
|
||||
msg.addr = client->addr;
|
||||
msg.flags = client->flags & I2C_M_TEN;
|
||||
msg.len = count;
|
||||
msg.buf = (char *)buf;
|
||||
msg.addr = client->addr;
|
||||
msg.flags = client->flags & I2C_M_TEN;
|
||||
msg.len = count;
|
||||
msg.buf = (char *)buf;
|
||||
|
||||
dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n",
|
||||
count);
|
||||
|
||||
down(&adap->bus_lock);
|
||||
ret = adap->algo->master_xfer(adap,&msg,1);
|
||||
up(&adap->bus_lock);
|
||||
ret = i2c_transfer(adap, &msg, 1);
|
||||
|
||||
/* if everything went ok (i.e. 1 msg transmitted), return #bytes
|
||||
* transmitted, else error code.
|
||||
*/
|
||||
return (ret == 1 )? count : ret;
|
||||
} else {
|
||||
dev_err(&client->adapter->dev, "I2C level transfers not supported\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
/* If everything went ok (i.e. 1 msg transmitted), return #bytes
|
||||
transmitted, else error code. */
|
||||
return (ret == 1) ? count : ret;
|
||||
}
|
||||
|
||||
int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
|
||||
@@ -640,31 +628,18 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
|
||||
struct i2c_adapter *adap=client->adapter;
|
||||
struct i2c_msg msg;
|
||||
int ret;
|
||||
if (client->adapter->algo->master_xfer) {
|
||||
msg.addr = client->addr;
|
||||
msg.flags = client->flags & I2C_M_TEN;
|
||||
msg.flags |= I2C_M_RD;
|
||||
msg.len = count;
|
||||
msg.buf = buf;
|
||||
|
||||
dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n",
|
||||
count);
|
||||
|
||||
down(&adap->bus_lock);
|
||||
ret = adap->algo->master_xfer(adap,&msg,1);
|
||||
up(&adap->bus_lock);
|
||||
|
||||
dev_dbg(&client->adapter->dev, "master_recv: return:%d (count:%d, addr:0x%02x)\n",
|
||||
ret, count, client->addr);
|
||||
|
||||
/* if everything went ok (i.e. 1 msg transmitted), return #bytes
|
||||
* transmitted, else error code.
|
||||
*/
|
||||
return (ret == 1 )? count : ret;
|
||||
} else {
|
||||
dev_err(&client->adapter->dev, "I2C level transfers not supported\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
msg.addr = client->addr;
|
||||
msg.flags = client->flags & I2C_M_TEN;
|
||||
msg.flags |= I2C_M_RD;
|
||||
msg.len = count;
|
||||
msg.buf = buf;
|
||||
|
||||
ret = i2c_transfer(adap, &msg, 1);
|
||||
|
||||
/* If everything went ok (i.e. 1 msg transmitted), return #bytes
|
||||
transmitted, else error code. */
|
||||
return (ret == 1) ? count : ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -742,18 +717,6 @@ int i2c_probe(struct i2c_adapter *adapter,
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
for (i = 0;
|
||||
!found && (address_data->ignore_range[i] != I2C_CLIENT_END);
|
||||
i += 3) {
|
||||
if (((adap_id == address_data->ignore_range[i]) ||
|
||||
((address_data->ignore_range[i]==ANY_I2C_BUS))) &&
|
||||
(addr >= address_data->ignore_range[i+1]) &&
|
||||
(addr <= address_data->ignore_range[i+2])) {
|
||||
dev_dbg(&adapter->dev, "found ignore_range parameter for adapter %d, "
|
||||
"addr %04x\n", adap_id,addr);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
@@ -769,17 +732,6 @@ int i2c_probe(struct i2c_adapter *adapter,
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0;
|
||||
!found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END);
|
||||
i += 2) {
|
||||
if ((addr >= address_data->normal_i2c_range[i]) &&
|
||||
(addr <= address_data->normal_i2c_range[i+1])) {
|
||||
found = 1;
|
||||
dev_dbg(&adapter->dev, "found normal i2c_range entry for adapter %d, "
|
||||
"addr %04x\n", adap_id,addr);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0;
|
||||
!found && (address_data->probe[i] != I2C_CLIENT_END);
|
||||
i += 2) {
|
||||
@@ -791,18 +743,6 @@ int i2c_probe(struct i2c_adapter *adapter,
|
||||
"addr %04x\n", adap_id,addr);
|
||||
}
|
||||
}
|
||||
for (i = 0;
|
||||
!found && (address_data->probe_range[i] != I2C_CLIENT_END);
|
||||
i += 3) {
|
||||
if (((adap_id == address_data->probe_range[i]) ||
|
||||
(address_data->probe_range[i] == ANY_I2C_BUS)) &&
|
||||
(addr >= address_data->probe_range[i+1]) &&
|
||||
(addr <= address_data->probe_range[i+2])) {
|
||||
found = 1;
|
||||
dev_dbg(&adapter->dev, "found probe_range parameter for adapter %d, "
|
||||
"addr %04x\n", adap_id,addr);
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
continue;
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
/* The devfs code is contributed by Philipp Matthias Hahn
|
||||
<pmhahn@titan.lahn.de> */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
@@ -214,7 +213,7 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
|
||||
sizeof(rdwr_arg)))
|
||||
return -EFAULT;
|
||||
|
||||
/* Put an arbritrary limit on the number of messages that can
|
||||
/* Put an arbitrary limit on the number of messages that can
|
||||
* be sent at once */
|
||||
if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -51,8 +51,10 @@
|
||||
static int do_probe( struct i2c_adapter *adapter, int addr, int kind);
|
||||
|
||||
/* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */
|
||||
static unsigned short normal_i2c[] = { 0x49, 0x2c, I2C_CLIENT_END };
|
||||
static unsigned short normal_i2c_range[] = { 0x48, 0x4f, 0x2c, 0x2f, I2C_CLIENT_END };
|
||||
static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
|
||||
0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x2c, 0x2d, 0x2e, 0x2f,
|
||||
I2C_CLIENT_END };
|
||||
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
|
||||
@@ -384,22 +384,14 @@ static unsigned short normal_i2c[] =
|
||||
I2C_ADV7171 >> 1, (I2C_ADV7171 >> 1) + 1,
|
||||
I2C_CLIENT_END
|
||||
};
|
||||
static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
|
||||
|
||||
static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.normal_i2c_range = normal_i2c_range,
|
||||
.probe = probe,
|
||||
.probe_range = probe_range,
|
||||
.ignore = ignore,
|
||||
.ignore_range = ignore_range,
|
||||
.force = force
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
.force = &ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_adv7170;
|
||||
|
||||
@@ -434,22 +434,14 @@ static unsigned short normal_i2c[] =
|
||||
I2C_ADV7176 >> 1, (I2C_ADV7176 >> 1) + 1,
|
||||
I2C_CLIENT_END
|
||||
};
|
||||
static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
|
||||
|
||||
static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.normal_i2c_range = normal_i2c_range,
|
||||
.probe = probe,
|
||||
.probe_range = probe_range,
|
||||
.ignore = ignore,
|
||||
.ignore_range = ignore_range,
|
||||
.force = force
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
.force = &ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_adv7175;
|
||||
|
||||
@@ -500,22 +500,14 @@ static unsigned short normal_i2c[] = {
|
||||
I2C_BT819 >> 1,
|
||||
I2C_CLIENT_END,
|
||||
};
|
||||
static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
|
||||
|
||||
static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.normal_i2c_range = normal_i2c_range,
|
||||
.probe = probe,
|
||||
.probe_range = probe_range,
|
||||
.ignore = ignore,
|
||||
.ignore_range = ignore_range,
|
||||
.force = force
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
.force = &ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_bt819;
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = {I2C_CLIENT_END};
|
||||
static unsigned short normal_i2c_range[] = {I2C_BT832_ALT1>>1,I2C_BT832_ALT2>>1,I2C_CLIENT_END};
|
||||
static unsigned short normal_i2c[] = { I2C_BT832_ALT1>>1, I2C_BT832_ALT2>>1,
|
||||
I2C_CLIENT_END };
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
@@ -288,22 +288,14 @@ bt856_command (struct i2c_client *client,
|
||||
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
|
||||
*/
|
||||
static unsigned short normal_i2c[] = { I2C_BT856 >> 1, I2C_CLIENT_END };
|
||||
static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
|
||||
|
||||
static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.normal_i2c_range = normal_i2c_range,
|
||||
.probe = probe,
|
||||
.probe_range = probe_range,
|
||||
.ignore = ignore,
|
||||
.ignore_range = ignore_range,
|
||||
.force = force
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
.force = &ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_bt856;
|
||||
|
||||
@@ -147,7 +147,6 @@ static unsigned short normal_i2c[] = {
|
||||
I2C_MSP3400C_ALT >> 1,
|
||||
I2C_CLIENT_END
|
||||
};
|
||||
static unsigned short normal_i2c_range[] = {I2C_CLIENT_END,I2C_CLIENT_END};
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
@@ -64,7 +64,6 @@ static struct video_device saa_template; /* Declared near bottom */
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = { I2C_ADDRESS, I2C_CLIENT_END };
|
||||
static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
static struct i2c_client client_template;
|
||||
|
||||
@@ -132,7 +132,6 @@ static struct video_device saa_template; /* Declared near bottom */
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = {34>>1,I2C_CLIENT_END};
|
||||
static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
static struct i2c_client client_template;
|
||||
|
||||
@@ -463,22 +463,14 @@ static unsigned short normal_i2c[] = {
|
||||
(I2C_SAA7110 >> 1) + 1,
|
||||
I2C_CLIENT_END
|
||||
};
|
||||
static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
|
||||
|
||||
static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.normal_i2c_range = normal_i2c_range,
|
||||
.probe = probe,
|
||||
.probe_range = probe_range,
|
||||
.ignore = ignore,
|
||||
.ignore_range = ignore_range,
|
||||
.force = force
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
.force = &ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_saa7110;
|
||||
|
||||
@@ -482,22 +482,14 @@ saa7111_command (struct i2c_client *client,
|
||||
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
|
||||
*/
|
||||
static unsigned short normal_i2c[] = { I2C_SAA7111 >> 1, I2C_CLIENT_END };
|
||||
static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
|
||||
|
||||
static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.normal_i2c_range = normal_i2c_range,
|
||||
.probe = probe,
|
||||
.probe_range = probe_range,
|
||||
.ignore = ignore,
|
||||
.ignore_range = ignore_range,
|
||||
.force = force
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
.force = &ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_saa7111;
|
||||
|
||||
@@ -820,22 +820,14 @@ saa7114_command (struct i2c_client *client,
|
||||
*/
|
||||
static unsigned short normal_i2c[] =
|
||||
{ I2C_SAA7114 >> 1, I2C_SAA7114A >> 1, I2C_CLIENT_END };
|
||||
static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
|
||||
|
||||
static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.normal_i2c_range = normal_i2c_range,
|
||||
.probe = probe,
|
||||
.probe_range = probe_range,
|
||||
.ignore = ignore,
|
||||
.ignore_range = ignore_range,
|
||||
.force = force
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
.force = &ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_saa7114;
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
/* Addresses to scan */
|
||||
static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END};
|
||||
static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder");
|
||||
|
||||
@@ -380,22 +380,14 @@ saa7185_command (struct i2c_client *client,
|
||||
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
|
||||
*/
|
||||
static unsigned short normal_i2c[] = { I2C_SAA7185 >> 1, I2C_CLIENT_END };
|
||||
static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
|
||||
|
||||
static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END };
|
||||
static unsigned short ignore = I2C_CLIENT_END;
|
||||
|
||||
static struct i2c_client_address_data addr_data = {
|
||||
.normal_i2c = normal_i2c,
|
||||
.normal_i2c_range = normal_i2c_range,
|
||||
.probe = probe,
|
||||
.probe_range = probe_range,
|
||||
.ignore = ignore,
|
||||
.ignore_range = ignore_range,
|
||||
.force = force
|
||||
.probe = &ignore,
|
||||
.ignore = &ignore,
|
||||
.force = &ignore,
|
||||
};
|
||||
|
||||
static struct i2c_driver i2c_driver_saa7185;
|
||||
|
||||
@@ -74,7 +74,6 @@ static unsigned short normal_i2c[] = {
|
||||
I2C_TDA7432 >> 1,
|
||||
I2C_CLIENT_END,
|
||||
};
|
||||
static unsigned short normal_i2c_range[] = { I2C_CLIENT_END, I2C_CLIENT_END };
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
/* Structure of address and subaddresses for the tda7432 */
|
||||
|
||||
@@ -43,7 +43,6 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
|
||||
|
||||
/* addresses to scan, found only at 0x42 (7-Bit) */
|
||||
static unsigned short normal_i2c[] = { I2C_TDA9840, I2C_CLIENT_END };
|
||||
static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
|
||||
|
||||
/* magic definition of all other variables and things */
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
@@ -44,7 +44,6 @@ static unsigned short normal_i2c[] = {
|
||||
I2C_TDA9875 >> 1,
|
||||
I2C_CLIENT_END
|
||||
};
|
||||
static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
|
||||
I2C_CLIENT_INSMOD;
|
||||
|
||||
/* This is a superset of the TDA9875 */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user