Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
2864cffb
Commit
2864cffb
authored
May 19, 2003
by
Greg Kroah-Hartman
Browse files
Options
Browse Files
Download
Plain Diff
Merge
parents
d7b7a72d
7a503879
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
606 additions
and
70 deletions
+606
-70
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Kconfig
+25
-0
drivers/i2c/busses/Makefile
drivers/i2c/busses/Makefile
+1
-0
drivers/i2c/busses/i2c-piix4.c
drivers/i2c/busses/i2c-piix4.c
+2
-2
drivers/i2c/busses/i2c-sis96x.c
drivers/i2c/busses/i2c-sis96x.c
+376
-0
drivers/i2c/chips/it87.c
drivers/i2c/chips/it87.c
+0
-1
drivers/i2c/i2c-dev.c
drivers/i2c/i2c-dev.c
+158
-66
drivers/pci/quirks.c
drivers/pci/quirks.c
+40
-0
include/linux/i2c-id.h
include/linux/i2c-id.h
+1
-1
include/linux/pci_ids.h
include/linux/pci_ids.h
+3
-0
No files found.
drivers/i2c/busses/Kconfig
View file @
2864cffb
...
...
@@ -117,6 +117,31 @@ config I2C_PIIX4
http://www.lm-sensors.nu
config I2C_SIS96X
tristate " SiS 96x"
depends on I2C && PCI && EXPERIMENTAL
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
chipsets are supported:
645/961
645DX/961
645DX/962
648/961
650/961
735
This can also be built as a module which can be inserted and removed
while the kernel is running. If you want to compile it as a module,
say M here and read <file:Documentation/modules.txt>.
The module will be called i2c-sis96x.
You will also need the latest user-space utilties: you can find them
in the lm_sensors package, which you can download at
http://www.lm-sensors.nu
config I2C_VIAPRO
tristate " VIA 82C596/82C686/823x"
depends on I2C && PCI && EXPERIMENTAL
...
...
drivers/i2c/busses/Makefile
View file @
2864cffb
...
...
@@ -8,4 +8,5 @@ obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
obj-$(CONFIG_I2C_I801)
+=
i2c-i801.o
obj-$(CONFIG_I2C_ISA)
+=
i2c-isa.o
obj-$(CONFIG_I2C_PIIX4)
+=
i2c-piix4.o
obj-$(CONFIG_I2C_SIS96X)
+=
i2c-sis96x.o
obj-$(CONFIG_I2C_VIAPRO)
+=
i2c-viapro.o
drivers/i2c/busses/i2c-piix4.c
View file @
2864cffb
...
...
@@ -269,7 +269,7 @@ static int piix4_transaction(void)
if
(
temp
&
0x04
)
{
result
=
-
1
;
dev_
err
(
&
piix4_adapter
.
dev
,
"Error: no response!
\n
"
);
dev_
dbg
(
&
piix4_adapter
.
dev
,
"Error: no response!
\n
"
);
}
if
(
inb_p
(
SMBHSTSTS
)
!=
0x00
)
...
...
@@ -467,7 +467,7 @@ static void __devexit piix4_remove(struct pci_dev *dev)
static
struct
pci_driver
piix4_driver
=
{
.
name
=
"piix4
smbus"
,
.
name
=
"piix4
-
smbus"
,
.
id_table
=
piix4_ids
,
.
probe
=
piix4_probe
,
.
remove
=
__devexit_p
(
piix4_remove
),
...
...
drivers/i2c/busses/i2c-sis96x.c
0 → 100644
View file @
2864cffb
/*
sis96x.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (c) 2003 Mark M. Hoffman <mhoffman@lightlink.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; 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.
*/
/*
This module must be considered BETA unless and until
the chipset manufacturer releases a datasheet.
The register definitions are based on the SiS630.
This module relies on quirk_sis_96x_smbus (drivers/pci/quirks.c)
for just about every machine for which users have reported.
If this module isn't detecting your 96x south bridge, have a
look there.
We assume there can only be one SiS96x with one SMBus interface.
*/
/* #define DEBUG */
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <asm/io.h>
/*
HISTORY:
2003-05-11 1.0.0 Updated from lm_sensors project for kernel 2.5
(was i2c-sis645.c from lm_sensors 2.7.0)
*/
#define SIS96x_VERSION "1.0.0"
/* SiS96x SMBus PCI device ID */
#define PCI_DEVICE_ID_SI_SMBUS 0x16
/* base address register in PCI config space */
#define SIS96x_BAR 0x04
/* SiS96x SMBus registers */
#define SMB_STS 0x00
#define SMB_EN 0x01
#define SMB_CNT 0x02
#define SMB_HOST_CNT 0x03
#define SMB_ADDR 0x04
#define SMB_CMD 0x05
#define SMB_PCOUNT 0x06
#define SMB_COUNT 0x07
#define SMB_BYTE 0x08
#define SMB_DEV_ADDR 0x10
#define SMB_DB0 0x11
#define SMB_DB1 0x12
#define SMB_SAA 0x13
/* register count for request_region */
#define SMB_IOSIZE 0x20
/* Other settings */
#define MAX_TIMEOUT 500
/* SiS96x SMBus constants */
#define SIS96x_QUICK 0x00
#define SIS96x_BYTE 0x01
#define SIS96x_BYTE_DATA 0x02
#define SIS96x_WORD_DATA 0x03
#define SIS96x_PROC_CALL 0x04
#define SIS96x_BLOCK_DATA 0x05
static
struct
i2c_adapter
sis96x_adapter
;
static
u16
sis96x_smbus_base
=
0
;
static
inline
u8
sis96x_read
(
u8
reg
)
{
return
inb
(
sis96x_smbus_base
+
reg
)
;
}
static
inline
void
sis96x_write
(
u8
reg
,
u8
data
)
{
outb
(
data
,
sis96x_smbus_base
+
reg
)
;
}
/* Internally used pause function */
static
void
sis96x_do_pause
(
unsigned
int
amount
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule_timeout
(
amount
);
}
/* Execute a SMBus transaction.
int size is from SIS96x_QUICK to SIS96x_BLOCK_DATA
*/
static
int
sis96x_transaction
(
int
size
)
{
int
temp
;
int
result
=
0
;
int
timeout
=
0
;
dev_dbg
(
&
sis96x_adapter
.
dev
,
"SMBus transaction %d
\n
"
,
size
);
/* Make sure the SMBus host is ready to start transmitting */
if
(((
temp
=
sis96x_read
(
SMB_CNT
))
&
0x03
)
!=
0x00
)
{
dev_dbg
(
&
sis96x_adapter
.
dev
,
"SMBus busy (0x%02x). "
"Resetting...
\n
"
,
temp
);
/* kill the transaction */
sis96x_write
(
SMB_HOST_CNT
,
0x20
);
/* check it again */
if
(((
temp
=
sis96x_read
(
SMB_CNT
))
&
0x03
)
!=
0x00
)
{
dev_dbg
(
&
sis96x_adapter
.
dev
,
"Failed (0x%02x)
\n
"
,
temp
);
return
-
1
;
}
else
{
dev_dbg
(
&
sis96x_adapter
.
dev
,
"Successful
\n
"
);
}
}
/* Turn off timeout interrupts, set fast host clock */
sis96x_write
(
SMB_CNT
,
0x20
);
/* clear all (sticky) status flags */
temp
=
sis96x_read
(
SMB_STS
);
sis96x_write
(
SMB_STS
,
temp
&
0x1e
);
/* start the transaction by setting bit 4 and size bits */
sis96x_write
(
SMB_HOST_CNT
,
0x10
|
(
size
&
0x07
));
/* We will always wait for a fraction of a second! */
do
{
sis96x_do_pause
(
1
);
temp
=
sis96x_read
(
SMB_STS
);
}
while
(
!
(
temp
&
0x0e
)
&&
(
timeout
++
<
MAX_TIMEOUT
));
/* If the SMBus is still busy, we give up */
if
(
timeout
>=
MAX_TIMEOUT
)
{
dev_dbg
(
&
sis96x_adapter
.
dev
,
"SMBus Timeout! (0x%02x)
\n
"
,
temp
);
result
=
-
1
;
}
/* device error - probably missing ACK */
if
(
temp
&
0x02
)
{
dev_dbg
(
&
sis96x_adapter
.
dev
,
"Failed bus transaction!
\n
"
);
result
=
-
1
;
}
/* bus collision */
if
(
temp
&
0x04
)
{
dev_dbg
(
&
sis96x_adapter
.
dev
,
"Bus collision!
\n
"
);
result
=
-
1
;
}
/* Finish up by resetting the bus */
sis96x_write
(
SMB_STS
,
temp
);
if
((
temp
=
sis96x_read
(
SMB_STS
)))
{
dev_dbg
(
&
sis96x_adapter
.
dev
,
"Failed reset at "
"end of transaction! (0x%02x)
\n
"
,
temp
);
}
return
result
;
}
/* Return -1 on error. */
static
s32
sis96x_access
(
struct
i2c_adapter
*
adap
,
u16
addr
,
unsigned
short
flags
,
char
read_write
,
u8
command
,
int
size
,
union
i2c_smbus_data
*
data
)
{
switch
(
size
)
{
case
I2C_SMBUS_QUICK
:
sis96x_write
(
SMB_ADDR
,
((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
));
size
=
SIS96x_QUICK
;
break
;
case
I2C_SMBUS_BYTE
:
sis96x_write
(
SMB_ADDR
,
((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
));
if
(
read_write
==
I2C_SMBUS_WRITE
)
sis96x_write
(
SMB_CMD
,
command
);
size
=
SIS96x_BYTE
;
break
;
case
I2C_SMBUS_BYTE_DATA
:
sis96x_write
(
SMB_ADDR
,
((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
));
sis96x_write
(
SMB_CMD
,
command
);
if
(
read_write
==
I2C_SMBUS_WRITE
)
sis96x_write
(
SMB_BYTE
,
data
->
byte
);
size
=
SIS96x_BYTE_DATA
;
break
;
case
I2C_SMBUS_PROC_CALL
:
case
I2C_SMBUS_WORD_DATA
:
sis96x_write
(
SMB_ADDR
,
((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
));
sis96x_write
(
SMB_CMD
,
command
);
if
(
read_write
==
I2C_SMBUS_WRITE
)
{
sis96x_write
(
SMB_BYTE
,
data
->
word
&
0xff
);
sis96x_write
(
SMB_BYTE
+
1
,
(
data
->
word
&
0xff00
)
>>
8
);
}
size
=
(
size
==
I2C_SMBUS_PROC_CALL
?
SIS96x_PROC_CALL
:
SIS96x_WORD_DATA
);
break
;
case
I2C_SMBUS_BLOCK_DATA
:
/* TO DO: */
dev_info
(
&
adap
->
dev
,
"SMBus block not implemented!
\n
"
);
return
-
1
;
break
;
default:
dev_info
(
&
adap
->
dev
,
"Unsupported I2C size
\n
"
);
return
-
1
;
break
;
}
if
(
sis96x_transaction
(
size
))
return
-
1
;
if
((
size
!=
SIS96x_PROC_CALL
)
&&
((
read_write
==
I2C_SMBUS_WRITE
)
||
(
size
==
SIS96x_QUICK
)))
return
0
;
switch
(
size
)
{
case
SIS96x_BYTE
:
case
SIS96x_BYTE_DATA
:
data
->
byte
=
sis96x_read
(
SMB_BYTE
);
break
;
case
SIS96x_WORD_DATA
:
case
SIS96x_PROC_CALL
:
data
->
word
=
sis96x_read
(
SMB_BYTE
)
+
(
sis96x_read
(
SMB_BYTE
+
1
)
<<
8
);
break
;
}
return
0
;
}
static
u32
sis96x_func
(
struct
i2c_adapter
*
adapter
)
{
return
I2C_FUNC_SMBUS_QUICK
|
I2C_FUNC_SMBUS_BYTE
|
I2C_FUNC_SMBUS_BYTE_DATA
|
I2C_FUNC_SMBUS_WORD_DATA
|
I2C_FUNC_SMBUS_PROC_CALL
;
}
static
struct
i2c_algorithm
smbus_algorithm
=
{
.
name
=
"Non-I2C SMBus adapter"
,
.
id
=
I2C_ALGO_SMBUS
,
.
smbus_xfer
=
sis96x_access
,
.
functionality
=
sis96x_func
,
};
static
struct
i2c_adapter
sis96x_adapter
=
{
.
owner
=
THIS_MODULE
,
.
id
=
I2C_ALGO_SMBUS
|
I2C_HW_SMBUS_SIS96X
,
.
class
=
I2C_ADAP_CLASS_SMBUS
,
.
algo
=
&
smbus_algorithm
,
.
dev
=
{
.
name
=
"unset"
,
},
};
static
struct
pci_device_id
sis96x_ids
[]
__devinitdata
=
{
{
.
vendor
=
PCI_VENDOR_ID_SI
,
.
device
=
PCI_DEVICE_ID_SI_SMBUS
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
},
{
0
,
}
};
static
int
__devinit
sis96x_probe
(
struct
pci_dev
*
dev
,
const
struct
pci_device_id
*
id
)
{
u16
ww
=
0
;
int
retval
;
if
(
sis96x_smbus_base
)
{
dev_err
(
&
dev
->
dev
,
"Only one device supported.
\n
"
);
return
-
EBUSY
;
}
pci_read_config_word
(
dev
,
PCI_CLASS_DEVICE
,
&
ww
);
if
(
PCI_CLASS_SERIAL_SMBUS
!=
ww
)
{
dev_err
(
&
dev
->
dev
,
"Unsupported device class 0x%04x!
\n
"
,
ww
);
return
-
ENODEV
;
}
sis96x_smbus_base
=
pci_resource_start
(
dev
,
SIS96x_BAR
);
if
(
!
sis96x_smbus_base
)
{
dev_err
(
&
dev
->
dev
,
"SiS96x SMBus base address "
"not initialized!
\n
"
);
return
-
EINVAL
;
}
dev_info
(
&
dev
->
dev
,
"SiS96x SMBus base address: 0x%04x
\n
"
,
sis96x_smbus_base
);
/* Everything is happy, let's grab the memory and set things up. */
if
(
!
request_region
(
sis96x_smbus_base
,
SMB_IOSIZE
,
"sis96x-smbus"
))
{
dev_err
(
&
dev
->
dev
,
"SMBus registers 0x%04x-0x%04x "
"already in use!
\n
"
,
sis96x_smbus_base
,
sis96x_smbus_base
+
SMB_IOSIZE
-
1
);
sis96x_smbus_base
=
0
;
return
-
EINVAL
;
}
/* set up the driverfs linkage to our parent device */
sis96x_adapter
.
dev
.
parent
=
&
dev
->
dev
;
snprintf
(
sis96x_adapter
.
dev
.
name
,
DEVICE_NAME_SIZE
,
"SiS96x SMBus adapter at 0x%04x"
,
sis96x_smbus_base
);
if
((
retval
=
i2c_add_adapter
(
&
sis96x_adapter
)))
{
dev_err
(
&
dev
->
dev
,
"Couldn't register adapter!
\n
"
);
release_region
(
sis96x_smbus_base
,
SMB_IOSIZE
);
sis96x_smbus_base
=
0
;
}
return
retval
;
}
static
void
__devexit
sis96x_remove
(
struct
pci_dev
*
dev
)
{
if
(
sis96x_smbus_base
)
{
i2c_del_adapter
(
&
sis96x_adapter
);
release_region
(
sis96x_smbus_base
,
SMB_IOSIZE
);
sis96x_smbus_base
=
0
;
}
}
static
struct
pci_driver
sis96x_driver
=
{
.
name
=
"sis96x smbus"
,
.
id_table
=
sis96x_ids
,
.
probe
=
sis96x_probe
,
.
remove
=
__devexit_p
(
sis96x_remove
),
};
static
int
__init
i2c_sis96x_init
(
void
)
{
printk
(
KERN_INFO
"i2c-sis96x version %s
\n
"
,
SIS96x_VERSION
);
return
pci_module_init
(
&
sis96x_driver
);
}
static
void
__exit
i2c_sis96x_exit
(
void
)
{
pci_unregister_driver
(
&
sis96x_driver
);
}
MODULE_AUTHOR
(
"Mark M. Hoffman <mhoffman@lightlink.com>"
);
MODULE_DESCRIPTION
(
"SiS96x SMBus driver"
);
MODULE_LICENSE
(
"GPL"
);
/* Register initialization functions using helper macros */
module_init
(
i2c_sis96x_init
);
module_exit
(
i2c_sis96x_exit
);
drivers/i2c/chips/it87.c
View file @
2864cffb
...
...
@@ -630,7 +630,6 @@ int it87_detect(struct i2c_adapter *adapter, int address, int kind)
}
}
}
memset
(
new_client
,
0x00
,
sizeof
(
struct
i2c_client
)
+
sizeof
(
struct
it87_data
));
/* OK. For now, we presume we have a valid client. We now create the
client structure, even though we cannot fill it completely yet.
...
...
drivers/i2c/i2c-dev.c
View file @
2864cffb
...
...
@@ -3,6 +3,7 @@
Copyright (C) 1995-97 Simon G. Vogl
Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.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
...
...
@@ -28,8 +29,6 @@
/* The devfs code is contributed by Philipp Matthias Hahn
<pmhahn@titan.lahn.de> */
/* $Id: i2c-dev.c,v 1.53 2003/01/21 08:08:16 kmalkki Exp $ */
/* If you want debugging uncomment: */
/* #define DEBUG 1 */
...
...
@@ -44,54 +43,84 @@
#include <linux/i2c-dev.h>
#include <asm/uaccess.h>
/* struct file_operations changed too often in the 2.1 series for nice code */
static
struct
i2c_client
i2cdev_client_template
;
static
ssize_t
i2cdev_read
(
struct
file
*
file
,
char
*
buf
,
size_t
count
,
loff_t
*
offset
);
static
ssize_t
i2cdev_write
(
struct
file
*
file
,
const
char
*
buf
,
size_t
count
,
loff_t
*
offset
);
struct
i2c_dev
{
int
minor
;
struct
i2c_adapter
*
adap
;
struct
class_device
class_dev
;
};
#define to_i2c_dev(d) container_of(d, struct i2c_dev, class_dev)
static
int
i2cdev_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
;
static
int
i2cdev_open
(
struct
inode
*
inode
,
struct
file
*
file
)
;
#define I2C_MINORS 256
static
struct
i2c_dev
*
i2c_dev_array
[
I2C_MINORS
]
;
static
spinlock_t
i2c_dev_array_lock
=
SPIN_LOCK_UNLOCKED
;
static
int
i2cdev_release
(
struct
inode
*
inode
,
struct
file
*
file
);
struct
i2c_dev
*
i2c_dev_get_by_minor
(
unsigned
index
)
{
struct
i2c_dev
*
i2c_dev
;
static
int
i2cdev_attach_adapter
(
struct
i2c_adapter
*
adap
);
static
int
i2cdev_detach_adapter
(
struct
i2c_adapter
*
adap
)
;
static
int
i2cdev_detach_client
(
struct
i2c_client
*
client
);
static
int
i2cdev_command
(
struct
i2c_client
*
client
,
unsigned
int
cmd
,
void
*
arg
);
spin_lock
(
&
i2c_dev_array_lock
);
i2c_dev
=
i2c_dev_array
[
index
]
;
spin_unlock
(
&
i2c_dev_array_lock
);
return
i2c_dev
;
}
static
struct
file_operations
i2cdev_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
read
=
i2cdev_read
,
.
write
=
i2cdev_write
,
.
ioctl
=
i2cdev_ioctl
,
.
open
=
i2cdev_open
,
.
release
=
i2cdev_release
,
};
struct
i2c_dev
*
i2c_dev_get_by_adapter
(
struct
i2c_adapter
*
adap
)
{
struct
i2c_dev
*
i2c_dev
=
NULL
;
int
i
;
static
struct
i2c_driver
i2cdev_driver
=
{
.
owner
=
THIS_MODULE
,
.
name
=
"dev driver"
,
.
id
=
I2C_DRIVERID_I2CDEV
,
.
flags
=
I2C_DF_NOTIFY
,
.
attach_adapter
=
i2cdev_attach_adapter
,
.
detach_adapter
=
i2cdev_detach_adapter
,
.
detach_client
=
i2cdev_detach_client
,
.
command
=
i2cdev_command
,
};
spin_lock
(
&
i2c_dev_array_lock
);
for
(
i
=
0
;
i
<
I2C_MINORS
;
++
i
)
{
if
((
i2c_dev_array
[
i
])
&&
(
i2c_dev_array
[
i
]
->
adap
==
adap
))
{
i2c_dev
=
i2c_dev_array
[
i
];
break
;
}
}
spin_unlock
(
&
i2c_dev_array_lock
);
return
i2c_dev
;
}
static
struct
i2c_client
i2cdev_client_template
=
{
.
dev
=
{
.
name
=
"I2C /dev entry"
,
},
.
id
=
1
,
.
addr
=
-
1
,
.
driver
=
&
i2cdev_driver
,
};
static
struct
i2c_dev
*
get_free_i2c_dev
(
void
)
{
struct
i2c_dev
*
i2c_dev
;
unsigned
int
i
;
i2c_dev
=
kmalloc
(
sizeof
(
*
i2c_dev
),
GFP_KERNEL
);
if
(
!
i2c_dev
)
return
ERR_PTR
(
-
ENOMEM
);
memset
(
i2c_dev
,
0x00
,
sizeof
(
*
i2c_dev
));
spin_lock
(
&
i2c_dev_array_lock
);
for
(
i
=
0
;
i
<
I2C_MINORS
;
++
i
)
{
if
(
i2c_dev_array
[
i
])
continue
;
i2c_dev
->
minor
=
i
;
i2c_dev_array
[
i
]
=
i2c_dev
;
spin_unlock
(
&
i2c_dev_array_lock
);
return
i2c_dev
;
}
spin_unlock
(
&
i2c_dev_array_lock
);
kfree
(
i2c_dev
);
return
ERR_PTR
(
-
ENODEV
);
}
static
void
return_i2c_dev
(
struct
i2c_dev
*
i2c_dev
)
{
spin_lock
(
&
i2c_dev_array_lock
);
i2c_dev_array
[
i2c_dev
->
minor
]
=
NULL
;
spin_unlock
(
&
i2c_dev_array_lock
);
kfree
(
i2c_dev
);
}
static
ssize_t
show_dev
(
struct
class_device
*
class_dev
,
char
*
buf
)
{
struct
i2c_dev
*
i2c_dev
=
to_i2c_dev
(
class_dev
);
return
sprintf
(
buf
,
"%04x
\n
"
,
MKDEV
(
I2C_MAJOR
,
i2c_dev
->
minor
));
}
static
CLASS_DEVICE_ATTR
(
dev
,
S_IRUGO
,
show_dev
,
NULL
);
static
ssize_t
i2cdev_read
(
struct
file
*
file
,
char
*
buf
,
size_t
count
,
loff_t
*
offset
)
...
...
@@ -104,7 +133,6 @@ static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
if
(
count
>
8192
)
count
=
8192
;
/* copy user space data to kernel space. */
tmp
=
kmalloc
(
count
,
GFP_KERNEL
);
if
(
tmp
==
NULL
)
return
-
ENOMEM
;
...
...
@@ -129,7 +157,6 @@ static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count,
if
(
count
>
8192
)
count
=
8192
;
/* copy user space data to kernel space. */
tmp
=
kmalloc
(
count
,
GFP_KERNEL
);
if
(
tmp
==
NULL
)
return
-
ENOMEM
;
...
...
@@ -157,7 +184,7 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
int
i
,
datasize
,
res
;
unsigned
long
funcs
;
pr_debug
(
"i2c-dev.o:
i2c-%d ioctl, cmd: 0x%x, arg: %lx.
\n
"
,
dev_dbg
(
&
client
->
dev
,
"
i2c-%d ioctl, cmd: 0x%x, arg: %lx.
\n
"
,
minor
(
inode
->
i_rdev
),
cmd
,
arg
);
switch
(
cmd
)
{
...
...
@@ -242,13 +269,11 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
rdwr_arg
.
nmsgs
);
}
while
(
i
--
>
0
)
{
if
(
res
>=
0
&&
(
rdwr_pa
[
i
].
flags
&
I2C_M_RD
))
{
if
(
res
>=
0
&&
(
rdwr_pa
[
i
].
flags
&
I2C_M_RD
))
{
if
(
copy_to_user
(
rdwr_arg
.
msgs
[
i
].
buf
,
rdwr_pa
[
i
].
buf
,
rdwr_pa
[
i
].
len
))
{
rdwr_pa
[
i
].
len
))
{
res
=
-
EFAULT
;
}
}
...
...
@@ -340,9 +365,14 @@ static int i2cdev_open(struct inode *inode, struct file *file)
unsigned
int
minor
=
minor
(
inode
->
i_rdev
);
struct
i2c_client
*
client
;
struct
i2c_adapter
*
adap
;
struct
i2c_dev
*
i2c_dev
;
i2c_dev
=
i2c_dev_get_by_minor
(
minor
);
if
(
!
i2c_dev
)
return
-
ENODEV
;
adap
=
i2c_get_adapter
(
mino
r
);
if
(
NULL
==
adap
)
adap
=
i2c_get_adapter
(
i2c_dev
->
adap
->
n
r
);
if
(
!
adap
)
return
-
ENODEV
;
client
=
kmalloc
(
sizeof
(
*
client
),
GFP_KERNEL
);
...
...
@@ -370,29 +400,68 @@ static int i2cdev_release(struct inode *inode, struct file *file)
return
0
;
}
int
i2cdev_attach_adapter
(
struct
i2c_adapter
*
adap
)
{
int
i
;
static
struct
file_operations
i2cdev_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
read
=
i2cdev_read
,
.
write
=
i2cdev_write
,
.
ioctl
=
i2cdev_ioctl
,
.
open
=
i2cdev_open
,
.
release
=
i2cdev_release
,
};
i
=
i2c_adapter_id
(
adap
);
devfs_mk_cdev
(
MKDEV
(
I2C_MAJOR
,
i
),
S_IFCHR
|
S_IRUSR
|
S_IWUSR
,
"i2c/%d"
,
i
);
dev_dbg
(
&
adap
->
dev
,
"Registered as minor %d
\n
"
,
i
);
static
struct
class
i2c_dev_class
=
{
.
name
=
"i2c-dev"
,
};
static
int
i2cdev_attach_adapter
(
struct
i2c_adapter
*
adap
)
{
struct
i2c_dev
*
i2c_dev
;
int
retval
;
i2c_dev
=
get_free_i2c_dev
();
if
(
IS_ERR
(
i2c_dev
))
return
PTR_ERR
(
i2c_dev
);
devfs_mk_cdev
(
MKDEV
(
I2C_MAJOR
,
i2c_dev
->
minor
),
S_IFCHR
|
S_IRUSR
|
S_IWUSR
,
"i2c/%d"
,
i2c_dev
->
minor
);
dev_dbg
(
&
adap
->
dev
,
"Registered as minor %d
\n
"
,
i2c_dev
->
minor
);
/* register this i2c device with the driver core */
i2c_dev
->
adap
=
adap
;
if
(
adap
->
dev
.
parent
==
&
legacy_bus
)
i2c_dev
->
class_dev
.
dev
=
&
adap
->
dev
;
else
i2c_dev
->
class_dev
.
dev
=
adap
->
dev
.
parent
;
i2c_dev
->
class_dev
.
class
=
&
i2c_dev_class
;
snprintf
(
i2c_dev
->
class_dev
.
class_id
,
BUS_ID_SIZE
,
"i2c-%d"
,
i2c_dev
->
minor
);
retval
=
class_device_register
(
&
i2c_dev
->
class_dev
);
if
(
retval
)
goto
error
;
class_device_create_file
(
&
i2c_dev
->
class_dev
,
&
class_device_attr_dev
);
return
0
;
error:
return_i2c_dev
(
i2c_dev
);
return
retval
;
}
int
i2cdev_detach_adapter
(
struct
i2c_adapter
*
adap
)
static
int
i2cdev_detach_adapter
(
struct
i2c_adapter
*
adap
)
{
int
i
;
struct
i2c_dev
*
i2c_dev
;
i
=
i2c_adapter_id
(
adap
);
i2c_dev
=
i2c_dev_get_by_adapter
(
adap
);
if
(
!
i2c_dev
)
return
-
ENODEV
;
class_device_unregister
(
&
i2c_dev
->
class_dev
);
devfs_remove
(
"i2c/%d"
,
i2c_dev
->
minor
);
return_i2c_dev
(
i2c_dev
);
devfs_remove
(
"i2c/%d"
,
i
);
dev_dbg
(
&
adap
->
dev
,
"Adapter unregistered
\n
"
);
return
0
;
}
int
i2cdev_detach_client
(
struct
i2c_client
*
client
)
static
int
i2cdev_detach_client
(
struct
i2c_client
*
client
)
{
return
0
;
}
...
...
@@ -403,7 +472,27 @@ static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
return
-
1
;
}
int
__init
i2c_dev_init
(
void
)
static
struct
i2c_driver
i2cdev_driver
=
{
.
owner
=
THIS_MODULE
,
.
name
=
"dev driver"
,
.
id
=
I2C_DRIVERID_I2CDEV
,
.
flags
=
I2C_DF_NOTIFY
,
.
attach_adapter
=
i2cdev_attach_adapter
,
.
detach_adapter
=
i2cdev_detach_adapter
,
.
detach_client
=
i2cdev_detach_client
,
.
command
=
i2cdev_command
,
};
static
struct
i2c_client
i2cdev_client_template
=
{
.
dev
=
{
.
name
=
"I2C /dev entry"
,
},
.
id
=
1
,
.
addr
=
-
1
,
.
driver
=
&
i2cdev_driver
,
};
static
int
__init
i2c_dev_init
(
void
)
{
int
res
;
...
...
@@ -416,6 +505,7 @@ int __init i2c_dev_init(void)
return
-
EIO
;
}
devfs_mk_dir
(
"i2c"
);
class_register
(
&
i2c_dev_class
);
if
((
res
=
i2c_add_driver
(
&
i2cdev_driver
)))
{
printk
(
KERN_ERR
"i2c-dev.o: Driver registration failed, module not inserted.
\n
"
);
devfs_remove
(
"i2c"
);
...
...
@@ -428,11 +518,13 @@ int __init i2c_dev_init(void)
static
void
__exit
i2c_dev_exit
(
void
)
{
i2c_del_driver
(
&
i2cdev_driver
);
class_unregister
(
&
i2c_dev_class
);
devfs_remove
(
"i2c"
);
unregister_chrdev
(
I2C_MAJOR
,
"i2c"
);
}
MODULE_AUTHOR
(
"Frodo Looijaard <frodol@dds.nl> and Simon G. Vogl <simon@tk.uni-linz.ac.at>"
);
MODULE_AUTHOR
(
"Frodo Looijaard <frodol@dds.nl> and "
"Simon G. Vogl <simon@tk.uni-linz.ac.at>"
);
MODULE_DESCRIPTION
(
"I2C /dev entries driver"
);
MODULE_LICENSE
(
"GPL"
);
...
...
drivers/pci/quirks.c
View file @
2864cffb
...
...
@@ -696,6 +696,37 @@ static void __init asus_hides_smbus_lpc(struct pci_dev *dev)
}
}
/*
* SiS 96x south bridge: BIOS typically hides SMBus device...
*/
static
void
__init
quirk_sis_96x_smbus
(
struct
pci_dev
*
dev
)
{
u8
val
=
0
;
printk
(
KERN_INFO
"Enabling SiS 96x SMBus.
\n
"
);
pci_read_config_byte
(
dev
,
0x77
,
&
val
);
pci_write_config_byte
(
dev
,
0x77
,
val
&
~
0x10
);
pci_read_config_byte
(
dev
,
0x77
,
&
val
);
}
/*
* ... This is further complicated by the fact that some SiS96x south
* bridges pretend to be 85C503/5513 instead. In that case see if we
* spotted a compatible north bridge to make sure.
* (pci_find_device doesn't work yet)
*/
static
int
__devinitdata
sis_96x_compatible
=
0
;
static
void
__init
quirk_sis_503_smbus
(
struct
pci_dev
*
dev
)
{
if
(
sis_96x_compatible
)
quirk_sis_96x_smbus
(
dev
);
}
static
void
__init
quirk_sis_96x_compatible
(
struct
pci_dev
*
dev
)
{
sis_96x_compatible
=
1
;
}
/*
* The main table of quirks.
*/
...
...
@@ -729,6 +760,15 @@ static struct pci_fixup pci_fixups[] __devinitdata = {
{
PCI_FIXUP_FINAL
,
PCI_VENDOR_ID_INTEL
,
PCI_DEVICE_ID_INTEL_82443BX_2
,
quirk_natoma
},
{
PCI_FIXUP_FINAL
,
PCI_VENDOR_ID_SI
,
PCI_DEVICE_ID_SI_5597
,
quirk_nopcipci
},
{
PCI_FIXUP_FINAL
,
PCI_VENDOR_ID_SI
,
PCI_DEVICE_ID_SI_496
,
quirk_nopcipci
},
{
PCI_FIXUP_HEADER
,
PCI_VENDOR_ID_SI
,
PCI_DEVICE_ID_SI_503
,
quirk_sis_503_smbus
},
{
PCI_FIXUP_HEADER
,
PCI_VENDOR_ID_SI
,
PCI_DEVICE_ID_SI_645
,
quirk_sis_96x_compatible
},
{
PCI_FIXUP_HEADER
,
PCI_VENDOR_ID_SI
,
PCI_DEVICE_ID_SI_646
,
quirk_sis_96x_compatible
},
{
PCI_FIXUP_HEADER
,
PCI_VENDOR_ID_SI
,
PCI_DEVICE_ID_SI_648
,
quirk_sis_96x_compatible
},
{
PCI_FIXUP_HEADER
,
PCI_VENDOR_ID_SI
,
PCI_DEVICE_ID_SI_650
,
quirk_sis_96x_compatible
},
{
PCI_FIXUP_HEADER
,
PCI_VENDOR_ID_SI
,
PCI_DEVICE_ID_SI_651
,
quirk_sis_96x_compatible
},
{
PCI_FIXUP_HEADER
,
PCI_VENDOR_ID_SI
,
PCI_DEVICE_ID_SI_961
,
quirk_sis_96x_smbus
},
{
PCI_FIXUP_HEADER
,
PCI_VENDOR_ID_SI
,
PCI_DEVICE_ID_SI_962
,
quirk_sis_96x_smbus
},
{
PCI_FIXUP_HEADER
,
PCI_VENDOR_ID_SI
,
PCI_DEVICE_ID_SI_963
,
quirk_sis_96x_smbus
},
{
PCI_FIXUP_FINAL
,
PCI_VENDOR_ID_AL
,
PCI_DEVICE_ID_AL_M1647
,
quirk_alimagik
},
{
PCI_FIXUP_FINAL
,
PCI_VENDOR_ID_AL
,
PCI_DEVICE_ID_AL_M1651
,
quirk_alimagik
},
{
PCI_FIXUP_FINAL
,
PCI_VENDOR_ID_VIA
,
PCI_DEVICE_ID_VIA_8363_0
,
quirk_vialatency
},
...
...
include/linux/i2c-id.h
View file @
2864cffb
...
...
@@ -245,7 +245,7 @@
#define I2C_HW_SMBUS_SIS5595 0x06
#define I2C_HW_SMBUS_ALI1535 0x07
#define I2C_HW_SMBUS_SIS630 0x08
#define I2C_HW_SMBUS_SIS
645
0x09
#define I2C_HW_SMBUS_SIS
96X
0x09
#define I2C_HW_SMBUS_AMD8111 0x0a
#define I2C_HW_SMBUS_SCX200 0x0b
#define I2C_HW_SMBUS_NFORCE2 0x0c
...
...
include/linux/pci_ids.h
View file @
2864cffb
...
...
@@ -569,6 +569,9 @@
#define PCI_DEVICE_ID_SI_751 0x0751
#define PCI_DEVICE_ID_SI_752 0x0752
#define PCI_DEVICE_ID_SI_900 0x0900
#define PCI_DEVICE_ID_SI_961 0x0961
#define PCI_DEVICE_ID_SI_962 0x0962
#define PCI_DEVICE_ID_SI_963 0x0963
#define PCI_DEVICE_ID_SI_5107 0x5107
#define PCI_DEVICE_ID_SI_5300 0x5300
#define PCI_DEVICE_ID_SI_5511 0x5511
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment