Compare commits
4 Commits
v5.6.4+crt
...
master
Author | SHA1 | Date |
---|---|---|
crt0mega | d6c6bb864a | |
crt0mega | 246ea0e38a | |
crt0mega | b92c0cfb86 | |
crt0mega | 1dc9218f63 |
12
README.md
12
README.md
|
@ -1,12 +1,16 @@
|
|||
# i2c-piix4-aura-dkms
|
||||
# openrgb-dkms-drivers
|
||||
|
||||
## Intro
|
||||
This repository contains a patched i2c-piix4 module which supports the secondary i2c controller on several >= X370 AM4 mainboards as DKMS-package for Debian GNU/Linux Unstable. This package might work with earlier versions of Debian but mileage may vary. It is designed as a soft dependency for future packaged versions of [OpenRGB](https://gitlab.com/CalcProgrammer1/OpenRGB) to enable access to RGB LED settings of these mainboards.
|
||||
This repository contains OpenRGB's i2c-piix4 and i2c-nct6775 drivers as DKMS kernel modules. The i2c-piix4 driver supports the secondary i2c controller on several >= X370 AM4 mainboards. This package is designed for Debian Unstable but might work with earlier versions of Debian, mileage may vary. It is designed as a soft dependency for future packaged versions of [OpenRGB](https://gitlab.com/CalcProgrammer1/OpenRGB) to enable access to RGB controllers on certain mainboards, namely boards with ASUS Aura and ASRock Polychrome RGB systems.
|
||||
|
||||
The original idea of patching and packaging this module was *lend* from the package i2c-piix4-aura-dkms found at [Arch Linux AUR](https://aur.archlinux.org/packages/i2c-piix4-aura-dkms). I have only changed some Debian-specific pathes and added some packaging information with debhelper.
|
||||
|
||||
## Usage
|
||||
Clone this repository and run `dpkg-buildpackage -us -uc -b`. Install the resulting package with `sudo dpkg -i path/to.deb`.
|
||||
To have OpenRGB controlling your LEDs you either need to add your user to the group `adm` or simply run OpenRGB as root. I'd rather not recommend to run any GUI application with root privileges.
|
||||
THX
|
||||
|
||||
## Thanks to
|
||||
- [CalcProgrammer1](https://gitlab.com/CalcProgrammer1) for his awesome work on OpenAuraSDK/OpenRGB and his fix for i2c-piix4,
|
||||
- [CalcProgrammer1](https://gitlab.com/CalcProgrammer1) for his awesome work on OpenAuraSDK/OpenRGB and his fix for i2c-piix4 (I swear that this was already in here when I forked it),
|
||||
- Térence Clastres for the awesome idea of squeezing this patch into a DKMS package and
|
||||
- my gf for sharing and supporting my obsession with RGB LED stuff and Linux.
|
||||
- [SurfsideShip264](https://www.reddit.com/user/SurfsideShip264/) for pointing out an issue with the build-dependencies
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
i2c-piix4-aura-dkms (5.6.4) unstable; urgency=medium
|
||||
openrgb-dkms-drivers (5.6.4-1) unstable; urgency=medium
|
||||
|
||||
* Changed package arch from all to amd64
|
||||
|
||||
-- crt0mega <crt0mega@c-r-t.tk> Fri, 19 Mar 2021 10:38:44 +0100
|
||||
|
||||
openrgb-dkms-drivers (5.6.4) unstable; urgency=medium
|
||||
|
||||
* Initial Release.
|
||||
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
Source: i2c-piix4-aura-dkms
|
||||
Source: openrgb-dkms-drivers
|
||||
Section: unknown
|
||||
Priority: optional
|
||||
Maintainer: crt0mega <crt0mega@c-r-t.tk>
|
||||
Build-Depends: debhelper-compat (= 12)
|
||||
Build-Depends: debhelper-compat (= 11), dkms
|
||||
Standards-Version: 4.4.1
|
||||
#Homepage: <insert the upstream URL, if relevant>
|
||||
#Vcs-Browser: https://salsa.debian.org/debian/i2c-piix4-aura-dkms-5.4.6
|
||||
#Vcs-Git: https://salsa.debian.org/debian/i2c-piix4-aura-dkms-5.4.6.git
|
||||
|
||||
Package: i2c-piix4-aura-dkms
|
||||
Architecture: all
|
||||
Package: openrgb-dkms-drivers
|
||||
Architecture: amd64
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, dkms
|
||||
Description: The i2c-piix4 kernel driver, patched to be used with OpenRGB
|
||||
i2c-piix4 needs a patch to enable a second SMBUS controller (see
|
||||
Bug 202587 at Kernel.org Bugzilla). This package provides a patched module
|
||||
ready for DKMS as well as some helper files found at Archlinux' AUR.
|
||||
Replaces: i2c-piix4-aura-dkms
|
||||
Breaks: i2c-piix4-aura-dkms
|
||||
Description: OpenRGB kernel patch includes the i2c-piix4 kernel driver,
|
||||
patched to enable a second SMBUS controller on AMD AM4 chipsets (see
|
||||
Bug 202587 at Kernel.org Bugzilla), as well as the i2c-nct6775 kernel
|
||||
driver which provides access to Nuvoton Super-IO chips' SMBus
|
||||
controllers. This package provides a patched module ready for DKMS as
|
||||
well as some helper files found at Archlinux' AUR.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: i2c-piix4-aura-dkms-5.4.6
|
||||
Upstream-Name: openrgb-dkms-drivers-5.4.6
|
||||
Upstream-Contact: <preferred name and address to reach the upstream project>
|
||||
Source: <url://example.com>
|
||||
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
PACKAGE_NAME="i2c-piix4-aura"
|
||||
PACKAGE_NAME="openrgb-dkms-drivers"
|
||||
PACKAGE_VERSION="5.4.6"
|
||||
|
||||
BUILT_MODULE_NAME[0]="i2c-piix4"
|
||||
MAKE[0]="make"
|
||||
DEST_MODULE_LOCATION[0]="/kernel/drivers/i2c/busses"
|
||||
|
||||
BUILT_MODULE_NAME[1]="i2c-nct6775"
|
||||
MAKE[1]="make"
|
||||
DEST_MODULE_LOCATION[1]="/kernel/drivers/i2c/busses"
|
||||
|
||||
AUTOINSTALL="yes"
|
||||
|
|
|
@ -18,9 +18,14 @@ VERSION=$(shell dpkg-parsechangelog |grep ^Version:|cut -d ' ' -f 2)
|
|||
dh $@ --with dkms
|
||||
|
||||
override_dh_install:
|
||||
dh_install src/Makefile src/i2c-piix4.c usr/src/i2c-piix4-aura-$(VERSION)/
|
||||
dh_install src/90-i2c-aura.rules lib/udev/rules.d/
|
||||
dh_install src/i2c-aura.conf usr/lib/modules-load.d/
|
||||
# i2c-piix4 source
|
||||
dh_install src/Makefile src/i2c-piix4.c usr/src/openrgb-dkms-drivers-$(VERSION)/
|
||||
|
||||
# i2c-nct6775 source
|
||||
dh_install src/Makefile src/i2c-nct6775.c usr/src/openrgb-dkms-drivers-$(VERSION)/
|
||||
|
||||
# modules-load configuration
|
||||
dh_install src/i2c-openrgb.conf usr/lib/modules-load.d/
|
||||
|
||||
override_dh_dkms:
|
||||
dh_dkms -V $(VERSION)
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
KERNEL=="i2c-*", ATTR{name}=="SMBus*" SUBSYSTEM=="i2c-dev" MODE="0660", GROUP="adm"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
obj-m := i2c-piix4.o
|
||||
obj-m := i2c-piix4.o i2c-nct6775.o
|
||||
|
||||
ifndef KERNELRELEASE
|
||||
KRELEASE := $(shell uname -r)
|
||||
|
|
|
@ -0,0 +1,647 @@
|
|||
/*
|
||||
* i2c-nct6775 - Driver for the SMBus master functionality of
|
||||
* Nuvoton NCT677x Super-I/O chips
|
||||
*
|
||||
* Copyright (C) 2019 Adam Honse <calcprogrammer1@gmail.com>
|
||||
*
|
||||
* Derived from nct6775 hwmon driver
|
||||
* Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/hwmon-vid.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/nospec.h>
|
||||
|
||||
#define DRVNAME "i2c-nct6775"
|
||||
|
||||
/* Nuvoton SMBus address offsets */
|
||||
#define SMBHSTDAT (0 + nuvoton_nct6793d_smba)
|
||||
#define SMBBLKSZ (1 + nuvoton_nct6793d_smba)
|
||||
#define SMBHSTCMD (2 + nuvoton_nct6793d_smba)
|
||||
#define SMBHSTIDX (3 + nuvoton_nct6793d_smba) //Index field is the Command field on other controllers
|
||||
#define SMBHSTCTL (4 + nuvoton_nct6793d_smba)
|
||||
#define SMBHSTADD (5 + nuvoton_nct6793d_smba)
|
||||
#define SMBHSTERR (9 + nuvoton_nct6793d_smba)
|
||||
#define SMBHSTSTS (0xE + nuvoton_nct6793d_smba)
|
||||
|
||||
/* Command register */
|
||||
#define NCT6793D_READ_BYTE 0
|
||||
#define NCT6793D_READ_WORD 1
|
||||
#define NCT6793D_READ_BLOCK 2
|
||||
#define NCT6793D_BLOCK_WRITE_READ_PROC_CALL 3
|
||||
#define NCT6793D_PROC_CALL 4
|
||||
#define NCT6793D_WRITE_BYTE 8
|
||||
#define NCT6793D_WRITE_WORD 9
|
||||
#define NCT6793D_WRITE_BLOCK 10
|
||||
|
||||
/* Control register */
|
||||
#define NCT6793D_MANUAL_START 128
|
||||
#define NCT6793D_SOFT_RESET 64
|
||||
|
||||
/* Error register */
|
||||
#define NCT6793D_NO_ACK 32
|
||||
|
||||
/* Status register */
|
||||
#define NCT6793D_FIFO_EMPTY 1
|
||||
#define NCT6793D_FIFO_FULL 2
|
||||
#define NCT6793D_MANUAL_ACTIVE 4
|
||||
|
||||
#define NCT6775_LD_SMBUS 0x0B
|
||||
|
||||
/* Other settings */
|
||||
#define MAX_RETRIES 400
|
||||
|
||||
enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
|
||||
nct6795, nct6796, nct6798 };
|
||||
|
||||
struct nct6775_sio_data {
|
||||
int sioreg;
|
||||
enum kinds kind;
|
||||
};
|
||||
|
||||
/* used to set data->name = nct6775_device_names[data->sio_kind] */
|
||||
static const char * const nct6775_device_names[] = {
|
||||
"nct6106",
|
||||
"nct6775",
|
||||
"nct6776",
|
||||
"nct6779",
|
||||
"nct6791",
|
||||
"nct6792",
|
||||
"nct6793",
|
||||
"nct6795",
|
||||
"nct6796",
|
||||
"nct6798",
|
||||
};
|
||||
|
||||
static const char * const nct6775_sio_names[] __initconst = {
|
||||
"NCT6106D",
|
||||
"NCT6775F",
|
||||
"NCT6776D/F",
|
||||
"NCT6779D",
|
||||
"NCT6791D",
|
||||
"NCT6792D",
|
||||
"NCT6793D",
|
||||
"NCT6795D",
|
||||
"NCT6796D",
|
||||
"NCT6798D",
|
||||
};
|
||||
|
||||
#define SIO_REG_LDSEL 0x07 /* Logical device select */
|
||||
#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
|
||||
#define SIO_REG_SMBA 0x62 /* SMBus base address register */
|
||||
|
||||
#define SIO_NCT6106_ID 0xc450
|
||||
#define SIO_NCT6775_ID 0xb470
|
||||
#define SIO_NCT6776_ID 0xc330
|
||||
#define SIO_NCT6779_ID 0xc560
|
||||
#define SIO_NCT6791_ID 0xc800
|
||||
#define SIO_NCT6792_ID 0xc910
|
||||
#define SIO_NCT6793_ID 0xd120
|
||||
#define SIO_NCT6795_ID 0xd350
|
||||
#define SIO_NCT6796_ID 0xd420
|
||||
#define SIO_NCT6798_ID 0xd428
|
||||
#define SIO_ID_MASK 0xFFF0
|
||||
|
||||
static inline void
|
||||
superio_outb(int ioreg, int reg, int val)
|
||||
{
|
||||
outb(reg, ioreg);
|
||||
outb(val, ioreg + 1);
|
||||
}
|
||||
|
||||
static inline int
|
||||
superio_inb(int ioreg, int reg)
|
||||
{
|
||||
outb(reg, ioreg);
|
||||
return inb(ioreg + 1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
superio_select(int ioreg, int ld)
|
||||
{
|
||||
outb(SIO_REG_LDSEL, ioreg);
|
||||
outb(ld, ioreg + 1);
|
||||
}
|
||||
|
||||
static inline int
|
||||
superio_enter(int ioreg)
|
||||
{
|
||||
/*
|
||||
* Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
|
||||
*/
|
||||
if (!request_muxed_region(ioreg, 2, DRVNAME))
|
||||
return -EBUSY;
|
||||
|
||||
outb(0x87, ioreg);
|
||||
outb(0x87, ioreg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
superio_exit(int ioreg)
|
||||
{
|
||||
outb(0xaa, ioreg);
|
||||
outb(0x02, ioreg);
|
||||
outb(0x02, ioreg + 1);
|
||||
release_region(ioreg, 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* ISA constants
|
||||
*/
|
||||
|
||||
#define IOREGION_ALIGNMENT (~7)
|
||||
#define IOREGION_LENGTH 2
|
||||
#define ADDR_REG_OFFSET 0
|
||||
#define DATA_REG_OFFSET 1
|
||||
|
||||
#define NCT6775_REG_BANK 0x4E
|
||||
#define NCT6775_REG_CONFIG 0x40
|
||||
|
||||
static struct i2c_adapter *nct6775_adapter;
|
||||
|
||||
struct i2c_nct6775_adapdata {
|
||||
unsigned short smba;
|
||||
};
|
||||
|
||||
/* Return negative errno on error. */
|
||||
static s32 nct6775_access(struct i2c_adapter * adap, u16 addr,
|
||||
unsigned short flags, char read_write,
|
||||
u8 command, int size, union i2c_smbus_data * data)
|
||||
{
|
||||
struct i2c_nct6775_adapdata *adapdata = i2c_get_adapdata(adap);
|
||||
unsigned short nuvoton_nct6793d_smba = adapdata->smba;
|
||||
int i, len, cnt;
|
||||
union i2c_smbus_data tmp_data;
|
||||
int timeout = 0;
|
||||
|
||||
tmp_data.word = 0;
|
||||
cnt = 0;
|
||||
len = 0;
|
||||
|
||||
outb_p(NCT6793D_SOFT_RESET, SMBHSTCTL);
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_QUICK:
|
||||
outb_p((addr << 1) | read_write,
|
||||
SMBHSTADD);
|
||||
break;
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
tmp_data.byte = data->byte;
|
||||
case I2C_SMBUS_BYTE:
|
||||
outb_p((addr << 1) | read_write,
|
||||
SMBHSTADD);
|
||||
outb_p(command, SMBHSTIDX);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
outb_p(tmp_data.byte, SMBHSTDAT);
|
||||
outb_p(NCT6793D_WRITE_BYTE, SMBHSTCMD);
|
||||
}
|
||||
else {
|
||||
outb_p(NCT6793D_READ_BYTE, SMBHSTCMD);
|
||||
}
|
||||
break;
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
outb_p((addr << 1) | read_write,
|
||||
SMBHSTADD);
|
||||
outb_p(command, SMBHSTIDX);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
outb_p(data->word & 0xff, SMBHSTDAT);
|
||||
outb_p((data->word & 0xff00) >> 8, SMBHSTDAT);
|
||||
outb_p(NCT6793D_WRITE_WORD, SMBHSTCMD);
|
||||
}
|
||||
else {
|
||||
outb_p(NCT6793D_READ_WORD, SMBHSTCMD);
|
||||
}
|
||||
break;
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
outb_p((addr << 1) | read_write,
|
||||
SMBHSTADD);
|
||||
outb_p(command, SMBHSTIDX);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
len = data->block[0];
|
||||
if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
|
||||
return -EINVAL;
|
||||
outb_p(len, SMBBLKSZ);
|
||||
|
||||
cnt = 1;
|
||||
if (len >= 4) {
|
||||
for (i = cnt; i <= 4; i++) {
|
||||
outb_p(data->block[i], SMBHSTDAT);
|
||||
}
|
||||
|
||||
len -= 4;
|
||||
cnt += 4;
|
||||
}
|
||||
else {
|
||||
for (i = cnt; i <= len; i++ ) {
|
||||
outb_p(data->block[i], SMBHSTDAT);
|
||||
}
|
||||
|
||||
len = 0;
|
||||
}
|
||||
|
||||
outb_p(NCT6793D_WRITE_BLOCK, SMBHSTCMD);
|
||||
}
|
||||
else {
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
outb_p(NCT6793D_MANUAL_START, SMBHSTCTL);
|
||||
|
||||
while ((size == I2C_SMBUS_BLOCK_DATA) && (len > 0)) {
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
timeout = 0;
|
||||
while ((inb_p(SMBHSTSTS) & NCT6793D_FIFO_EMPTY) == 0)
|
||||
{
|
||||
if(timeout > MAX_RETRIES)
|
||||
{
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
usleep_range(250, 500);
|
||||
timeout++;
|
||||
}
|
||||
|
||||
//Load more bytes into FIFO
|
||||
if (len >= 4) {
|
||||
for (i = cnt; i <= (cnt + 4); i++) {
|
||||
outb_p(data->block[i], SMBHSTDAT);
|
||||
}
|
||||
|
||||
len -= 4;
|
||||
cnt += 4;
|
||||
}
|
||||
else {
|
||||
for (i = cnt; i <= (cnt + len); i++) {
|
||||
outb_p(data->block[i], SMBHSTDAT);
|
||||
}
|
||||
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//wait for manual mode to complete
|
||||
timeout = 0;
|
||||
while ((inb_p(SMBHSTSTS) & NCT6793D_MANUAL_ACTIVE) != 0)
|
||||
{
|
||||
if(timeout > MAX_RETRIES)
|
||||
{
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
usleep_range(250, 500);
|
||||
timeout++;
|
||||
}
|
||||
|
||||
if ((inb_p(SMBHSTERR) & NCT6793D_NO_ACK) != 0) {
|
||||
return -ENXIO;
|
||||
}
|
||||
else if ((read_write == I2C_SMBUS_WRITE) || (size == I2C_SMBUS_QUICK)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_QUICK:
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
data->byte = inb_p(SMBHSTDAT);
|
||||
break;
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
data->word = inb_p(SMBHSTDAT) + (inb_p(SMBHSTDAT) << 8);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 nct6775_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_BLOCK_DATA;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
.smbus_xfer = nct6775_access,
|
||||
.functionality = nct6775_func,
|
||||
};
|
||||
|
||||
static int nct6775_add_adapter(unsigned short smba, const char *name, struct i2c_adapter **padap)
|
||||
{
|
||||
struct i2c_adapter *adap;
|
||||
struct i2c_nct6775_adapdata *adapdata;
|
||||
int retval;
|
||||
|
||||
adap = kzalloc(sizeof(*adap), GFP_KERNEL);
|
||||
if (adap == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
adap->algo = &smbus_algorithm;
|
||||
|
||||
adapdata = kzalloc(sizeof(*adapdata), GFP_KERNEL);
|
||||
if (adapdata == NULL) {
|
||||
kfree(adap);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
adapdata->smba = smba;
|
||||
|
||||
snprintf(adap->name, sizeof(adap->name),
|
||||
"SMBus NCT67xx adapter%s at %04x", name, smba);
|
||||
|
||||
i2c_set_adapdata(adap, adapdata);
|
||||
|
||||
retval = i2c_add_adapter(adap);
|
||||
if (retval) {
|
||||
kfree(adapdata);
|
||||
kfree(adap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
*padap = adap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nct6775_remove_adapter(struct i2c_adapter *adap)
|
||||
{
|
||||
struct i2c_nct6775_adapdata *adapdata = i2c_get_adapdata(adap);
|
||||
|
||||
if (adapdata->smba) {
|
||||
i2c_del_adapter(adap);
|
||||
kfree(adapdata);
|
||||
kfree(adap);
|
||||
}
|
||||
}
|
||||
|
||||
//static SIMPLE_DEV_PM_OPS(nct6775_dev_pm_ops, nct6775_suspend, nct6775_resume);
|
||||
|
||||
/*
|
||||
* when Super-I/O functions move to a separate file, the Super-I/O
|
||||
* bus will manage the lifetime of the device and this module will only keep
|
||||
* track of the nct6775 driver. But since we use platform_device_alloc(), we
|
||||
* must keep track of the device
|
||||
*/
|
||||
static struct platform_device *pdev[2];
|
||||
|
||||
static int nct6775_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
|
||||
struct resource *res;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
|
||||
DRVNAME))
|
||||
return -EBUSY;
|
||||
|
||||
switch (sio_data->kind) {
|
||||
case nct6791:
|
||||
case nct6792:
|
||||
case nct6793:
|
||||
case nct6795:
|
||||
case nct6796:
|
||||
case nct6798:
|
||||
nct6775_add_adapter(res->start, "", &nct6775_adapter);
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
static void nct6791_enable_io_mapping(int sioaddr)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
|
||||
if (val & 0x10) {
|
||||
pr_info("Enabling hardware monitor logical device mappings.\n");
|
||||
superio_outb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
|
||||
val & ~0x10);
|
||||
}
|
||||
}*/
|
||||
|
||||
static struct platform_driver i2c_nct6775_driver = {
|
||||
.driver = {
|
||||
.name = DRVNAME,
|
||||
// .pm = &nct6775_dev_pm_ops,
|
||||
},
|
||||
.probe = nct6775_probe,
|
||||
};
|
||||
|
||||
static void __exit i2c_nct6775_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(nct6775_adapter)
|
||||
nct6775_remove_adapter(nct6775_adapter);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pdev); i++) {
|
||||
if (pdev[i])
|
||||
platform_device_unregister(pdev[i]);
|
||||
}
|
||||
platform_driver_unregister(&i2c_nct6775_driver);
|
||||
}
|
||||
|
||||
/* nct6775_find() looks for a '627 in the Super-I/O config space */
|
||||
static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
|
||||
{
|
||||
u16 val;
|
||||
int err;
|
||||
int addr;
|
||||
|
||||
err = superio_enter(sioaddr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) |
|
||||
superio_inb(sioaddr, SIO_REG_DEVID + 1);
|
||||
|
||||
switch (val & SIO_ID_MASK) {
|
||||
case SIO_NCT6106_ID:
|
||||
sio_data->kind = nct6106;
|
||||
break;
|
||||
case SIO_NCT6775_ID:
|
||||
sio_data->kind = nct6775;
|
||||
break;
|
||||
case SIO_NCT6776_ID:
|
||||
sio_data->kind = nct6776;
|
||||
break;
|
||||
case SIO_NCT6779_ID:
|
||||
sio_data->kind = nct6779;
|
||||
break;
|
||||
case SIO_NCT6791_ID:
|
||||
sio_data->kind = nct6791;
|
||||
break;
|
||||
case SIO_NCT6792_ID:
|
||||
sio_data->kind = nct6792;
|
||||
break;
|
||||
case SIO_NCT6793_ID:
|
||||
sio_data->kind = nct6793;
|
||||
break;
|
||||
case SIO_NCT6795_ID:
|
||||
sio_data->kind = nct6795;
|
||||
break;
|
||||
case SIO_NCT6796_ID:
|
||||
sio_data->kind = nct6796;
|
||||
break;
|
||||
case SIO_NCT6798_ID:
|
||||
sio_data->kind = nct6798;
|
||||
break;
|
||||
default:
|
||||
if (val != 0xffff)
|
||||
pr_debug("unsupported chip ID: 0x%04x\n", val);
|
||||
superio_exit(sioaddr);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* We have a known chip, find the SMBus I/O address */
|
||||
superio_select(sioaddr, NCT6775_LD_SMBUS);
|
||||
val = (superio_inb(sioaddr, SIO_REG_SMBA) << 8)
|
||||
| superio_inb(sioaddr, SIO_REG_SMBA + 1);
|
||||
addr = val & IOREGION_ALIGNMENT;
|
||||
if (addr == 0) {
|
||||
pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
|
||||
superio_exit(sioaddr);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
//if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
|
||||
// sio_data->kind == nct6793 || sio_data->kind == nct6795 ||
|
||||
// sio_data->kind == nct6796)
|
||||
// nct6791_enable_io_mapping(sioaddr);
|
||||
|
||||
superio_exit(sioaddr);
|
||||
pr_info("Found %s or compatible chip at %#x:%#x\n",
|
||||
nct6775_sio_names[sio_data->kind], sioaddr, addr);
|
||||
sio_data->sioreg = sioaddr;
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static int __init i2c_nct6775_init(void)
|
||||
{
|
||||
int i, err;
|
||||
bool found = false;
|
||||
int address;
|
||||
struct resource res;
|
||||
struct nct6775_sio_data sio_data;
|
||||
int sioaddr[2] = { 0x2e, 0x4e };
|
||||
|
||||
err = platform_driver_register(&i2c_nct6775_driver);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* initialize sio_data->kind and sio_data->sioreg.
|
||||
*
|
||||
* when Super-I/O functions move to a separate file, the Super-I/O
|
||||
* driver will probe 0x2e and 0x4e and auto-detect the presence of a
|
||||
* nct6775 hardware monitor, and call probe()
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(pdev); i++) {
|
||||
address = nct6775_find(sioaddr[i], &sio_data);
|
||||
if (address <= 0)
|
||||
continue;
|
||||
|
||||
found = true;
|
||||
|
||||
pdev[i] = platform_device_alloc(DRVNAME, address);
|
||||
if (!pdev[i]) {
|
||||
err = -ENOMEM;
|
||||
goto exit_device_unregister;
|
||||
}
|
||||
|
||||
err = platform_device_add_data(pdev[i], &sio_data,
|
||||
sizeof(struct nct6775_sio_data));
|
||||
if (err)
|
||||
goto exit_device_put;
|
||||
|
||||
memset(&res, 0, sizeof(res));
|
||||
res.name = DRVNAME;
|
||||
res.start = address;
|
||||
res.end = address + IOREGION_LENGTH - 1;
|
||||
res.flags = IORESOURCE_IO;
|
||||
|
||||
err = acpi_check_resource_conflict(&res);
|
||||
if (err) {
|
||||
platform_device_put(pdev[i]);
|
||||
pdev[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
err = platform_device_add_resources(pdev[i], &res, 1);
|
||||
if (err)
|
||||
goto exit_device_put;
|
||||
|
||||
/* platform_device_add calls probe() */
|
||||
err = platform_device_add(pdev[i]);
|
||||
if (err)
|
||||
goto exit_device_put;
|
||||
}
|
||||
if (!found) {
|
||||
err = -ENODEV;
|
||||
goto exit_unregister;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_device_put:
|
||||
platform_device_put(pdev[i]);
|
||||
exit_device_unregister:
|
||||
while (--i >= 0) {
|
||||
if (pdev[i])
|
||||
platform_device_unregister(pdev[i]);
|
||||
}
|
||||
exit_unregister:
|
||||
platform_driver_unregister(&i2c_nct6775_driver);
|
||||
return err;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Adam Honse <calcprogrammer1@gmail.com>");
|
||||
MODULE_DESCRIPTION("SMBus driver for NCT6775F and compatible chips");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(i2c_nct6775_init);
|
||||
module_exit(i2c_nct6775_exit);
|
|
@ -1,2 +1,3 @@
|
|||
i2c-piix4
|
||||
i2c-nct6775
|
||||
i2c-dev
|
Loading…
Reference in New Issue