add iic interface to ig4 driver, move isl and cyapa to iicbus
Summary: The hardware does not expose a classic SMBus interface. Instead it has a lower level interface that can express a far richer I2C protocol than what smbus offers. However, the interface does not provide a way to explicitly generate the I2C stop and start conditions. It's only possible to request that the stop condition is generated after transferring the next byte in either direction. So, at least one data byte must always be transferred. Thus, some I2C sequences are impossible to generate, e.g., an equivalent of smbus quick command (<start>-<slave addr>-<r/w bit>-<stop>). At the same time isl(4) and cyapa(4) are moved to iicbus and now they use iicbus_transfer for communication. Previously they used smbus_trans() interface that is not defined by the SMBus protocol and was implemented only by ig4(4). In fact, that interface was impossible to implement for the typical SMBus controllers like intpm(4) or ichsmb(4) where a type of the SMBus command must be programmed. The plan is to remove smbus_trans() and all its uses. As an aside, the smbus_trans() method deviates from the standard, but perhaps backwards, FreeBSD convention of using 8-bit slave addresses (shifted by 1 bit to the left). The method expects 7-bit addresses. There is a user facing consequence of this change. A user must now provide device hints for isl and cyapa that specify an iicbus to use and a slave address on it. On Chromebook hardware where isl and cyapa devices are commonly found it is also possible to use a new chromebook_platform(4) driver that automatically configures isl and cyapa devices. There is no need to provide the device hints in that case, Right now smbus(4) driver tries to discover all slaves on the bus. That is very dangerous. Fortunately, the probing code uses smbus_trans() to do its job, so it is really enabled for ig4 only. The plan is to remove that auto-probing code and smbus_trans(). Tested by: grembo, Matthias Apitz <guru@unixarea.de> (w/o chromebook_platform) Discussed with: grembo, imp Reviewed by: wblock (docs) MFC after: 1 month Relnotes: yes Differential Revision: https://reviews.freebsd.org/D8172
This commit is contained in:
parent
3c1f73b18d
commit
448897d366
6
UPDATING
6
UPDATING
@ -51,6 +51,12 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 12.x IS SLOW:
|
||||
|
||||
****************************** SPECIAL WARNING: ******************************
|
||||
|
||||
20161030:
|
||||
isl(4) and cyapa(4) drivers now require a new driver,
|
||||
chromebook_platform(4), to work properly on Chromebook-class hardware.
|
||||
On other types of hardware the drivers may need to be configured using
|
||||
device hints. Please see the corresponding manual pages for details.
|
||||
|
||||
20161017:
|
||||
The urtwn(4) driver was merged into rtwn(4) and now consists of
|
||||
rtwn(4) main module + rtwn_usb(4) and rtwn_pci(4) bus-specific
|
||||
|
68
share/man/man4/chromebook_platform.4
Normal file
68
share/man/man4/chromebook_platform.4
Normal file
@ -0,0 +1,68 @@
|
||||
.\" Copyright (c) 2016 Andriy Gapon <avg@FreeBSD.org>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd October 13, 2016
|
||||
.Dt CHROMEBOOK_PLATFORM 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm chromebook_platform
|
||||
.Nd support driver for hardware on various Chromebook models
|
||||
.Sh SYNOPSIS
|
||||
To compile this driver into the kernel, place the following lines into
|
||||
the kernel configuration file:
|
||||
.Bd -ragged -offset indent
|
||||
.Cd "device chromebook_platform"
|
||||
.Ed
|
||||
.Pp
|
||||
Alternatively, to load the driver as a module at boot time, place the following line in
|
||||
.Xr loader.conf 5 :
|
||||
.Bd -literal -offset indent
|
||||
chromebook_platform_load="YES"
|
||||
.Ed
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
driver provides automatic configuration for devices that cannot be enumerated
|
||||
or safely probed.
|
||||
In particular, I2C peripherals are different from model to model.
|
||||
.Nm
|
||||
has a model-specific information about the I2C peripherals, their drivers,
|
||||
their bus attachments and slave addresses.
|
||||
.Pp
|
||||
Note that
|
||||
.Nm
|
||||
does not load driver modules for the peripherals.
|
||||
Those have to be compiled into the kernel or loaded separately.
|
||||
.Sh SEE ALSO
|
||||
.Xr cyapa 4 ,
|
||||
.Xr iicbus 4 ,
|
||||
.Xr isl 4 ,
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
The
|
||||
.Nm
|
||||
driver and this manual page were written by
|
||||
.An Andriy Gapon Aq Mt avg@FreeBSD.org .
|
@ -24,7 +24,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 25, 2015
|
||||
.Dd October 03, 2016
|
||||
.Dt CYAPA 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -36,7 +36,7 @@ the kernel configuration file:
|
||||
.Bd -ragged -offset indent
|
||||
.Cd "device cyapa"
|
||||
.Cd "device ig4"
|
||||
.Cd "device smbus"
|
||||
.Cd "device iicbus"
|
||||
.Ed
|
||||
.Pp
|
||||
Alternatively, to load the driver as a module at boot time, place the following line in
|
||||
@ -45,6 +45,13 @@ Alternatively, to load the driver as a module at boot time, place the following
|
||||
cyapa_load="YES"
|
||||
ig4_load="YES"
|
||||
.Ed
|
||||
.Pp
|
||||
In
|
||||
.Pa /boot/device.hints :
|
||||
.Cd hint.cyapa.0.at="iicbus0"
|
||||
.Cd hint.cyapa.0.addr="0xCE"
|
||||
.Cd hint.cyapa.1.at="iicbus1"
|
||||
.Cd hint.cyapa.1.addr="0xCE"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
@ -86,6 +93,20 @@ The upper right corner issues a MIDDLE button event.
|
||||
The lower right corner issues a RIGHT button.
|
||||
Optionally, tap to click can be enabled (see below).
|
||||
.El
|
||||
.Pp
|
||||
On a system using
|
||||
.Xr device.hints 5 ,
|
||||
these values are configurable for
|
||||
.Nm :
|
||||
.Bl -tag -width "hint.cyapa.%d.addr"
|
||||
.It Va hint.cyapa.%d.at
|
||||
target
|
||||
.Xr iicbus 4 .
|
||||
.It Va hint.cyapa.%d.addr
|
||||
.Nm
|
||||
i2c address on the
|
||||
.Xr iicbus 4 .
|
||||
.El
|
||||
.Sh SYSCTL VARIABLES
|
||||
These
|
||||
.Xr sysctl 8
|
||||
@ -175,7 +196,7 @@ file:
|
||||
.Dl debug.cyapa_enable_tapclick=2
|
||||
.Sh SEE ALSO
|
||||
.Xr ig4 4 ,
|
||||
.Xr smbus 4 ,
|
||||
.Xr iicbus 4 ,
|
||||
.Xr sysmouse 4 ,
|
||||
.Xr moused 8
|
||||
.Sh AUTHORS
|
||||
@ -195,6 +216,6 @@ This manual page was written by
|
||||
.Sh BUGS
|
||||
The
|
||||
.Nm
|
||||
driver detects the device based on its I2C address (0x67).
|
||||
driver detects the device from the I2C address.
|
||||
This might have unforeseen consequences if the initialization sequence
|
||||
is sent to an unknown device at that address.
|
||||
|
@ -24,18 +24,18 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd May 30, 2015
|
||||
.Dd October 03, 2016
|
||||
.Dt IG4 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ig4
|
||||
.Nd Intel(R) fourth generation mobile CPU integrated I2C SMBus driver
|
||||
.Nd Intel(R) fourth generation mobile CPU integrated I2C driver
|
||||
.Sh SYNOPSIS
|
||||
To compile this driver into the kernel, place the following lines into
|
||||
the kernel configuration file:
|
||||
.Bd -ragged -offset indent
|
||||
.Cd "device ig4"
|
||||
.Cd "device smbus"
|
||||
.Cd "device iicbus"
|
||||
.Ed
|
||||
.Pp
|
||||
Alternatively, to load the driver as a module at boot time, place the following line in
|
||||
@ -46,9 +46,10 @@ ig4_load="YES"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
driver provides access to peripherals attached to an I2C SMB controller.
|
||||
driver provides access to peripherals attached to an I2C controller.
|
||||
.Sh HARDWARE
|
||||
.Nm
|
||||
supports the SMBus controller found in fourth generation Intel(R) Core(TM)
|
||||
supports the I2C controllers found in fourth generation Intel(R) Core(TM)
|
||||
processors based on the mobile U-processor line for intelligent systems.
|
||||
This includes the i7-4650U, i5-4300U, i3-4010U, and 2980U.
|
||||
.Sh SYSCTL VARIABLES
|
||||
@ -57,13 +58,15 @@ These
|
||||
variables are available:
|
||||
.Bl -tag -width "debug.ig4_dump"
|
||||
.It Va debug.ig4_dump
|
||||
Setting this to a non-zero value dumps controller registers to console and
|
||||
syslog once.
|
||||
The sysctl resets to zero immediately.
|
||||
This sysctl is a zero-based bit mask.
|
||||
When any of the bits are set, a register dump is printed for
|
||||
every I2C transfer on an
|
||||
.Nm
|
||||
device with the same unit number.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr smb 4 ,
|
||||
.Xr smbus 4
|
||||
.Xr iic 4 ,
|
||||
.Xr iicbus 4
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
The
|
||||
|
@ -24,7 +24,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 25, 2015
|
||||
.Dd October 03, 2016
|
||||
.Dt ISL 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -36,7 +36,7 @@ the kernel configuration file:
|
||||
.Bd -ragged -offset indent
|
||||
.Cd "device isl"
|
||||
.Cd "device ig4"
|
||||
.Cd "device smbus"
|
||||
.Cd "device iicbus"
|
||||
.Ed
|
||||
.Pp
|
||||
Alternatively, to load the driver as a module at boot time, place the following line in
|
||||
@ -45,6 +45,13 @@ Alternatively, to load the driver as a module at boot time, place the following
|
||||
isl_load="YES"
|
||||
ig4_load="YES"
|
||||
.Ed
|
||||
.Pp
|
||||
In
|
||||
.Pa /boot/device.hints :
|
||||
.Cd hint.isl.0.at="iicbus0"
|
||||
.Cd hint.isl.0.addr="0x88"
|
||||
.Cd hint.isl.1.at="iicbus1"
|
||||
.Cd hint.isl.1.addr="0x88"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
@ -54,6 +61,20 @@ Function.
|
||||
Functionality is basic and provided through the
|
||||
.Xr sysctl 8
|
||||
interface.
|
||||
.Pp
|
||||
On a system using
|
||||
.Xr device.hints 5 ,
|
||||
these values are configurable for
|
||||
.Nm :
|
||||
.Bl -tag -width "hint.isl.%d.addr"
|
||||
.It Va hint.isl.%d.at
|
||||
target
|
||||
.Xr iicbus 4 .
|
||||
.It Va hint.isl.%d.addr
|
||||
.Nm
|
||||
i2c address on the
|
||||
.Xr iicbus 4 .
|
||||
.El
|
||||
.Sh SYSCTL VARIABLES
|
||||
The following
|
||||
.Xr sysctl 8
|
||||
@ -86,7 +107,7 @@ $ sh /usr/local/share/examples/intel-backlight/isl_backlight.sh
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr ig4 4 ,
|
||||
.Xr smbus 4
|
||||
.Xr iicbus 4
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
The
|
||||
@ -99,6 +120,6 @@ This manual page was written by
|
||||
.Sh BUGS
|
||||
The
|
||||
.Nm
|
||||
driver detects the device based on its I2C address (0x44).
|
||||
driver detects the device based from the I2C address.
|
||||
This might have unforeseen consequences if the initialization sequence
|
||||
is sent to an unknown device at that address.
|
||||
|
@ -1273,6 +1273,7 @@ dev/cfi/cfi_bus_nexus.c optional cfi
|
||||
dev/cfi/cfi_core.c optional cfi
|
||||
dev/cfi/cfi_dev.c optional cfi
|
||||
dev/cfi/cfi_disk.c optional cfid
|
||||
dev/chromebook_platform/chromebook_platform.c optional chromebook_platform
|
||||
dev/ciss/ciss.c optional ciss
|
||||
dev/cm/smc90cx6.c optional cm
|
||||
dev/cmx/cmx.c optional cmx
|
||||
@ -1389,7 +1390,7 @@ t5fw.fw optional cxgbe \
|
||||
dev/cy/cy.c optional cy
|
||||
dev/cy/cy_isa.c optional cy isa
|
||||
dev/cy/cy_pci.c optional cy pci
|
||||
dev/cyapa/cyapa.c optional cyapa smbus
|
||||
dev/cyapa/cyapa.c optional cyapa iicbus
|
||||
dev/dc/if_dc.c optional dc pci
|
||||
dev/dc/dcphy.c optional dc pci
|
||||
dev/dc/pnphy.c optional dc pci
|
||||
@ -1631,8 +1632,8 @@ dev/hptiop/hptiop.c optional hptiop scbus
|
||||
dev/hwpmc/hwpmc_logging.c optional hwpmc
|
||||
dev/hwpmc/hwpmc_mod.c optional hwpmc
|
||||
dev/hwpmc/hwpmc_soft.c optional hwpmc
|
||||
dev/ichiic/ig4_iic.c optional ig4 smbus
|
||||
dev/ichiic/ig4_pci.c optional ig4 pci smbus
|
||||
dev/ichiic/ig4_iic.c optional ig4 iicbus
|
||||
dev/ichiic/ig4_pci.c optional ig4 pci iicbus
|
||||
dev/ichsmb/ichsmb.c optional ichsmb
|
||||
dev/ichsmb/ichsmb_pci.c optional ichsmb pci
|
||||
dev/ida/ida.c optional ida
|
||||
@ -1726,7 +1727,7 @@ dev/iscsi_initiator/isc_soc.c optional iscsi_initiator scbus
|
||||
dev/iscsi_initiator/isc_sm.c optional iscsi_initiator scbus
|
||||
dev/iscsi_initiator/isc_subr.c optional iscsi_initiator scbus
|
||||
dev/ismt/ismt.c optional ismt
|
||||
dev/isl/isl.c optional isl smbus
|
||||
dev/isl/isl.c optional isl iicbus
|
||||
dev/isp/isp.c optional isp
|
||||
dev/isp/isp_freebsd.c optional isp
|
||||
dev/isp/isp_library.c optional isp
|
||||
|
102
sys/dev/chromebook_platform/chromebook_platform.c
Normal file
102
sys/dev/chromebook_platform/chromebook_platform.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 The FreeBSD Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <dev/pci/pcivar.h>
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/iicbus/iicbus.h>
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
|
||||
/*
|
||||
* Driver that attaches I2C devices.
|
||||
*/
|
||||
static struct {
|
||||
uint32_t pci_id;
|
||||
const char *name;
|
||||
uint8_t addr;
|
||||
} slaves[] = {
|
||||
{ 0x9c628086, "isl", 0x88 },
|
||||
{ 0x9c618086, "cyapa", 0xce },
|
||||
};
|
||||
|
||||
static void
|
||||
chromebook_i2c_identify(driver_t *driver, device_t bus)
|
||||
{
|
||||
device_t controller;
|
||||
device_t child;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* A stopgap approach to preserve the status quo.
|
||||
* A more intelligent approach is required to correctly
|
||||
* identify a machine model and hardware available on it.
|
||||
* For instance, DMI could be used.
|
||||
* See http://lxr.free-electrons.com/source/drivers/platform/chrome/chromeos_laptop.c
|
||||
*/
|
||||
controller = device_get_parent(bus);
|
||||
if (strcmp(device_get_name(controller), "ig4iic") != 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < nitems(slaves); i++) {
|
||||
if (device_find_child(bus, slaves[i].name, -1) != NULL)
|
||||
continue;
|
||||
if (slaves[i].pci_id != pci_get_devid(controller))
|
||||
continue;
|
||||
child = BUS_ADD_CHILD(bus, 0, slaves[i].name, -1);
|
||||
if (child != NULL)
|
||||
iicbus_set_addr(child, slaves[i].addr);
|
||||
}
|
||||
}
|
||||
|
||||
static device_method_t chromebook_i2c_methods[] = {
|
||||
DEVMETHOD(device_identify, chromebook_i2c_identify),
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t chromebook_i2c_driver = {
|
||||
"chromebook_i2c",
|
||||
chromebook_i2c_methods,
|
||||
0 /* no softc */
|
||||
};
|
||||
|
||||
static devclass_t chromebook_i2c_devclass;
|
||||
|
||||
DRIVER_MODULE(chromebook_i2c, iicbus, chromebook_i2c_driver,
|
||||
chromebook_i2c_devclass, 0, 0);
|
||||
MODULE_VERSION(chromebook_i2c, 1);
|
||||
|
@ -122,11 +122,11 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/uio.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <dev/smbus/smbconf.h>
|
||||
#include <dev/smbus/smbus.h>
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
#include <dev/iicbus/iicbus.h>
|
||||
#include <dev/cyapa/cyapa.h>
|
||||
|
||||
#include "smbus_if.h"
|
||||
#include "iicbus_if.h"
|
||||
#include "bus_if.h"
|
||||
#include "device_if.h"
|
||||
|
||||
@ -149,7 +149,6 @@ struct cyapa_fifo {
|
||||
struct cyapa_softc {
|
||||
device_t dev;
|
||||
int count; /* >0 if device opened */
|
||||
int addr;
|
||||
struct cdev *devnode;
|
||||
struct selinfo selinfo;
|
||||
struct mtx mutex;
|
||||
@ -273,6 +272,30 @@ static int cyapa_reset = 0;
|
||||
SYSCTL_INT(_debug, OID_AUTO, cyapa_reset, CTLFLAG_RW,
|
||||
&cyapa_reset, 0, "Reset track pad");
|
||||
|
||||
static int
|
||||
cyapa_read_bytes(device_t dev, uint8_t reg, uint8_t *val, int cnt)
|
||||
{
|
||||
uint16_t addr = iicbus_get_addr(dev);
|
||||
struct iic_msg msgs[] = {
|
||||
{ addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® },
|
||||
{ addr, IIC_M_RD, cnt, val },
|
||||
};
|
||||
|
||||
return (iicbus_transfer(dev, msgs, nitems(msgs)));
|
||||
}
|
||||
|
||||
static int
|
||||
cyapa_write_bytes(device_t dev, uint8_t reg, const uint8_t *val, int cnt)
|
||||
{
|
||||
uint16_t addr = iicbus_get_addr(dev);
|
||||
struct iic_msg msgs[] = {
|
||||
{ addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® },
|
||||
{ addr, IIC_M_WR | IIC_M_NOSTART, cnt, __DECONST(uint8_t *, val) },
|
||||
};
|
||||
|
||||
return (iicbus_transfer(dev, msgs, nitems(msgs)));
|
||||
}
|
||||
|
||||
static void
|
||||
cyapa_lock(struct cyapa_softc *sc)
|
||||
{
|
||||
@ -318,7 +341,7 @@ cyapa_notify(struct cyapa_softc *sc)
|
||||
* Initialize the device
|
||||
*/
|
||||
static int
|
||||
init_device(device_t dev, struct cyapa_cap *cap, int addr, int probe)
|
||||
init_device(device_t dev, struct cyapa_cap *cap, int probe)
|
||||
{
|
||||
static char bl_exit[] = {
|
||||
0x00, 0xff, 0xa5, 0x00, 0x01,
|
||||
@ -326,17 +349,13 @@ init_device(device_t dev, struct cyapa_cap *cap, int addr, int probe)
|
||||
static char bl_deactivate[] = {
|
||||
0x00, 0xff, 0x3b, 0x00, 0x01,
|
||||
0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
|
||||
device_t bus;
|
||||
struct cyapa_boot_regs boot;
|
||||
int error;
|
||||
int retries;
|
||||
|
||||
bus = device_get_parent(dev); /* smbus */
|
||||
|
||||
/* Get status */
|
||||
error = smbus_trans(bus, addr, CMD_BOOT_STATUS,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
|
||||
NULL, 0, (void *)&boot, sizeof(boot), NULL);
|
||||
error = cyapa_read_bytes(dev, CMD_BOOT_STATUS,
|
||||
(void *)&boot, sizeof(boot));
|
||||
if (error)
|
||||
goto done;
|
||||
|
||||
@ -350,25 +369,21 @@ init_device(device_t dev, struct cyapa_cap *cap, int addr, int probe)
|
||||
/* Busy, wait loop. */
|
||||
} else if (boot.error & CYAPA_ERROR_BOOTLOADER) {
|
||||
/* Magic */
|
||||
error = smbus_trans(bus, addr, CMD_BOOT_STATUS,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
|
||||
bl_deactivate, sizeof(bl_deactivate),
|
||||
NULL, 0, NULL);
|
||||
error = cyapa_write_bytes(dev, CMD_BOOT_STATUS,
|
||||
bl_deactivate, sizeof(bl_deactivate));
|
||||
if (error)
|
||||
goto done;
|
||||
} else {
|
||||
/* Magic */
|
||||
error = smbus_trans(bus, addr, CMD_BOOT_STATUS,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
|
||||
bl_exit, sizeof(bl_exit), NULL, 0, NULL);
|
||||
error = cyapa_write_bytes(dev, CMD_BOOT_STATUS,
|
||||
bl_exit, sizeof(bl_exit));
|
||||
if (error)
|
||||
goto done;
|
||||
}
|
||||
pause("cyapab1", (hz * 2) / 10);
|
||||
--retries;
|
||||
error = smbus_trans(bus, addr, CMD_BOOT_STATUS,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
|
||||
NULL, 0, (void *)&boot, sizeof(boot), NULL);
|
||||
error = cyapa_read_bytes(dev, CMD_BOOT_STATUS,
|
||||
(void *)&boot, sizeof(boot));
|
||||
if (error)
|
||||
goto done;
|
||||
}
|
||||
@ -381,9 +396,8 @@ init_device(device_t dev, struct cyapa_cap *cap, int addr, int probe)
|
||||
|
||||
/* Check identity */
|
||||
if (cap) {
|
||||
error = smbus_trans(bus, addr, CMD_QUERY_CAPABILITIES,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
|
||||
NULL, 0, (void *)cap, sizeof(*cap), NULL);
|
||||
error = cyapa_read_bytes(dev, CMD_QUERY_CAPABILITIES,
|
||||
(void *)cap, sizeof(*cap));
|
||||
|
||||
if (strncmp(cap->prod_ida, "CYTRA", 5) != 0) {
|
||||
device_printf(dev, "Product ID \"%5.5s\" mismatch\n",
|
||||
@ -391,9 +405,8 @@ init_device(device_t dev, struct cyapa_cap *cap, int addr, int probe)
|
||||
error = ENXIO;
|
||||
}
|
||||
}
|
||||
error = smbus_trans(bus, addr, CMD_BOOT_STATUS,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
|
||||
NULL, 0, (void *)&boot, sizeof(boot), NULL);
|
||||
error = cyapa_read_bytes(dev, CMD_BOOT_STATUS,
|
||||
(void *)&boot, sizeof(boot));
|
||||
|
||||
if (probe == 0) /* official init */
|
||||
device_printf(dev, "cyapa init status %02x\n", boot.stat);
|
||||
@ -452,16 +465,16 @@ cyapa_probe(device_t dev)
|
||||
int addr;
|
||||
int error;
|
||||
|
||||
addr = smbus_get_addr(dev);
|
||||
addr = iicbus_get_addr(dev);
|
||||
|
||||
/*
|
||||
* 0x67 - cypress trackpad on the acer c720
|
||||
* (other devices might use other ids).
|
||||
*/
|
||||
if (addr != 0x67)
|
||||
if (addr != 0xce)
|
||||
return (ENXIO);
|
||||
|
||||
error = init_device(dev, &cap, addr, 1);
|
||||
error = init_device(dev, &cap, 1);
|
||||
if (error != 0)
|
||||
return (ENXIO);
|
||||
|
||||
@ -482,15 +495,14 @@ cyapa_attach(device_t dev)
|
||||
sc->reporting_mode = 1;
|
||||
|
||||
unit = device_get_unit(dev);
|
||||
addr = smbus_get_addr(dev);
|
||||
addr = iicbus_get_addr(dev);
|
||||
|
||||
if (init_device(dev, &cap, addr, 0))
|
||||
if (init_device(dev, &cap, 0))
|
||||
return (ENXIO);
|
||||
|
||||
mtx_init(&sc->mutex, "cyapa", NULL, MTX_DEF);
|
||||
|
||||
sc->dev = dev;
|
||||
sc->addr = addr;
|
||||
|
||||
knlist_init_mtx(&sc->selinfo.si_note, &sc->mutex);
|
||||
|
||||
@ -1159,7 +1171,7 @@ cyapa_poll_thread(void *arg)
|
||||
{
|
||||
struct cyapa_softc *sc;
|
||||
struct cyapa_regs regs;
|
||||
device_t bus; /* smbus */
|
||||
device_t bus; /* iicbus */
|
||||
int error;
|
||||
int freq;
|
||||
int isidle;
|
||||
@ -1180,12 +1192,10 @@ cyapa_poll_thread(void *arg)
|
||||
|
||||
while (!sc->detaching) {
|
||||
cyapa_unlock(sc);
|
||||
error = smbus_request_bus(bus, sc->dev, SMB_WAIT);
|
||||
error = iicbus_request_bus(bus, sc->dev, IIC_WAIT);
|
||||
if (error == 0) {
|
||||
error = smbus_trans(bus, sc->addr, CMD_DEV_STATUS,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
|
||||
NULL, 0,
|
||||
(void *)®s, sizeof(regs), NULL);
|
||||
error = cyapa_read_bytes(sc->dev, CMD_DEV_STATUS,
|
||||
(void *)®s, sizeof(regs));
|
||||
if (error == 0) {
|
||||
isidle = cyapa_raw_input(sc, ®s, freq);
|
||||
}
|
||||
@ -1200,9 +1210,9 @@ cyapa_poll_thread(void *arg)
|
||||
(unsigned)(ticks - last_reset) > TIME_TO_RESET)) {
|
||||
cyapa_reset = 0;
|
||||
last_reset = ticks;
|
||||
init_device(sc->dev, NULL, sc->addr, 2);
|
||||
init_device(sc->dev, NULL, 2);
|
||||
}
|
||||
smbus_release_bus(bus, sc->dev);
|
||||
iicbus_release_bus(bus, sc->dev);
|
||||
}
|
||||
pause("cyapw", hz / freq);
|
||||
++sc->poll_ticks;
|
||||
@ -1531,18 +1541,16 @@ cyapa_set_power_mode(struct cyapa_softc *sc, int mode)
|
||||
int error;
|
||||
|
||||
bus = device_get_parent(sc->dev);
|
||||
error = smbus_request_bus(bus, sc->dev, SMB_WAIT);
|
||||
error = iicbus_request_bus(bus, sc->dev, IIC_WAIT);
|
||||
if (error == 0) {
|
||||
error = smbus_trans(bus, sc->addr, CMD_POWER_MODE,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
|
||||
NULL, 0, (void *)&data, 1, NULL);
|
||||
error = cyapa_read_bytes(sc->dev, CMD_POWER_MODE,
|
||||
&data, 1);
|
||||
data = (data & ~0xFC) | mode;
|
||||
if (error == 0) {
|
||||
error = smbus_trans(bus, sc->addr, CMD_POWER_MODE,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
|
||||
(void *)&data, 1, NULL, 0, NULL);
|
||||
error = cyapa_write_bytes(sc->dev, CMD_POWER_MODE,
|
||||
&data, 1);
|
||||
}
|
||||
smbus_release_bus(bus, sc->dev);
|
||||
iicbus_release_bus(bus, sc->dev);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1697,6 +1705,6 @@ cyapa_fuzz(int delta, int *fuzzp)
|
||||
return (delta);
|
||||
}
|
||||
|
||||
DRIVER_MODULE(cyapa, smbus, cyapa_driver, cyapa_devclass, NULL, NULL);
|
||||
MODULE_DEPEND(cyapa, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
|
||||
DRIVER_MODULE(cyapa, iicbus, cyapa_driver, cyapa_devclass, NULL, NULL);
|
||||
MODULE_DEPEND(cyapa, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
|
||||
MODULE_VERSION(cyapa, 1);
|
||||
|
@ -61,6 +61,8 @@ __FBSDID("$FreeBSD$");
|
||||
#include <dev/pci/pcivar.h>
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/smbus/smbconf.h>
|
||||
#include <dev/iicbus/iicbus.h>
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
|
||||
#include <dev/ichiic/ig4_reg.h>
|
||||
#include <dev/ichiic/ig4_var.h>
|
||||
@ -120,7 +122,7 @@ set_controller(ig4iic_softc_t *sc, uint32_t ctl)
|
||||
reg_write(sc, IG4_REG_INTR_MASK, 0);
|
||||
|
||||
reg_write(sc, IG4_REG_I2C_EN, ctl);
|
||||
error = SMB_ETIMEOUT;
|
||||
error = IIC_ETIMEOUT;
|
||||
|
||||
for (retry = 100; retry > 0; --retry) {
|
||||
v = reg_read(sc, IG4_REG_ENABLE_STATUS);
|
||||
@ -148,7 +150,7 @@ wait_status(ig4iic_softc_t *sc, uint32_t status)
|
||||
u_int count_us = 0;
|
||||
u_int limit_us = 25000; /* 25ms */
|
||||
|
||||
error = SMB_ETIMEOUT;
|
||||
error = IIC_ETIMEOUT;
|
||||
|
||||
for (;;) {
|
||||
/*
|
||||
@ -483,6 +485,236 @@ smb_transaction(ig4iic_softc_t *sc, char cmd, int op,
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* IICBUS API FUNCTIONS
|
||||
*/
|
||||
static int
|
||||
ig4iic_xfer_start(ig4iic_softc_t *sc, uint16_t slave)
|
||||
{
|
||||
/* XXX 10-bit address support? */
|
||||
set_slave_addr(sc, slave >> 1, 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ig4iic_read(ig4iic_softc_t *sc, uint8_t *buf, uint16_t len,
|
||||
bool repeated_start, bool stop)
|
||||
{
|
||||
uint32_t cmd;
|
||||
uint16_t i;
|
||||
int error;
|
||||
|
||||
if (len == 0)
|
||||
return (0);
|
||||
|
||||
cmd = IG4_DATA_COMMAND_RD;
|
||||
cmd |= repeated_start ? IG4_DATA_RESTART : 0;
|
||||
cmd |= stop && len == 1 ? IG4_DATA_STOP : 0;
|
||||
|
||||
/* Issue request for the first byte (could be last as well). */
|
||||
reg_write(sc, IG4_REG_DATA_CMD, cmd);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
/*
|
||||
* Maintain a pipeline by queueing the allowance for the next
|
||||
* read before waiting for the current read.
|
||||
*/
|
||||
cmd = IG4_DATA_COMMAND_RD;
|
||||
if (i < len - 1) {
|
||||
cmd = IG4_DATA_COMMAND_RD;
|
||||
cmd |= stop && i == len - 2 ? IG4_DATA_STOP : 0;
|
||||
reg_write(sc, IG4_REG_DATA_CMD, cmd);
|
||||
}
|
||||
error = wait_status(sc, IG4_STATUS_RX_NOTEMPTY);
|
||||
if (error)
|
||||
break;
|
||||
buf[i] = data_read(sc);
|
||||
}
|
||||
|
||||
(void)reg_read(sc, IG4_REG_TX_ABRT_SOURCE);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
ig4iic_write(ig4iic_softc_t *sc, uint8_t *buf, uint16_t len,
|
||||
bool repeated_start, bool stop)
|
||||
{
|
||||
uint32_t cmd;
|
||||
uint16_t i;
|
||||
int error;
|
||||
|
||||
if (len == 0)
|
||||
return (0);
|
||||
|
||||
cmd = repeated_start ? IG4_DATA_RESTART : 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
error = wait_status(sc, IG4_STATUS_TX_NOTFULL);
|
||||
if (error)
|
||||
break;
|
||||
cmd |= buf[i];
|
||||
cmd |= stop && i == len - 1 ? IG4_DATA_STOP : 0;
|
||||
reg_write(sc, IG4_REG_DATA_CMD, cmd);
|
||||
cmd = 0;
|
||||
}
|
||||
|
||||
(void)reg_read(sc, IG4_REG_TX_ABRT_SOURCE);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
ig4iic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
|
||||
{
|
||||
ig4iic_softc_t *sc = device_get_softc(dev);
|
||||
const char *reason = NULL;
|
||||
uint32_t i;
|
||||
int error;
|
||||
int unit;
|
||||
bool rpstart;
|
||||
bool stop;
|
||||
|
||||
/*
|
||||
* The hardware interface imposes limits on allowed I2C messages.
|
||||
* It is not possible to explicitly send a start or stop.
|
||||
* They are automatically sent (or not sent, depending on the
|
||||
* configuration) when a data byte is transferred.
|
||||
* For this reason it's impossible to send a message with no data
|
||||
* at all (like an SMBus quick message).
|
||||
* The start condition is automatically generated after the stop
|
||||
* condition, so it's impossible to not have a start after a stop.
|
||||
* The repeated start condition is automatically sent if a change
|
||||
* of the transfer direction happens, so it's impossible to have
|
||||
* a change of direction without a (repeated) start.
|
||||
* The repeated start can be forced even without the change of
|
||||
* direction.
|
||||
* Changing the target slave address requires resetting the hardware
|
||||
* state, so it's impossible to do that without the stop followed
|
||||
* by the start.
|
||||
*/
|
||||
for (i = 0; i < nmsgs; i++) {
|
||||
#if 0
|
||||
if (i == 0 && (msgs[i].flags & IIC_M_NOSTART) != 0) {
|
||||
reason = "first message without start";
|
||||
break;
|
||||
}
|
||||
if (i == nmsgs - 1 && (msgs[i].flags & IIC_M_NOSTOP) != 0) {
|
||||
reason = "last message without stop";
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (msgs[i].len == 0) {
|
||||
reason = "message with no data";
|
||||
break;
|
||||
}
|
||||
if (i > 0) {
|
||||
if ((msgs[i].flags & IIC_M_NOSTART) != 0 &&
|
||||
(msgs[i - 1].flags & IIC_M_NOSTOP) == 0) {
|
||||
reason = "stop not followed by start";
|
||||
break;
|
||||
}
|
||||
if ((msgs[i - 1].flags & IIC_M_NOSTOP) != 0 &&
|
||||
msgs[i].slave != msgs[i - 1].slave) {
|
||||
reason = "change of slave without stop";
|
||||
break;
|
||||
}
|
||||
if ((msgs[i].flags & IIC_M_NOSTART) != 0 &&
|
||||
(msgs[i].flags & IIC_M_RD) !=
|
||||
(msgs[i - 1].flags & IIC_M_RD)) {
|
||||
reason = "change of direction without repeated"
|
||||
" start";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (reason != NULL) {
|
||||
if (bootverbose)
|
||||
device_printf(dev, "%s\n", reason);
|
||||
return (IIC_ENOTSUPP);
|
||||
}
|
||||
|
||||
sx_xlock(&sc->call_lock);
|
||||
mtx_lock(&sc->io_lock);
|
||||
|
||||
/* Debugging - dump registers. */
|
||||
if (ig4_dump) {
|
||||
unit = device_get_unit(dev);
|
||||
if (ig4_dump & (1 << unit)) {
|
||||
ig4_dump &= ~(1 << unit);
|
||||
ig4iic_dump(sc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear any previous abort condition that may have been holding
|
||||
* the txfifo in reset.
|
||||
*/
|
||||
reg_read(sc, IG4_REG_CLR_TX_ABORT);
|
||||
|
||||
/*
|
||||
* Clean out any previously received data.
|
||||
*/
|
||||
if (sc->rpos != sc->rnext && bootverbose) {
|
||||
device_printf(sc->dev, "discarding %d bytes of spurious data\n",
|
||||
sc->rnext - sc->rpos);
|
||||
}
|
||||
sc->rpos = 0;
|
||||
sc->rnext = 0;
|
||||
|
||||
rpstart = false;
|
||||
error = 0;
|
||||
for (i = 0; i < nmsgs; i++) {
|
||||
if ((msgs[i].flags & IIC_M_NOSTART) == 0) {
|
||||
error = ig4iic_xfer_start(sc, msgs[i].slave);
|
||||
} else {
|
||||
if (!sc->slave_valid ||
|
||||
(msgs[i].slave >> 1) != sc->last_slave) {
|
||||
device_printf(dev, "start condition suppressed"
|
||||
"but slave address is not set up");
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
rpstart = false;
|
||||
}
|
||||
if (error != 0)
|
||||
break;
|
||||
|
||||
stop = (msgs[i].flags & IIC_M_NOSTOP) == 0;
|
||||
if (msgs[i].flags & IIC_M_RD)
|
||||
error = ig4iic_read(sc, msgs[i].buf, msgs[i].len,
|
||||
rpstart, stop);
|
||||
else
|
||||
error = ig4iic_write(sc, msgs[i].buf, msgs[i].len,
|
||||
rpstart, stop);
|
||||
if (error != 0)
|
||||
break;
|
||||
|
||||
rpstart = !stop;
|
||||
}
|
||||
|
||||
mtx_unlock(&sc->io_lock);
|
||||
sx_unlock(&sc->call_lock);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
ig4iic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
|
||||
{
|
||||
ig4iic_softc_t *sc = device_get_softc(dev);
|
||||
|
||||
sx_xlock(&sc->call_lock);
|
||||
mtx_lock(&sc->io_lock);
|
||||
|
||||
/* TODO handle speed configuration? */
|
||||
if (oldaddr != NULL)
|
||||
*oldaddr = sc->last_slave << 1;
|
||||
set_slave_addr(sc, addr >> 1, 0);
|
||||
if (addr == IIC_UNKNOWN)
|
||||
sc->slave_valid = false;
|
||||
|
||||
mtx_unlock(&sc->io_lock);
|
||||
sx_unlock(&sc->call_lock);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* SMBUS API FUNCTIONS
|
||||
*
|
||||
@ -549,9 +781,9 @@ ig4iic_attach(ig4iic_softc_t *sc)
|
||||
IG4_CTL_RESTARTEN |
|
||||
IG4_CTL_SPEED_STD);
|
||||
|
||||
sc->smb = device_add_child(sc->dev, "smbus", -1);
|
||||
if (sc->smb == NULL) {
|
||||
device_printf(sc->dev, "smbus driver not found\n");
|
||||
sc->iicbus = device_add_child(sc->dev, "iicbus", -1);
|
||||
if (sc->iicbus == NULL) {
|
||||
device_printf(sc->dev, "iicbus driver not found\n");
|
||||
error = ENXIO;
|
||||
goto done;
|
||||
}
|
||||
@ -624,15 +856,15 @@ ig4iic_detach(ig4iic_softc_t *sc)
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
if (sc->smb)
|
||||
device_delete_child(sc->dev, sc->smb);
|
||||
if (sc->iicbus)
|
||||
device_delete_child(sc->dev, sc->iicbus);
|
||||
if (sc->intr_handle)
|
||||
bus_teardown_intr(sc->dev, sc->intr_res, sc->intr_handle);
|
||||
|
||||
sx_xlock(&sc->call_lock);
|
||||
mtx_lock(&sc->io_lock);
|
||||
|
||||
sc->smb = NULL;
|
||||
sc->iicbus = NULL;
|
||||
sc->intr_handle = NULL;
|
||||
reg_write(sc, IG4_REG_INTR_MASK, 0);
|
||||
set_controller(sc, 0);
|
||||
@ -976,4 +1208,4 @@ ig4iic_dump(ig4iic_softc_t *sc)
|
||||
}
|
||||
#undef REGDUMP
|
||||
|
||||
DRIVER_MODULE(smbus, ig4iic, smbus_driver, smbus_devclass, NULL, NULL);
|
||||
DRIVER_MODULE(iicbus, ig4iic, iicbus_driver, iicbus_devclass, NULL, NULL);
|
||||
|
@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <dev/pci/pcivar.h>
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/smbus/smbconf.h>
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
|
||||
#include "smbus_if.h"
|
||||
|
||||
@ -180,6 +181,10 @@ static device_method_t ig4iic_pci_methods[] = {
|
||||
DEVMETHOD(smbus_bread, ig4iic_smb_bread),
|
||||
DEVMETHOD(smbus_trans, ig4iic_smb_trans),
|
||||
|
||||
DEVMETHOD(iicbus_transfer, ig4iic_transfer),
|
||||
DEVMETHOD(iicbus_reset, ig4iic_reset),
|
||||
DEVMETHOD(iicbus_callback, iicbus_null_callback),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
@ -191,7 +196,9 @@ static driver_t ig4iic_pci_driver = {
|
||||
|
||||
static devclass_t ig4iic_pci_devclass;
|
||||
|
||||
DRIVER_MODULE(ig4iic, pci, ig4iic_pci_driver, ig4iic_pci_devclass, 0, 0);
|
||||
DRIVER_MODULE_ORDERED(ig4iic, pci, ig4iic_pci_driver, ig4iic_pci_devclass, 0, 0,
|
||||
SI_ORDER_ANY);
|
||||
MODULE_DEPEND(ig4iic, pci, 1, 1, 1);
|
||||
MODULE_DEPEND(ig4iic, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
|
||||
MODULE_DEPEND(ig4iic, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
|
||||
MODULE_VERSION(ig4iic, 1);
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "device_if.h"
|
||||
#include "pci_if.h"
|
||||
#include "smbus_if.h"
|
||||
#include "iicbus_if.h"
|
||||
|
||||
#define IG4_RBUFSIZE 128
|
||||
#define IG4_RBUFMASK (IG4_RBUFSIZE - 1)
|
||||
@ -51,7 +52,7 @@ enum ig4_op { IG4_IDLE, IG4_READ, IG4_WRITE };
|
||||
struct ig4iic_softc {
|
||||
device_t dev;
|
||||
struct intr_config_hook enum_hook;
|
||||
device_t smb;
|
||||
device_t iicbus;
|
||||
struct resource *regs_res;
|
||||
int regs_rid;
|
||||
struct resource *intr_res;
|
||||
@ -115,5 +116,7 @@ extern smbus_pcall_t ig4iic_smb_pcall;
|
||||
extern smbus_bwrite_t ig4iic_smb_bwrite;
|
||||
extern smbus_bread_t ig4iic_smb_bread;
|
||||
extern smbus_trans_t ig4iic_smb_trans;
|
||||
extern iicbus_transfer_t ig4iic_transfer;
|
||||
extern iicbus_reset_t ig4iic_reset;
|
||||
|
||||
#endif
|
||||
|
@ -208,7 +208,9 @@ iicbus_write_ivar(device_t bus, device_t child, int which, uintptr_t value)
|
||||
default:
|
||||
return (EINVAL);
|
||||
case IICBUS_IVAR_ADDR:
|
||||
return (EINVAL);
|
||||
if (devi->addr != 0)
|
||||
return (EINVAL);
|
||||
devi->addr = value;
|
||||
case IICBUS_IVAR_NOSTOP:
|
||||
devi->nostop = value;
|
||||
break;
|
||||
|
@ -52,14 +52,12 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <dev/smbus/smbconf.h>
|
||||
#include <dev/smbus/smbus.h>
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
#include <dev/iicbus/iicbus.h>
|
||||
#include <dev/isl/isl.h>
|
||||
|
||||
#include "smbus_if.h"
|
||||
#include "iicbus_if.h"
|
||||
#include "bus_if.h"
|
||||
#include "device_if.h"
|
||||
|
||||
@ -71,46 +69,58 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
struct isl_softc {
|
||||
device_t dev;
|
||||
int addr;
|
||||
|
||||
struct sx isl_sx;
|
||||
};
|
||||
|
||||
/* Returns < 0 on problem. */
|
||||
static int isl_read_sensor(device_t dev, int addr, uint8_t cmd_mask);
|
||||
static int isl_read_sensor(device_t dev, uint8_t cmd_mask);
|
||||
|
||||
static int
|
||||
isl_read_byte(device_t dev, uint8_t reg, uint8_t *val)
|
||||
{
|
||||
uint16_t addr = iicbus_get_addr(dev);
|
||||
struct iic_msg msgs[] = {
|
||||
{ addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® },
|
||||
{ addr, IIC_M_RD, 1, val },
|
||||
};
|
||||
|
||||
return (iicbus_transfer(dev, msgs, nitems(msgs)));
|
||||
}
|
||||
|
||||
static int
|
||||
isl_write_byte(device_t dev, uint8_t reg, uint8_t val)
|
||||
{
|
||||
uint16_t addr = iicbus_get_addr(dev);
|
||||
uint8_t bytes[] = { reg, val };
|
||||
struct iic_msg msgs[] = {
|
||||
{ addr, IIC_M_WR, nitems(bytes), bytes },
|
||||
};
|
||||
|
||||
return (iicbus_transfer(dev, msgs, nitems(msgs)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the device
|
||||
*/
|
||||
static int
|
||||
init_device(device_t dev, int addr, int probe)
|
||||
init_device(device_t dev, int probe)
|
||||
{
|
||||
static char bl_init[] = { 0x00 };
|
||||
|
||||
device_t bus;
|
||||
int error;
|
||||
|
||||
bus = device_get_parent(dev); /* smbus */
|
||||
|
||||
/*
|
||||
* init procedure: send 0x00 to test ref and cmd reg 1
|
||||
*/
|
||||
error = smbus_trans(bus, addr, REG_TEST,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
|
||||
bl_init, sizeof(bl_init), NULL, 0, NULL);
|
||||
error = isl_write_byte(dev, REG_TEST, 0);
|
||||
if (error)
|
||||
goto done;
|
||||
|
||||
error = smbus_trans(bus, addr, REG_CMD1,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
|
||||
bl_init, sizeof(bl_init), NULL, 0, NULL);
|
||||
error = isl_write_byte(dev, REG_CMD1, 0);
|
||||
if (error)
|
||||
goto done;
|
||||
|
||||
pause("islinit", hz/100);
|
||||
|
||||
done:
|
||||
if (error)
|
||||
if (error && !probe)
|
||||
device_printf(dev, "Unable to initialize\n");
|
||||
return (error);
|
||||
}
|
||||
@ -138,27 +148,33 @@ static driver_t isl_driver = {
|
||||
sizeof(struct isl_softc),
|
||||
};
|
||||
|
||||
#if 0
|
||||
static void
|
||||
isl_identify(driver_t *driver, device_t parent)
|
||||
{
|
||||
|
||||
if (device_find_child(parent, "asl", -1)) {
|
||||
if (bootverbose)
|
||||
printf("asl: device(s) already created\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if we can communicate to our slave. */
|
||||
if (init_device(dev, 0x88, 1) == 0)
|
||||
BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "isl", -1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
isl_probe(device_t dev)
|
||||
{
|
||||
int addr;
|
||||
int error;
|
||||
uint32_t addr = iicbus_get_addr(dev);
|
||||
|
||||
addr = smbus_get_addr(dev);
|
||||
|
||||
/*
|
||||
* 0x44 - isl ambient light sensor on the acer c720.
|
||||
* (other devices might use other ids).
|
||||
*/
|
||||
if (addr != 0x44)
|
||||
if (addr != 0x88)
|
||||
return (ENXIO);
|
||||
|
||||
error = init_device(dev, addr, 1);
|
||||
if (error)
|
||||
if (init_device(dev, 1) != 0)
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "ISL Digital Ambient Light Sensor");
|
||||
|
||||
return (BUS_PROBE_VENDOR);
|
||||
}
|
||||
|
||||
@ -168,36 +184,28 @@ isl_attach(device_t dev)
|
||||
struct isl_softc *sc;
|
||||
struct sysctl_ctx_list *sysctl_ctx;
|
||||
struct sysctl_oid *sysctl_tree;
|
||||
int addr;
|
||||
int use_als;
|
||||
int use_ir;
|
||||
int use_prox;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->dev = dev;
|
||||
|
||||
if (!sc)
|
||||
return (ENOMEM);
|
||||
|
||||
addr = smbus_get_addr(dev);
|
||||
|
||||
if (init_device(dev, addr, 0))
|
||||
if (init_device(dev, 0) != 0)
|
||||
return (ENXIO);
|
||||
|
||||
sx_init(&sc->isl_sx, "ISL read lock");
|
||||
|
||||
sc->dev = dev;
|
||||
sc->addr = addr;
|
||||
|
||||
sysctl_ctx = device_get_sysctl_ctx(dev);
|
||||
sysctl_tree = device_get_sysctl_tree(dev);
|
||||
|
||||
use_als = isl_read_sensor(dev, addr, CMD1_MASK_ALS_ONCE) >= 0;
|
||||
use_ir = isl_read_sensor(dev, addr, CMD1_MASK_IR_ONCE) >= 0;
|
||||
use_prox = isl_read_sensor(dev, addr, CMD1_MASK_PROX_ONCE) >= 0;
|
||||
use_als = isl_read_sensor(dev, CMD1_MASK_ALS_ONCE) >= 0;
|
||||
use_ir = isl_read_sensor(dev, CMD1_MASK_IR_ONCE) >= 0;
|
||||
use_prox = isl_read_sensor(dev, CMD1_MASK_PROX_ONCE) >= 0;
|
||||
|
||||
if (use_als) {
|
||||
SYSCTL_ADD_PROC(sysctl_ctx,
|
||||
SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
|
||||
SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
|
||||
"als", CTLTYPE_INT | CTLFLAG_RD,
|
||||
sc, ISL_METHOD_ALS, isl_sysctl, "I",
|
||||
"Current ALS sensor read-out");
|
||||
@ -252,7 +260,6 @@ isl_sysctl(SYSCTL_HANDLER_ARGS)
|
||||
static int ranges[] = { 1000, 4000, 16000, 64000};
|
||||
|
||||
struct isl_softc *sc;
|
||||
device_t bus;
|
||||
uint8_t rbyte;
|
||||
int arg;
|
||||
int resolution;
|
||||
@ -262,10 +269,7 @@ isl_sysctl(SYSCTL_HANDLER_ARGS)
|
||||
arg = -1;
|
||||
|
||||
sx_xlock(&sc->isl_sx);
|
||||
bus = device_get_parent(sc->dev); /* smbus */
|
||||
if (smbus_trans(bus, sc->addr, REG_CMD2,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
|
||||
NULL, 0, &rbyte, sizeof(rbyte), NULL)) {
|
||||
if (isl_read_byte(sc->dev, REG_CMD2, &rbyte) != 0) {
|
||||
sx_xunlock(&sc->isl_sx);
|
||||
return (-1);
|
||||
}
|
||||
@ -275,16 +279,14 @@ isl_sysctl(SYSCTL_HANDLER_ARGS)
|
||||
|
||||
switch (oidp->oid_arg2) {
|
||||
case ISL_METHOD_ALS:
|
||||
arg = (isl_read_sensor(sc->dev, sc->addr,
|
||||
arg = (isl_read_sensor(sc->dev,
|
||||
CMD1_MASK_ALS_ONCE) * range) >> resolution;
|
||||
break;
|
||||
case ISL_METHOD_IR:
|
||||
arg = isl_read_sensor(sc->dev, sc->addr,
|
||||
CMD1_MASK_IR_ONCE);
|
||||
arg = isl_read_sensor(sc->dev, CMD1_MASK_IR_ONCE);
|
||||
break;
|
||||
case ISL_METHOD_PROX:
|
||||
arg = isl_read_sensor(sc->dev, sc->addr,
|
||||
CMD1_MASK_PROX_ONCE);
|
||||
arg = isl_read_sensor(sc->dev, CMD1_MASK_PROX_ONCE);
|
||||
break;
|
||||
case ISL_METHOD_RESOLUTION:
|
||||
arg = (1 << resolution);
|
||||
@ -300,18 +302,13 @@ isl_sysctl(SYSCTL_HANDLER_ARGS)
|
||||
}
|
||||
|
||||
static int
|
||||
isl_read_sensor(device_t dev, int addr, uint8_t cmd_mask)
|
||||
isl_read_sensor(device_t dev, uint8_t cmd_mask)
|
||||
{
|
||||
device_t bus;
|
||||
uint8_t rbyte;
|
||||
uint8_t cmd;
|
||||
int ret;
|
||||
|
||||
bus = device_get_parent(dev); /* smbus */
|
||||
|
||||
if (smbus_trans(bus, addr, REG_CMD1,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
|
||||
NULL, 0, &rbyte, sizeof(rbyte), NULL)) {
|
||||
if (isl_read_byte(dev, REG_CMD1, &rbyte) != 0) {
|
||||
device_printf(dev,
|
||||
"Couldn't read first byte before issuing command %d\n",
|
||||
cmd_mask);
|
||||
@ -319,27 +316,21 @@ isl_read_sensor(device_t dev, int addr, uint8_t cmd_mask)
|
||||
}
|
||||
|
||||
cmd = (rbyte & 0x1f) | cmd_mask;
|
||||
if (smbus_trans(bus, addr, REG_CMD1,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
|
||||
&cmd, sizeof(cmd), NULL, 0, NULL)) {
|
||||
if (isl_write_byte(dev, REG_CMD1, cmd) != 0) {
|
||||
device_printf(dev, "Couldn't write command %d\n", cmd_mask);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
pause("islconv", hz/10);
|
||||
|
||||
if (smbus_trans(bus, addr, REG_DATA1,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
|
||||
NULL, 0, &rbyte, sizeof(rbyte), NULL)) {
|
||||
if (isl_read_byte(dev, REG_DATA1, &rbyte) != 0) {
|
||||
device_printf(dev,
|
||||
"Couldn't read first byte after command %d\n", cmd_mask);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
ret = rbyte;
|
||||
if (smbus_trans(bus, addr, REG_DATA2,
|
||||
SMB_TRANS_NOCNT | SMB_TRANS_7BIT,
|
||||
NULL, 0, &rbyte, sizeof(rbyte), NULL)) {
|
||||
if (isl_read_byte(dev, REG_DATA2, &rbyte) != 0) {
|
||||
device_printf(dev, "Couldn't read second byte after command %d\n", cmd_mask);
|
||||
return (-1);
|
||||
}
|
||||
@ -348,6 +339,6 @@ isl_read_sensor(device_t dev, int addr, uint8_t cmd_mask)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
DRIVER_MODULE(isl, smbus, isl_driver, isl_devclass, NULL, NULL);
|
||||
MODULE_DEPEND(isl, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
|
||||
DRIVER_MODULE(isl, iicbus, isl_driver, isl_devclass, NULL, NULL);
|
||||
MODULE_DEPEND(isl, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
|
||||
MODULE_VERSION(isl, 1);
|
||||
|
@ -73,6 +73,7 @@ SUBDIR= \
|
||||
cd9660_iconv \
|
||||
${_ce} \
|
||||
${_cfi} \
|
||||
${_chromebook_platform} \
|
||||
${_ciss} \
|
||||
cloudabi \
|
||||
${_cloudabi32} \
|
||||
@ -604,6 +605,7 @@ _amdtemp= amdtemp
|
||||
_arcmsr= arcmsr
|
||||
_asmc= asmc
|
||||
_ciss= ciss
|
||||
_chromebook_platform= chromebook_platform
|
||||
_cmx= cmx
|
||||
_coretemp= coretemp
|
||||
.if ${MK_SOURCELESS_HOST} != "no"
|
||||
|
7
sys/modules/chromebook_platform/Makefile
Normal file
7
sys/modules/chromebook_platform/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
#$FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../dev/chromebook_platform
|
||||
KMOD = chromebook_platform
|
||||
SRCS = chromebook_platform.c bus_if.h device_if.h pci_if.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
@ -2,7 +2,7 @@
|
||||
|
||||
.PATH: ${.CURDIR}/../../../../dev/ichiic
|
||||
KMOD = ig4
|
||||
SRCS = device_if.h bus_if.h iicbb_if.h pci_if.h smbus_if.h \
|
||||
SRCS = device_if.h bus_if.h iicbus_if.h pci_if.h smbus_if.h \
|
||||
ig4_iic.c ig4_pci.c ig4_reg.h ig4_var.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
||||
|
@ -2,6 +2,6 @@
|
||||
|
||||
.PATH: ${.CURDIR}/../../../dev/cyapa
|
||||
KMOD = cyapa
|
||||
SRCS = cyapa.c device_if.h bus_if.h smbus_if.h vnode_if.h
|
||||
SRCS = cyapa.c device_if.h bus_if.h iicbus_if.h vnode_if.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
||||
|
@ -2,6 +2,6 @@
|
||||
|
||||
.PATH: ${.CURDIR}/../../../dev/isl
|
||||
KMOD = isl
|
||||
SRCS = isl.c device_if.h bus_if.h smbus_if.h vnode_if.h
|
||||
SRCS = isl.c device_if.h bus_if.h iicbus_if.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
||||
|
Loading…
Reference in New Issue
Block a user