2022-10-24 13:17:40 +03:00
|
|
|
/* $NetBSD: i2c.c,v 1.90 2022/10/24 10:17:40 riastradh Exp $ */
|
2003-09-30 04:35:30 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2003 Wasabi Systems, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed for the NetBSD Project by
|
|
|
|
* Wasabi Systems, Inc.
|
|
|
|
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
|
|
|
|
* or promote products derived from this software without specific prior
|
|
|
|
* written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2014-12-07 03:32:35 +03:00
|
|
|
#ifdef _KERNEL_OPT
|
|
|
|
#include "opt_i2c.h"
|
2022-01-17 22:34:31 +03:00
|
|
|
|
|
|
|
#include "opt_fdt.h"
|
|
|
|
#ifdef FDT
|
|
|
|
#define I2C_USE_FDT
|
|
|
|
#endif /* FDT */
|
|
|
|
|
|
|
|
#if defined(__aarch64__) || defined(__amd64__)
|
|
|
|
#include "acpica.h"
|
|
|
|
#if NACPICA > 0
|
|
|
|
#define I2C_USE_ACPI
|
|
|
|
#endif /* NACPICA > 0 */
|
|
|
|
#endif /* __aarch64__ || __amd64__ */
|
|
|
|
|
|
|
|
#endif /* _KERNEL_OPT */
|
2014-12-07 03:32:35 +03:00
|
|
|
|
2007-12-11 15:09:21 +03:00
|
|
|
#include <sys/cdefs.h>
|
2022-10-24 13:17:40 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.90 2022/10/24 10:17:40 riastradh Exp $");
|
2007-12-11 15:09:21 +03:00
|
|
|
|
2003-09-30 04:35:30 +04:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/device.h>
|
|
|
|
#include <sys/event.h>
|
|
|
|
#include <sys/conf.h>
|
2007-02-06 02:31:37 +03:00
|
|
|
#include <sys/malloc.h>
|
2011-10-03 01:12:43 +04:00
|
|
|
#include <sys/kmem.h>
|
2007-02-06 02:31:37 +03:00
|
|
|
#include <sys/kthread.h>
|
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/kernel.h>
|
2011-10-02 21:39:40 +04:00
|
|
|
#include <sys/fcntl.h>
|
2011-10-02 15:38:48 +04:00
|
|
|
#include <sys/module.h>
|
2015-12-10 08:33:28 +03:00
|
|
|
#include <sys/once.h>
|
|
|
|
#include <sys/mutex.h>
|
2003-09-30 04:35:30 +04:00
|
|
|
|
2022-01-17 22:34:31 +03:00
|
|
|
#ifdef I2C_USE_ACPI
|
|
|
|
#include <dev/acpi/acpivar.h>
|
|
|
|
#endif /* I2C_USE_ACPI */
|
|
|
|
|
|
|
|
#ifdef I2C_USE_FDT
|
|
|
|
#include <dev/fdt/fdtvar.h>
|
|
|
|
#endif /* I2C_USE_FDT */
|
|
|
|
|
2003-09-30 04:35:30 +04:00
|
|
|
#include <dev/i2c/i2cvar.h>
|
|
|
|
|
2017-10-28 07:53:54 +03:00
|
|
|
#include "ioconf.h"
|
2003-09-30 04:35:30 +04:00
|
|
|
#include "locators.h"
|
|
|
|
|
2014-12-07 03:32:35 +03:00
|
|
|
#ifndef I2C_MAX_ADDR
|
2011-08-02 22:46:35 +04:00
|
|
|
#define I2C_MAX_ADDR 0x3ff /* 10-bit address, max */
|
2014-12-07 03:32:35 +03:00
|
|
|
#endif
|
2011-08-02 22:46:35 +04:00
|
|
|
|
2003-09-30 04:35:30 +04:00
|
|
|
struct iic_softc {
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
device_t sc_dev;
|
2003-09-30 04:35:30 +04:00
|
|
|
i2c_tag_t sc_tag;
|
2011-08-02 22:46:35 +04:00
|
|
|
device_t sc_devices[I2C_MAX_ADDR + 1];
|
2003-09-30 04:35:30 +04:00
|
|
|
};
|
|
|
|
|
2011-10-02 20:39:45 +04:00
|
|
|
static dev_type_open(iic_open);
|
|
|
|
static dev_type_close(iic_close);
|
|
|
|
static dev_type_ioctl(iic_ioctl);
|
|
|
|
|
2015-12-10 08:33:28 +03:00
|
|
|
int iic_init(void);
|
|
|
|
|
|
|
|
kmutex_t iic_mtx;
|
|
|
|
int iic_refcnt;
|
|
|
|
|
|
|
|
ONCE_DECL(iic_once);
|
|
|
|
|
2011-10-02 20:39:45 +04:00
|
|
|
const struct cdevsw iic_cdevsw = {
|
2014-03-16 09:20:22 +04:00
|
|
|
.d_open = iic_open,
|
|
|
|
.d_close = iic_close,
|
|
|
|
.d_read = noread,
|
|
|
|
.d_write = nowrite,
|
|
|
|
.d_ioctl = iic_ioctl,
|
|
|
|
.d_stop = nostop,
|
|
|
|
.d_tty = notty,
|
|
|
|
.d_poll = nopoll,
|
|
|
|
.d_mmap = nommap,
|
|
|
|
.d_kqfilter = nokqfilter,
|
2014-07-25 12:10:31 +04:00
|
|
|
.d_discard = nodiscard,
|
2014-03-16 09:20:22 +04:00
|
|
|
.d_flag = D_OTHER
|
2011-10-02 20:39:45 +04:00
|
|
|
};
|
|
|
|
|
2010-02-28 14:34:42 +03:00
|
|
|
static void iic_fill_compat(struct i2c_attach_args*, const char*,
|
|
|
|
size_t, char **);
|
2007-02-06 02:31:37 +03:00
|
|
|
|
2010-02-28 14:34:42 +03:00
|
|
|
static int
|
|
|
|
iic_print_direct(void *aux, const char *pnp)
|
|
|
|
{
|
|
|
|
struct i2c_attach_args *ia = aux;
|
|
|
|
|
|
|
|
if (pnp != NULL)
|
2022-07-23 06:05:27 +03:00
|
|
|
aprint_normal("%s%s%s%s at %s addr 0x%02x",
|
2018-06-17 00:22:13 +03:00
|
|
|
ia->ia_name ? ia->ia_name : "(unknown)",
|
2022-07-23 06:05:27 +03:00
|
|
|
ia->ia_ncompat ? " (" : "",
|
|
|
|
ia->ia_ncompat ? ia->ia_compat[0] : "",
|
|
|
|
ia->ia_ncompat ? ")" : "",
|
2018-06-17 00:22:13 +03:00
|
|
|
pnp, ia->ia_addr);
|
2010-02-28 14:34:42 +03:00
|
|
|
else
|
|
|
|
aprint_normal(" addr 0x%02x", ia->ia_addr);
|
|
|
|
|
|
|
|
return UNCONF;
|
|
|
|
}
|
|
|
|
|
2003-09-30 04:35:30 +04:00
|
|
|
static int
|
2006-11-16 04:32:37 +03:00
|
|
|
iic_print(void *aux, const char *pnp)
|
2003-09-30 04:35:30 +04:00
|
|
|
{
|
|
|
|
struct i2c_attach_args *ia = aux;
|
|
|
|
|
2018-05-15 05:02:18 +03:00
|
|
|
if (ia->ia_addr != (i2c_addr_t)IICCF_ADDR_DEFAULT)
|
2006-03-28 03:59:38 +04:00
|
|
|
aprint_normal(" addr 0x%x", ia->ia_addr);
|
2003-09-30 04:35:30 +04:00
|
|
|
|
2011-10-02 16:25:40 +04:00
|
|
|
return UNCONF;
|
2003-09-30 04:35:30 +04:00
|
|
|
}
|
|
|
|
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
static bool
|
|
|
|
iic_is_special_address(i2c_addr_t addr)
|
|
|
|
{
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See: https://www.i2c-bus.org/addressing/
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* General Call (read) / Start Byte (write) */
|
|
|
|
if (addr == 0x00)
|
|
|
|
return (true);
|
|
|
|
|
|
|
|
/* CBUS Addresses */
|
|
|
|
if (addr == 0x01)
|
|
|
|
return (true);
|
|
|
|
|
|
|
|
/* Reserved for Different Bus Formats */
|
|
|
|
if (addr == 0x02)
|
|
|
|
return (true);
|
|
|
|
|
|
|
|
/* Reserved for future purposes */
|
|
|
|
if (addr == 0x03)
|
|
|
|
return (true);
|
|
|
|
|
|
|
|
/* High Speed Master Code */
|
|
|
|
if ((addr & 0x7c) == 0x04)
|
|
|
|
return (true);
|
|
|
|
|
|
|
|
/* 10-bit Slave Addressing prefix */
|
|
|
|
if ((addr & 0x7c) == 0x78)
|
|
|
|
return (true);
|
|
|
|
|
|
|
|
/* Reserved for future purposes */
|
|
|
|
if ((addr & 0x7c) == 0x7c)
|
|
|
|
return (true);
|
|
|
|
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
iic_probe_none(struct iic_softc *sc,
|
|
|
|
const struct i2c_attach_args *ia, int flags)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
iic_probe_smbus_quick_write(struct iic_softc *sc,
|
|
|
|
const struct i2c_attach_args *ia, int flags)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if ((error = iic_acquire_bus(ia->ia_tag, flags)) == 0) {
|
|
|
|
error = iic_smbus_quick_write(ia->ia_tag, ia->ia_addr, flags);
|
|
|
|
}
|
|
|
|
(void) iic_release_bus(ia->ia_tag, flags);
|
|
|
|
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
iic_probe_smbus_receive_byte(struct iic_softc *sc,
|
|
|
|
const struct i2c_attach_args *ia, int flags)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if ((error = iic_acquire_bus(ia->ia_tag, flags)) == 0) {
|
|
|
|
uint8_t dummy;
|
|
|
|
|
|
|
|
error = iic_smbus_receive_byte(ia->ia_tag, ia->ia_addr,
|
|
|
|
&dummy, flags);
|
|
|
|
}
|
|
|
|
(void) iic_release_bus(ia->ia_tag, flags);
|
|
|
|
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2020-07-07 19:14:23 +03:00
|
|
|
iic_indirect_driver_is_permitted(struct iic_softc *sc, cfdata_t cf)
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
{
|
|
|
|
prop_object_iterator_t iter;
|
2020-07-07 19:14:23 +03:00
|
|
|
prop_array_t permitlist;
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
prop_string_t pstr;
|
|
|
|
prop_type_t ptype;
|
|
|
|
bool rv = false;
|
|
|
|
|
2020-07-07 19:14:23 +03:00
|
|
|
permitlist = prop_dictionary_get(device_properties(sc->sc_dev),
|
|
|
|
I2C_PROP_INDIRECT_DEVICE_PERMITLIST);
|
|
|
|
if (permitlist == NULL) {
|
|
|
|
/* No permitlist -> everything allowed */
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
2020-07-07 19:14:23 +03:00
|
|
|
if ((ptype = prop_object_type(permitlist)) != PROP_TYPE_ARRAY) {
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
aprint_error_dev(sc->sc_dev,
|
|
|
|
"invalid property type (%d) for '%s'; must be array (%d)\n",
|
2020-07-07 19:14:23 +03:00
|
|
|
ptype, I2C_PROP_INDIRECT_DEVICE_PERMITLIST,
|
|
|
|
PROP_TYPE_ARRAY);
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
|
2020-07-07 19:14:23 +03:00
|
|
|
iter = prop_array_iterator(permitlist);
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
while ((pstr = prop_object_iterator_next(iter)) != NULL) {
|
2020-06-11 05:32:06 +03:00
|
|
|
if (prop_string_equals_string(pstr, cf->cf_name)) {
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
rv = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
prop_object_iterator_release(iter);
|
|
|
|
|
|
|
|
return (rv);
|
|
|
|
}
|
|
|
|
|
2003-09-30 04:35:30 +04:00
|
|
|
static int
|
2008-05-04 19:26:29 +04:00
|
|
|
iic_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
|
2003-09-30 04:35:30 +04:00
|
|
|
{
|
2008-05-04 19:26:29 +04:00
|
|
|
struct iic_softc *sc = device_private(parent);
|
2003-09-30 04:35:30 +04:00
|
|
|
struct i2c_attach_args ia;
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
int (*probe_func)(struct iic_softc *,
|
|
|
|
const struct i2c_attach_args *, int);
|
|
|
|
prop_string_t pstr;
|
|
|
|
i2c_addr_t first_addr, last_addr;
|
2003-09-30 04:35:30 +04:00
|
|
|
|
2018-05-15 05:02:18 +03:00
|
|
|
/*
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
* Before we do any more work, consult the allowed-driver
|
2020-07-07 19:14:23 +03:00
|
|
|
* permit-list for this bus (if any).
|
2018-05-15 05:02:18 +03:00
|
|
|
*/
|
2020-07-07 19:14:23 +03:00
|
|
|
if (iic_indirect_driver_is_permitted(sc, cf) == false)
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
return (0);
|
|
|
|
|
|
|
|
/* default to "quick write". */
|
|
|
|
probe_func = iic_probe_smbus_quick_write;
|
|
|
|
|
|
|
|
pstr = prop_dictionary_get(device_properties(sc->sc_dev),
|
|
|
|
I2C_PROP_INDIRECT_PROBE_STRATEGY);
|
|
|
|
if (pstr == NULL) {
|
|
|
|
/* Use the default. */
|
2020-06-11 05:32:06 +03:00
|
|
|
} else if (prop_string_equals_string(pstr,
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
I2C_PROBE_STRATEGY_QUICK_WRITE)) {
|
|
|
|
probe_func = iic_probe_smbus_quick_write;
|
2020-06-11 05:32:06 +03:00
|
|
|
} else if (prop_string_equals_string(pstr,
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
I2C_PROBE_STRATEGY_RECEIVE_BYTE)) {
|
|
|
|
probe_func = iic_probe_smbus_receive_byte;
|
2020-06-11 05:32:06 +03:00
|
|
|
} else if (prop_string_equals_string(pstr,
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
I2C_PROBE_STRATEGY_NONE)) {
|
|
|
|
probe_func = iic_probe_none;
|
|
|
|
} else {
|
|
|
|
aprint_error_dev(sc->sc_dev,
|
|
|
|
"unknown probe strategy '%s'; defaulting to '%s'\n",
|
2020-06-11 05:32:06 +03:00
|
|
|
prop_string_value(pstr),
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
I2C_PROBE_STRATEGY_QUICK_WRITE);
|
|
|
|
|
|
|
|
/* Use the default. */
|
|
|
|
}
|
2018-05-15 05:02:18 +03:00
|
|
|
|
2003-09-30 04:35:30 +04:00
|
|
|
ia.ia_tag = sc->sc_tag;
|
|
|
|
|
2010-03-01 20:35:21 +03:00
|
|
|
ia.ia_name = NULL;
|
|
|
|
ia.ia_ncompat = 0;
|
|
|
|
ia.ia_compat = NULL;
|
2017-12-10 19:53:32 +03:00
|
|
|
ia.ia_prop = NULL;
|
2010-03-01 20:35:21 +03:00
|
|
|
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
if (cf->cf_loc[IICCF_ADDR] == IICCF_ADDR_DEFAULT) {
|
|
|
|
/*
|
|
|
|
* This particular config directive has
|
|
|
|
* wildcarded the address, so we will
|
|
|
|
* scan the entire bus for it.
|
|
|
|
*/
|
|
|
|
first_addr = 0;
|
|
|
|
last_addr = I2C_MAX_ADDR;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* This config directive hard-wires the i2c
|
|
|
|
* bus address for the device, so there is
|
|
|
|
* no need to go poking around at any other
|
|
|
|
* addresses.
|
|
|
|
*/
|
|
|
|
if (cf->cf_loc[IICCF_ADDR] < 0 ||
|
|
|
|
cf->cf_loc[IICCF_ADDR] > I2C_MAX_ADDR) {
|
|
|
|
/* Invalid config directive! */
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
first_addr = last_addr = cf->cf_loc[IICCF_ADDR];
|
|
|
|
}
|
|
|
|
|
|
|
|
for (ia.ia_addr = first_addr; ia.ia_addr <= last_addr; ia.ia_addr++) {
|
|
|
|
int error, match_result;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip I2C addresses that are reserved for
|
|
|
|
* special purposes.
|
|
|
|
*/
|
|
|
|
if (iic_is_special_address(ia.ia_addr))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip addresses where a device is already attached.
|
|
|
|
*/
|
2013-08-07 23:38:45 +04:00
|
|
|
if (sc->sc_devices[ia.ia_addr] != NULL)
|
|
|
|
continue;
|
|
|
|
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
/*
|
|
|
|
* Call the "match" routine for the device. If that
|
|
|
|
* returns success, then call the probe strategy
|
|
|
|
* function.
|
|
|
|
*
|
|
|
|
* We do it in this order because i2c devices tend
|
|
|
|
* to be found at a small number of possible addresses
|
|
|
|
* (e.g. read-time clocks that are only ever found at
|
|
|
|
* 0x68). This gives the driver a chance to skip any
|
|
|
|
* address that are not valid for the device, saving
|
|
|
|
* us from having to poke at the bus to see if anything
|
|
|
|
* is there.
|
|
|
|
*/
|
Merge thorpej-cfargs branch:
Simplify and make extensible the config_search() / config_found() /
config_attach() interfaces: rather than having different variants for
which arguments you want pass along, just have a single call that
takes a variadic list of tag-value arguments.
Adjust all call sites:
- Simplify wherever possible; don't pass along arguments that aren't
actually needed.
- Don't be explicit about what interface attribute is attaching if
the device only has one. (More simplification.)
- Add a config_probe() function to be used in indirect configuiration
situations, making is visibly easier to see when indirect config is
in play, and allowing for future change in semantics. (As of now,
this is just a wrapper around config_match(), but that is an
implementation detail.)
Remove unnecessary or redundant interface attributes where they're not
needed.
There are currently 5 "cfargs" defined:
- CFARG_SUBMATCH (submatch function for direct config)
- CFARG_SEARCH (search function for indirect config)
- CFARG_IATTR (interface attribte)
- CFARG_LOCATORS (locators array)
- CFARG_DEVHANDLE (devhandle_t - wraps OFW, ACPI, etc. handles)
...and a sentinel value CFARG_EOL.
Add some extra sanity checking to ensure that interface attributes
aren't ambiguous.
Use CFARG_DEVHANDLE in MI FDT, OFW, and ACPI code, and macppc and shark
ports to associate those device handles with device_t instance. This
will trickle trough to more places over time (need back-end for pre-OFW
Sun OBP; any others?).
2021-04-25 02:36:23 +03:00
|
|
|
match_result = config_probe(parent, cf, &ia);/*XXX*/
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
if (match_result <= 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the quality of the match by the driver was low
|
|
|
|
* (i.e. matched on being a valid address only, didn't
|
|
|
|
* perform any hardware probe), invoke our probe routine
|
|
|
|
* to see if it looks like something is really there.
|
|
|
|
*/
|
|
|
|
if (match_result == I2C_MATCH_ADDRESS_ONLY &&
|
2019-12-23 21:20:02 +03:00
|
|
|
(error = (*probe_func)(sc, &ia, 0)) != 0)
|
2013-08-07 23:38:45 +04:00
|
|
|
continue;
|
|
|
|
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
sc->sc_devices[ia.ia_addr] =
|
2021-08-07 19:18:40 +03:00
|
|
|
config_attach(parent, cf, &ia, iic_print, CFARGS_NONE);
|
2011-08-02 22:46:35 +04:00
|
|
|
}
|
2013-08-07 23:38:45 +04:00
|
|
|
|
2011-10-02 16:25:40 +04:00
|
|
|
return 0;
|
2003-09-30 04:35:30 +04:00
|
|
|
}
|
|
|
|
|
2011-08-02 22:46:35 +04:00
|
|
|
static void
|
|
|
|
iic_child_detach(device_t parent, device_t child)
|
|
|
|
{
|
|
|
|
struct iic_softc *sc = device_private(parent);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i <= I2C_MAX_ADDR; i++)
|
|
|
|
if (sc->sc_devices[i] == child) {
|
|
|
|
sc->sc_devices[i] = NULL;
|
|
|
|
break;
|
2013-08-07 23:38:45 +04:00
|
|
|
}
|
2011-08-02 22:46:35 +04:00
|
|
|
}
|
|
|
|
|
2011-07-31 19:58:25 +04:00
|
|
|
static int
|
|
|
|
iic_rescan(device_t self, const char *ifattr, const int *locators)
|
|
|
|
{
|
Merge thorpej-cfargs branch:
Simplify and make extensible the config_search() / config_found() /
config_attach() interfaces: rather than having different variants for
which arguments you want pass along, just have a single call that
takes a variadic list of tag-value arguments.
Adjust all call sites:
- Simplify wherever possible; don't pass along arguments that aren't
actually needed.
- Don't be explicit about what interface attribute is attaching if
the device only has one. (More simplification.)
- Add a config_probe() function to be used in indirect configuiration
situations, making is visibly easier to see when indirect config is
in play, and allowing for future change in semantics. (As of now,
this is just a wrapper around config_match(), but that is an
implementation detail.)
Remove unnecessary or redundant interface attributes where they're not
needed.
There are currently 5 "cfargs" defined:
- CFARG_SUBMATCH (submatch function for direct config)
- CFARG_SEARCH (search function for indirect config)
- CFARG_IATTR (interface attribte)
- CFARG_LOCATORS (locators array)
- CFARG_DEVHANDLE (devhandle_t - wraps OFW, ACPI, etc. handles)
...and a sentinel value CFARG_EOL.
Add some extra sanity checking to ensure that interface attributes
aren't ambiguous.
Use CFARG_DEVHANDLE in MI FDT, OFW, and ACPI code, and macppc and shark
ports to associate those device handles with device_t instance. This
will trickle trough to more places over time (need back-end for pre-OFW
Sun OBP; any others?).
2021-04-25 02:36:23 +03:00
|
|
|
config_search(self, NULL,
|
2021-08-07 19:18:40 +03:00
|
|
|
CFARGS(.search = iic_search,
|
|
|
|
.locators = locators));
|
2011-07-31 19:58:25 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-09-30 04:35:30 +04:00
|
|
|
static int
|
2008-05-04 19:26:29 +04:00
|
|
|
iic_match(device_t parent, cfdata_t cf, void *aux)
|
2003-09-30 04:35:30 +04:00
|
|
|
{
|
|
|
|
|
2011-10-02 16:25:40 +04:00
|
|
|
return 1;
|
2003-09-30 04:35:30 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-05-04 19:26:29 +04:00
|
|
|
iic_attach(device_t parent, device_t self, void *aux)
|
2003-09-30 04:35:30 +04:00
|
|
|
{
|
2006-03-29 10:41:24 +04:00
|
|
|
struct iic_softc *sc = device_private(self);
|
2003-09-30 04:35:30 +04:00
|
|
|
struct i2cbus_attach_args *iba = aux;
|
2010-02-28 14:34:42 +03:00
|
|
|
prop_array_t child_devices;
|
2013-09-24 22:04:53 +04:00
|
|
|
prop_dictionary_t props;
|
2010-02-28 14:34:42 +03:00
|
|
|
char *buf;
|
2007-07-10 00:51:58 +04:00
|
|
|
i2c_tag_t ic;
|
2020-06-12 06:32:30 +03:00
|
|
|
bool no_indirect_config = false;
|
2003-09-30 04:35:30 +04:00
|
|
|
|
2011-10-02 22:58:45 +04:00
|
|
|
aprint_naive("\n");
|
2003-09-30 04:35:30 +04:00
|
|
|
aprint_normal(": I2C bus\n");
|
|
|
|
|
Changes / enhancements to i2c indirect device auto-configuration:
— iic_search() chooses a “probe strategy” based on the
"i2c-indirect-probe-strategy” property on the “iic” instance.
Valid values are "smbus-quick-write”, "smbus-receive-byte”, and
“none”. If no value is specified, the default is "smbus-quick-write”.
— If the "i2c-indirect-device-whitelist” exists on the “iic” instance,
iic_search() will first check the driver name in the cfdata_t against
this list, and only allow the match/probe to move forward if the
cfdata_t driver name is in the list. This is primarily to accommodate
the Intel integrated memory controller neutered-i2c-thing.
— If the cfdata_t specifies a wildcard address, each address of the i2c
bus will be consulted. If the cfdata_t contains a nailed-down address,
then we limit the bus scan to that specific address.
— We explicitly skip reserved / special i2c addresses, such as the
General-Call address, etc.
— We introduce the notion of a “match quality” for i2c drivers. From
lowest-quality to highest-quality: matched by plausible address only,
matched by plausible address and poking at the bus to see if the
device looks reasonable, matched by direct-config “compatible” string,
matched by direct-config “driver name” string.
— If the “match quality” is merely “plausible address only”, then
iic_search() will use the probe strategy selected above to see if
a device responds to that address.
2018-06-07 16:30:49 +03:00
|
|
|
sc->sc_dev = self;
|
2003-09-30 04:35:30 +04:00
|
|
|
sc->sc_tag = iba->iba_tag;
|
2007-07-10 00:51:58 +04:00
|
|
|
ic = sc->sc_tag;
|
2003-09-30 04:35:30 +04:00
|
|
|
|
2007-12-09 23:27:42 +03:00
|
|
|
if (!pmf_device_register(self, NULL, NULL))
|
|
|
|
aprint_error_dev(self, "couldn't establish power handler\n");
|
|
|
|
|
2015-12-13 20:14:56 +03:00
|
|
|
if (iba->iba_child_devices) {
|
|
|
|
child_devices = iba->iba_child_devices;
|
2020-06-12 06:32:30 +03:00
|
|
|
no_indirect_config = true;
|
2015-12-13 20:14:56 +03:00
|
|
|
} else {
|
|
|
|
props = device_properties(parent);
|
2020-06-12 06:32:30 +03:00
|
|
|
prop_dictionary_get_bool(props, "i2c-no-indirect-config",
|
|
|
|
&no_indirect_config);
|
2015-12-13 20:14:56 +03:00
|
|
|
child_devices = prop_dictionary_get(props, "i2c-child-devices");
|
|
|
|
}
|
|
|
|
|
2010-02-28 14:34:42 +03:00
|
|
|
if (child_devices) {
|
|
|
|
unsigned int i, count;
|
|
|
|
prop_dictionary_t dev;
|
|
|
|
prop_data_t cdata;
|
2018-06-26 09:34:55 +03:00
|
|
|
uint32_t addr;
|
2010-02-28 14:34:42 +03:00
|
|
|
uint64_t cookie;
|
2021-01-25 15:18:18 +03:00
|
|
|
uint32_t cookietype;
|
2010-02-28 14:34:42 +03:00
|
|
|
const char *name;
|
|
|
|
struct i2c_attach_args ia;
|
2022-01-17 22:34:31 +03:00
|
|
|
devhandle_t devhandle;
|
2016-07-23 20:42:37 +03:00
|
|
|
int loc[IICCF_NLOCS];
|
2010-02-28 14:34:42 +03:00
|
|
|
|
|
|
|
memset(loc, 0, sizeof loc);
|
|
|
|
count = prop_array_count(child_devices);
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
dev = prop_array_get(child_devices, i);
|
|
|
|
if (!dev) continue;
|
2021-06-21 06:04:27 +03:00
|
|
|
if (!prop_dictionary_get_string(
|
2018-06-17 00:22:13 +03:00
|
|
|
dev, "name", &name)) {
|
|
|
|
/* "name" property is optional. */
|
|
|
|
name = NULL;
|
|
|
|
}
|
2010-02-28 14:34:42 +03:00
|
|
|
if (!prop_dictionary_get_uint32(dev, "addr", &addr))
|
|
|
|
continue;
|
|
|
|
if (!prop_dictionary_get_uint64(dev, "cookie", &cookie))
|
|
|
|
cookie = 0;
|
2021-01-25 15:18:18 +03:00
|
|
|
if (!prop_dictionary_get_uint32(dev, "cookietype",
|
|
|
|
&cookietype))
|
|
|
|
cookietype = I2C_COOKIE_NONE;
|
2016-07-23 20:42:37 +03:00
|
|
|
loc[IICCF_ADDR] = addr;
|
2010-02-28 14:34:42 +03:00
|
|
|
|
|
|
|
memset(&ia, 0, sizeof ia);
|
|
|
|
ia.ia_addr = addr;
|
|
|
|
ia.ia_tag = ic;
|
|
|
|
ia.ia_name = name;
|
|
|
|
ia.ia_cookie = cookie;
|
2021-01-25 15:18:18 +03:00
|
|
|
ia.ia_cookietype = cookietype;
|
2017-12-10 19:53:32 +03:00
|
|
|
ia.ia_prop = dev;
|
2010-02-28 14:34:42 +03:00
|
|
|
|
2022-01-21 18:55:36 +03:00
|
|
|
devhandle = devhandle_invalid();
|
2022-01-17 22:34:31 +03:00
|
|
|
#ifdef I2C_USE_FDT
|
|
|
|
if (cookietype == I2C_COOKIE_OF) {
|
2022-01-22 14:49:16 +03:00
|
|
|
devhandle = devhandle_from_of(devhandle,
|
|
|
|
(int)cookie);
|
2022-01-17 22:34:31 +03:00
|
|
|
}
|
|
|
|
#endif /* I2C_USE_FDT */
|
|
|
|
#ifdef I2C_USE_ACPI
|
|
|
|
if (cookietype == I2C_COOKIE_ACPI) {
|
|
|
|
devhandle =
|
2022-01-22 14:49:16 +03:00
|
|
|
devhandle_from_acpi(devhandle,
|
|
|
|
(ACPI_HANDLE)cookie);
|
2022-01-17 22:34:31 +03:00
|
|
|
}
|
|
|
|
#endif /* I2C_USE_ACPI */
|
|
|
|
|
2010-02-28 14:34:42 +03:00
|
|
|
buf = NULL;
|
|
|
|
cdata = prop_dictionary_get(dev, "compatible");
|
|
|
|
if (cdata)
|
|
|
|
iic_fill_compat(&ia,
|
2020-06-11 05:32:06 +03:00
|
|
|
prop_data_value(cdata),
|
2010-02-28 14:34:42 +03:00
|
|
|
prop_data_size(cdata), &buf);
|
|
|
|
|
2018-06-17 00:22:13 +03:00
|
|
|
if (name == NULL && cdata == NULL) {
|
2011-10-02 22:58:45 +04:00
|
|
|
aprint_error_dev(self,
|
2018-06-17 00:22:13 +03:00
|
|
|
"WARNING: ignoring bad child device entry "
|
|
|
|
"for address 0x%02x\n", addr);
|
|
|
|
} else {
|
|
|
|
if (addr > I2C_MAX_ADDR) {
|
|
|
|
aprint_error_dev(self,
|
|
|
|
"WARNING: ignoring bad device "
|
|
|
|
"address @ 0x%02x\n", addr);
|
|
|
|
} else if (sc->sc_devices[addr] == NULL) {
|
|
|
|
sc->sc_devices[addr] =
|
Merge thorpej-cfargs branch:
Simplify and make extensible the config_search() / config_found() /
config_attach() interfaces: rather than having different variants for
which arguments you want pass along, just have a single call that
takes a variadic list of tag-value arguments.
Adjust all call sites:
- Simplify wherever possible; don't pass along arguments that aren't
actually needed.
- Don't be explicit about what interface attribute is attaching if
the device only has one. (More simplification.)
- Add a config_probe() function to be used in indirect configuiration
situations, making is visibly easier to see when indirect config is
in play, and allowing for future change in semantics. (As of now,
this is just a wrapper around config_match(), but that is an
implementation detail.)
Remove unnecessary or redundant interface attributes where they're not
needed.
There are currently 5 "cfargs" defined:
- CFARG_SUBMATCH (submatch function for direct config)
- CFARG_SEARCH (search function for indirect config)
- CFARG_IATTR (interface attribte)
- CFARG_LOCATORS (locators array)
- CFARG_DEVHANDLE (devhandle_t - wraps OFW, ACPI, etc. handles)
...and a sentinel value CFARG_EOL.
Add some extra sanity checking to ensure that interface attributes
aren't ambiguous.
Use CFARG_DEVHANDLE in MI FDT, OFW, and ACPI code, and macppc and shark
ports to associate those device handles with device_t instance. This
will trickle trough to more places over time (need back-end for pre-OFW
Sun OBP; any others?).
2021-04-25 02:36:23 +03:00
|
|
|
config_found(self, &ia,
|
|
|
|
iic_print_direct,
|
2022-01-17 22:34:31 +03:00
|
|
|
CFARGS(.locators = loc,
|
|
|
|
.devhandle = devhandle));
|
2018-06-17 00:22:13 +03:00
|
|
|
}
|
2011-10-02 22:58:45 +04:00
|
|
|
}
|
2010-02-28 14:34:42 +03:00
|
|
|
|
|
|
|
if (ia.ia_compat)
|
|
|
|
free(ia.ia_compat, M_TEMP);
|
|
|
|
if (buf)
|
|
|
|
free(buf, M_TEMP);
|
|
|
|
}
|
2020-06-12 06:32:30 +03:00
|
|
|
} else if (!no_indirect_config) {
|
2010-02-28 14:34:42 +03:00
|
|
|
/*
|
|
|
|
* Attach all i2c devices described in the kernel
|
|
|
|
* configuration file.
|
|
|
|
*/
|
2011-07-31 19:58:25 +04:00
|
|
|
iic_rescan(self, "iic", NULL);
|
2010-02-28 14:34:42 +03:00
|
|
|
}
|
2003-09-30 04:35:30 +04:00
|
|
|
}
|
|
|
|
|
2011-10-02 22:58:45 +04:00
|
|
|
static int
|
|
|
|
iic_detach(device_t self, int flags)
|
|
|
|
{
|
2022-10-24 13:17:40 +03:00
|
|
|
int error;
|
2011-10-02 22:58:45 +04:00
|
|
|
|
2022-10-24 13:17:40 +03:00
|
|
|
error = config_detach_children(self, flags);
|
|
|
|
if (error)
|
|
|
|
return error;
|
2011-10-02 22:58:45 +04:00
|
|
|
|
|
|
|
pmf_device_deregister(self);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-02-28 14:34:42 +03:00
|
|
|
static void
|
|
|
|
iic_fill_compat(struct i2c_attach_args *ia, const char *compat, size_t len,
|
|
|
|
char **buffer)
|
|
|
|
{
|
|
|
|
int count, i;
|
|
|
|
const char *c, *start, **ptr;
|
|
|
|
|
|
|
|
*buffer = NULL;
|
|
|
|
for (i = count = 0, c = compat; i < len; i++, c++)
|
|
|
|
if (*c == 0)
|
|
|
|
count++;
|
|
|
|
count += 2;
|
|
|
|
ptr = malloc(sizeof(char*)*count, M_TEMP, M_WAITOK);
|
|
|
|
if (!ptr) return;
|
|
|
|
|
|
|
|
for (i = count = 0, start = c = compat; i < len; i++, c++) {
|
|
|
|
if (*c == 0) {
|
|
|
|
ptr[count++] = start;
|
|
|
|
start = c+1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (start < compat+len) {
|
|
|
|
/* last string not 0 terminated */
|
|
|
|
size_t l = c-start;
|
|
|
|
*buffer = malloc(l+1, M_TEMP, M_WAITOK);
|
|
|
|
memcpy(*buffer, start, l);
|
|
|
|
(*buffer)[l] = 0;
|
|
|
|
ptr[count++] = *buffer;
|
|
|
|
}
|
|
|
|
ptr[count] = NULL;
|
|
|
|
|
|
|
|
ia->ia_compat = ptr;
|
|
|
|
ia->ia_ncompat = count;
|
|
|
|
}
|
|
|
|
|
2018-06-17 00:22:13 +03:00
|
|
|
/*
|
2018-06-18 20:07:07 +03:00
|
|
|
* iic_compatible_match --
|
2018-06-17 00:22:13 +03:00
|
|
|
* Match a device's "compatible" property against the list
|
2018-06-18 20:07:07 +03:00
|
|
|
* of compatible strings provided by the driver.
|
2018-06-17 00:22:13 +03:00
|
|
|
*/
|
2018-06-26 07:32:35 +03:00
|
|
|
int
|
2018-06-18 20:07:07 +03:00
|
|
|
iic_compatible_match(const struct i2c_attach_args *ia,
|
2021-01-18 18:28:21 +03:00
|
|
|
const struct device_compatible_entry *compats)
|
2010-02-28 14:34:42 +03:00
|
|
|
{
|
2018-06-26 07:32:35 +03:00
|
|
|
int match_result;
|
|
|
|
|
|
|
|
match_result = device_compatible_match(ia->ia_compat, ia->ia_ncompat,
|
2021-01-18 18:28:21 +03:00
|
|
|
compats);
|
2018-06-26 07:32:35 +03:00
|
|
|
if (match_result) {
|
|
|
|
match_result =
|
|
|
|
MIN(I2C_MATCH_DIRECT_COMPATIBLE + match_result - 1,
|
|
|
|
I2C_MATCH_DIRECT_COMPATIBLE_MAX);
|
2010-02-28 14:34:42 +03:00
|
|
|
}
|
2018-06-18 20:07:07 +03:00
|
|
|
|
2018-06-26 07:32:35 +03:00
|
|
|
return match_result;
|
2018-06-17 00:22:13 +03:00
|
|
|
}
|
|
|
|
|
2021-01-18 18:28:21 +03:00
|
|
|
/*
|
|
|
|
* iic_compatible_lookup --
|
|
|
|
* Look the compatible entry that matches one of the driver's
|
|
|
|
* "compatible" strings. The first match is returned.
|
|
|
|
*/
|
|
|
|
const struct device_compatible_entry *
|
|
|
|
iic_compatible_lookup(const struct i2c_attach_args *ia,
|
|
|
|
const struct device_compatible_entry *compats)
|
|
|
|
{
|
|
|
|
return device_compatible_lookup(ia->ia_compat, ia->ia_ncompat,
|
|
|
|
compats);
|
|
|
|
}
|
|
|
|
|
2018-06-18 20:07:07 +03:00
|
|
|
/*
|
|
|
|
* iic_use_direct_match --
|
|
|
|
* Helper for direct-config of i2c. Returns true if this is
|
2022-01-24 12:42:13 +03:00
|
|
|
* a direct-config situation, along with match result.
|
2018-06-18 20:07:07 +03:00
|
|
|
* Returns false if the driver should use indirect-config
|
|
|
|
* matching logic.
|
|
|
|
*/
|
2018-06-17 00:22:13 +03:00
|
|
|
bool
|
|
|
|
iic_use_direct_match(const struct i2c_attach_args *ia, const cfdata_t cf,
|
2018-06-18 20:07:07 +03:00
|
|
|
const struct device_compatible_entry *compats,
|
|
|
|
int *match_resultp)
|
2018-06-17 00:22:13 +03:00
|
|
|
{
|
|
|
|
KASSERT(match_resultp != NULL);
|
|
|
|
|
|
|
|
if (ia->ia_name != NULL &&
|
|
|
|
strcmp(ia->ia_name, cf->cf_name) == 0) {
|
|
|
|
*match_resultp = I2C_MATCH_DIRECT_SPECIFIC;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ia->ia_ncompat > 0 && ia->ia_compat != NULL) {
|
2021-01-18 18:28:21 +03:00
|
|
|
*match_resultp = iic_compatible_match(ia, compats);
|
2019-12-05 09:28:09 +03:00
|
|
|
return true;
|
2018-06-17 00:22:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2010-02-28 14:34:42 +03:00
|
|
|
}
|
|
|
|
|
2011-10-02 20:39:45 +04:00
|
|
|
static int
|
|
|
|
iic_open(dev_t dev, int flag, int fmt, lwp_t *l)
|
|
|
|
{
|
|
|
|
struct iic_softc *sc = device_lookup_private(&iic_cd, minor(dev));
|
|
|
|
|
2015-12-10 08:33:28 +03:00
|
|
|
mutex_enter(&iic_mtx);
|
|
|
|
if (sc == NULL) {
|
|
|
|
mutex_exit(&iic_mtx);
|
2011-10-02 20:39:45 +04:00
|
|
|
return ENXIO;
|
2015-12-10 08:33:28 +03:00
|
|
|
}
|
|
|
|
iic_refcnt++;
|
|
|
|
mutex_exit(&iic_mtx);
|
2011-10-02 20:39:45 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
iic_close(dev_t dev, int flag, int fmt, lwp_t *l)
|
|
|
|
{
|
2015-12-10 08:33:28 +03:00
|
|
|
|
|
|
|
mutex_enter(&iic_mtx);
|
|
|
|
iic_refcnt--;
|
|
|
|
mutex_exit(&iic_mtx);
|
|
|
|
|
2011-10-02 20:39:45 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2011-10-02 21:39:40 +04:00
|
|
|
iic_ioctl_exec(struct iic_softc *sc, i2c_ioctl_exec_t *iie, int flag)
|
2011-10-02 20:39:45 +04:00
|
|
|
{
|
|
|
|
i2c_tag_t ic = sc->sc_tag;
|
2022-06-29 18:33:45 +03:00
|
|
|
uint8_t *buf = NULL;
|
2011-10-03 01:12:43 +04:00
|
|
|
void *cmd = NULL;
|
2011-10-02 20:39:45 +04:00
|
|
|
int error;
|
|
|
|
|
|
|
|
/* Validate parameters */
|
|
|
|
if (iie->iie_addr > I2C_MAX_ADDR)
|
|
|
|
return EINVAL;
|
|
|
|
if (iie->iie_cmdlen > I2C_EXEC_MAX_CMDLEN ||
|
|
|
|
iie->iie_buflen > I2C_EXEC_MAX_BUFLEN)
|
|
|
|
return EINVAL;
|
|
|
|
if (iie->iie_cmd != NULL && iie->iie_cmdlen == 0)
|
|
|
|
return EINVAL;
|
|
|
|
if (iie->iie_buf != NULL && iie->iie_buflen == 0)
|
|
|
|
return EINVAL;
|
2011-10-02 21:39:40 +04:00
|
|
|
if (I2C_OP_WRITE_P(iie->iie_op) && (flag & FWRITE) == 0)
|
|
|
|
return EBADF;
|
2011-10-02 20:39:45 +04:00
|
|
|
|
|
|
|
#if 0
|
|
|
|
/* Disallow userspace access to devices that have drivers attached. */
|
|
|
|
if (sc->sc_devices[iie->iie_addr] != NULL)
|
|
|
|
return EBUSY;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (iie->iie_cmd != NULL) {
|
2011-10-03 01:12:43 +04:00
|
|
|
cmd = kmem_alloc(iie->iie_cmdlen, KM_SLEEP);
|
2011-10-02 20:39:45 +04:00
|
|
|
error = copyin(iie->iie_cmd, cmd, iie->iie_cmdlen);
|
2015-04-04 18:16:54 +03:00
|
|
|
if (error)
|
|
|
|
goto out;
|
2011-10-02 20:39:45 +04:00
|
|
|
}
|
|
|
|
|
2022-06-29 18:33:45 +03:00
|
|
|
if (iie->iie_buf != NULL) {
|
|
|
|
buf = kmem_alloc(iie->iie_buflen, KM_SLEEP);
|
|
|
|
if (I2C_OP_WRITE_P(iie->iie_op)) {
|
|
|
|
error = copyin(iie->iie_buf, buf, iie->iie_buflen);
|
|
|
|
if (error)
|
|
|
|
goto out;
|
|
|
|
}
|
2015-01-22 20:56:35 +03:00
|
|
|
}
|
|
|
|
|
2011-10-02 20:39:45 +04:00
|
|
|
iic_acquire_bus(ic, 0);
|
|
|
|
error = iic_exec(ic, iie->iie_op, iie->iie_addr, cmd, iie->iie_cmdlen,
|
|
|
|
buf, iie->iie_buflen, 0);
|
|
|
|
iic_release_bus(ic, 0);
|
|
|
|
|
2011-10-04 03:53:04 +04:00
|
|
|
/*
|
|
|
|
* Some drivers return error codes on failure, and others return -1.
|
|
|
|
*/
|
|
|
|
if (error < 0)
|
|
|
|
error = EIO;
|
|
|
|
|
2015-04-04 18:16:54 +03:00
|
|
|
out:
|
2022-06-29 18:33:45 +03:00
|
|
|
if (iie->iie_buf != NULL && I2C_OP_READ_P(iie->iie_op))
|
|
|
|
error = copyout(buf, iie->iie_buf, iie->iie_buflen);
|
|
|
|
|
|
|
|
if (buf)
|
|
|
|
kmem_free(buf, iie->iie_buflen);
|
|
|
|
|
2011-10-03 01:12:43 +04:00
|
|
|
if (cmd)
|
|
|
|
kmem_free(cmd, iie->iie_cmdlen);
|
|
|
|
|
2011-10-02 20:39:45 +04:00
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
iic_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
|
|
|
|
{
|
|
|
|
struct iic_softc *sc = device_lookup_private(&iic_cd, minor(dev));
|
|
|
|
|
|
|
|
if (sc == NULL)
|
|
|
|
return ENXIO;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case I2C_IOCTL_EXEC:
|
2011-10-02 21:39:40 +04:00
|
|
|
return iic_ioctl_exec(sc, (i2c_ioctl_exec_t *)data, flag);
|
2011-10-02 20:39:45 +04:00
|
|
|
default:
|
|
|
|
return ENODEV;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-28 14:34:42 +03:00
|
|
|
|
2018-12-09 22:21:16 +03:00
|
|
|
CFATTACH_DECL3_NEW(iic, sizeof(struct iic_softc),
|
|
|
|
iic_match, iic_attach, iic_detach, NULL, iic_rescan, iic_child_detach,
|
|
|
|
DVF_DETACH_SHUTDOWN);
|
2011-10-02 15:38:48 +04:00
|
|
|
|
2022-04-01 18:49:11 +03:00
|
|
|
MODULE(MODULE_CLASS_DRIVER, iic, "i2cexec,i2c_bitbang,i2c_subr");
|
2011-10-02 15:38:48 +04:00
|
|
|
|
|
|
|
#ifdef _MODULE
|
|
|
|
#include "ioconf.c"
|
|
|
|
#endif
|
|
|
|
|
2015-12-10 08:33:28 +03:00
|
|
|
int
|
|
|
|
iic_init(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
mutex_init(&iic_mtx, MUTEX_DEFAULT, IPL_NONE);
|
|
|
|
iic_refcnt = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-10-02 15:38:48 +04:00
|
|
|
static int
|
|
|
|
iic_modcmd(modcmd_t cmd, void *opaque)
|
|
|
|
{
|
2015-12-10 08:33:28 +03:00
|
|
|
#ifdef _MODULE
|
|
|
|
int bmajor, cmajor;
|
|
|
|
#endif
|
2011-10-02 15:38:48 +04:00
|
|
|
int error;
|
|
|
|
|
|
|
|
error = 0;
|
|
|
|
switch (cmd) {
|
|
|
|
case MODULE_CMD_INIT:
|
2015-12-10 08:33:28 +03:00
|
|
|
RUN_ONCE(&iic_once, iic_init);
|
|
|
|
|
2011-10-02 15:38:48 +04:00
|
|
|
#ifdef _MODULE
|
2015-12-10 08:33:28 +03:00
|
|
|
mutex_enter(&iic_mtx);
|
|
|
|
bmajor = cmajor = -1;
|
|
|
|
error = devsw_attach("iic", NULL, &bmajor,
|
|
|
|
&iic_cdevsw, &cmajor);
|
|
|
|
if (error != 0) {
|
|
|
|
mutex_exit(&iic_mtx);
|
|
|
|
break;
|
|
|
|
}
|
2011-10-02 15:38:48 +04:00
|
|
|
error = config_init_component(cfdriver_ioconf_iic,
|
|
|
|
cfattach_ioconf_iic, cfdata_ioconf_iic);
|
2015-12-10 08:33:28 +03:00
|
|
|
if (error) {
|
2011-10-02 15:38:48 +04:00
|
|
|
aprint_error("%s: unable to init component\n",
|
|
|
|
iic_cd.cd_name);
|
2022-03-28 15:33:20 +03:00
|
|
|
devsw_detach(NULL, &iic_cdevsw);
|
2015-12-10 08:33:28 +03:00
|
|
|
}
|
|
|
|
mutex_exit(&iic_mtx);
|
2011-10-02 15:38:48 +04:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case MODULE_CMD_FINI:
|
2015-12-10 08:33:28 +03:00
|
|
|
mutex_enter(&iic_mtx);
|
|
|
|
if (iic_refcnt != 0) {
|
|
|
|
mutex_exit(&iic_mtx);
|
|
|
|
return EBUSY;
|
|
|
|
}
|
2011-10-02 15:38:48 +04:00
|
|
|
#ifdef _MODULE
|
2015-12-10 08:33:28 +03:00
|
|
|
error = config_fini_component(cfdriver_ioconf_iic,
|
2011-10-02 15:38:48 +04:00
|
|
|
cfattach_ioconf_iic, cfdata_ioconf_iic);
|
2015-12-10 08:33:28 +03:00
|
|
|
if (error != 0) {
|
|
|
|
mutex_exit(&iic_mtx);
|
|
|
|
break;
|
|
|
|
}
|
2022-03-28 15:33:20 +03:00
|
|
|
devsw_detach(NULL, &iic_cdevsw);
|
2011-10-02 15:38:48 +04:00
|
|
|
#endif
|
2015-12-10 08:33:28 +03:00
|
|
|
mutex_exit(&iic_mtx);
|
2011-10-02 15:38:48 +04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error = ENOTTY;
|
|
|
|
}
|
|
|
|
return error;
|
|
|
|
}
|