Merge branch 'i2c/for-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: "I2C has mostly driver updates this time. The few noteworthy changes are: the core has now support for analog and digital filters with at91 being the first user, a core addition to replace the NULL returning i2c_new_probed_device() with an ERR_PTR variant, and the pxa driver has finally being moved to use the generic I2C slave interface. We have quite a significant number of reviews per patch this time, so thank you to all involved!" * 'i2c/for-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (37 commits) video: fbdev: matrox: convert to i2c_new_scanned_device i2c: icy: convert to i2c_new_scanned_device i2c: replace i2c_new_probed_device with an ERR_PTR variant i2c: Fix Kconfig indentation i2c: smbus: Don't filter out duplicate alerts i2c: i801: Correct Intel Jasper Lake SOC naming i2c: i2c-stm32f7: fix 10-bits check in slave free id search loop i2c: iproc: Add i2c repeated start capability i2c: remove helpers for ref-counting clients i2c: tegra: Use dma_request_chan() directly for channel request i2c: sh_mobile: Use dma_request_chan() directly for channel request i2c: qup: Use dma_request_chan() directly for channel request i2c: at91: Use dma_request_chan() directly for channel request i2c: rcar: Remove superfluous call to clk_get_rate() i2c: pxa: remove unused i2c-slave APIs i2c: pxa: migrate to new i2c_slave APIs i2c: cros-ec-tunnel: Make the device acpi compatible i2c: stm32f7: report dma error during probe i2c: icy: no need to populate address for scanned device i2c: xiic: Fix kerneldoc warnings ...
This commit is contained in:
commit
3265568db8
|
@ -0,0 +1,53 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright 2019 BayLibre, SAS
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/i2c/amlogic,meson6-i2c.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Amlogic Meson I2C Controller
|
||||
|
||||
maintainers:
|
||||
- Neil Armstrong <narmstrong@baylibre.com>
|
||||
- Beniamino Galvani <b.galvani@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- amlogic,meson6-i2c # Meson6, Meson8 and compatible SoCs
|
||||
- amlogic,meson-gxbb-i2c # GXBB and compatible SoCs
|
||||
- amlogic,meson-axg-i2c # AXG and compatible SoCs
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c@c8100500 {
|
||||
compatible = "amlogic,meson6-i2c";
|
||||
reg = <0xc8100500 0x20>;
|
||||
interrupts = <92>;
|
||||
clocks = <&clk81>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
eeprom@52 {
|
||||
compatible = "atmel,24c32";
|
||||
reg = <0x52>;
|
||||
};
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
Device tree configuration for the I2C busses on the AST24XX and AST25XX SoCs.
|
||||
Device tree configuration for the I2C busses on the AST24XX, AST25XX, and AST26XX SoCs.
|
||||
|
||||
Required Properties:
|
||||
- #address-cells : should be 1
|
||||
|
@ -6,6 +6,7 @@ Required Properties:
|
|||
- reg : address offset and range of bus
|
||||
- compatible : should be "aspeed,ast2400-i2c-bus"
|
||||
or "aspeed,ast2500-i2c-bus"
|
||||
or "aspeed,ast2600-i2c-bus"
|
||||
- clocks : root clock of bus, should reference the APB
|
||||
clock in the second cell
|
||||
- resets : phandle to reset controller with the reset number in
|
||||
|
|
|
@ -3,7 +3,8 @@ I2C for Atmel platforms
|
|||
Required properties :
|
||||
- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
|
||||
"atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c",
|
||||
"atmel,at91sam9x5-i2c", "atmel,sama5d4-i2c" or "atmel,sama5d2-i2c"
|
||||
"atmel,at91sam9x5-i2c", "atmel,sama5d4-i2c", "atmel,sama5d2-i2c" or
|
||||
"microchip,sam9x60-i2c"
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: interrupt number to the cpu.
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
Amlogic Meson I2C controller
|
||||
|
||||
Required properties:
|
||||
- compatible: must be:
|
||||
"amlogic,meson6-i2c" for Meson8 and compatible SoCs
|
||||
"amlogic,meson-gxbb-i2c" for GXBB and compatible SoCs
|
||||
"amlogic,meson-axg-i2c"for AXG and compatible SoCs
|
||||
|
||||
- reg: physical address and length of the device registers
|
||||
- interrupts: a single interrupt specifier
|
||||
- clocks: clock for the device
|
||||
- #address-cells: should be <1>
|
||||
- #size-cells: should be <0>
|
||||
|
||||
For details regarding the following core I2C bindings see also i2c.txt.
|
||||
|
||||
Optional properties:
|
||||
- clock-frequency: the desired I2C bus clock frequency in Hz; in
|
||||
absence of this property the default value is used (100 kHz).
|
||||
|
||||
Examples:
|
||||
|
||||
i2c@c8100500 {
|
||||
compatible = "amlogic,meson6-i2c";
|
||||
reg = <0xc8100500 0x20>;
|
||||
interrupts = <0 92 1>;
|
||||
clocks = <&clk81>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
|
@ -55,6 +55,24 @@ wants to support one of the below features, it should adapt the bindings below.
|
|||
Number of nanoseconds the SDA signal takes to fall; t(f) in the I2C
|
||||
specification.
|
||||
|
||||
- i2c-analog-filter
|
||||
Enable analog filter for i2c lines.
|
||||
|
||||
- i2c-digital-filter
|
||||
Enable digital filter for i2c lines.
|
||||
|
||||
- i2c-digital-filter-width-ns
|
||||
Width of spikes which can be filtered by digital filter
|
||||
(i2c-digital-filter). This width is specified in nanoseconds.
|
||||
|
||||
- i2c-analog-filter-cutoff-frequency
|
||||
Frequency that the analog filter (i2c-analog-filter) uses to distinguish
|
||||
which signal to filter. Signal with higher frequency than specified will
|
||||
be filtered out. Only lower frequency will pass (this is applicable to
|
||||
a low-pass analog filter). Typical value should be above the normal
|
||||
i2c bus clock frequency (clock-frequency).
|
||||
Specified in Hz.
|
||||
|
||||
- interrupts
|
||||
interrupts used by the device.
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ Required properties:
|
|||
"renesas,i2c-r8a7745" if the device is a part of a R8A7745 SoC.
|
||||
"renesas,i2c-r8a77470" if the device is a part of a R8A77470 SoC.
|
||||
"renesas,i2c-r8a774a1" if the device is a part of a R8A774A1 SoC.
|
||||
"renesas,i2c-r8a774b1" if the device is a part of a R8A774B1 SoC.
|
||||
"renesas,i2c-r8a774c0" if the device is a part of a R8A774C0 SoC.
|
||||
"renesas,i2c-r8a7778" if the device is a part of a R8A7778 SoC.
|
||||
"renesas,i2c-r8a7779" if the device is a part of a R8A7779 SoC.
|
||||
|
|
|
@ -8,6 +8,7 @@ Required properties:
|
|||
- "renesas,iic-r8a7744" (RZ/G1N)
|
||||
- "renesas,iic-r8a7745" (RZ/G1E)
|
||||
- "renesas,iic-r8a774a1" (RZ/G2M)
|
||||
- "renesas,iic-r8a774b1" (RZ/G2N)
|
||||
- "renesas,iic-r8a774c0" (RZ/G2E)
|
||||
- "renesas,iic-r8a7790" (R-Car H2)
|
||||
- "renesas,iic-r8a7791" (R-Car M2-W)
|
||||
|
|
|
@ -42,6 +42,7 @@ Supported adapters:
|
|||
* Intel Comet Lake (PCH)
|
||||
* Intel Elkhart Lake (PCH)
|
||||
* Intel Tiger Lake (PCH)
|
||||
* Intel Jasper Lake (SOC)
|
||||
|
||||
Datasheets: Publicly available at the Intel website
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ present or not (for example for an optional feature which is not present
|
|||
on cheap variants of a board but you have no way to tell them apart), or
|
||||
it may have different addresses from one board to the next (manufacturer
|
||||
changing its design without notice). In this case, you can call
|
||||
i2c_new_probed_device() instead of i2c_new_device().
|
||||
i2c_new_scanned_device() instead of i2c_new_device().
|
||||
|
||||
Example (from the nxp OHCI driver)::
|
||||
|
||||
|
@ -139,8 +139,8 @@ Example (from the nxp OHCI driver)::
|
|||
i2c_adap = i2c_get_adapter(2);
|
||||
memset(&i2c_info, 0, sizeof(struct i2c_board_info));
|
||||
strscpy(i2c_info.type, "isp1301_nxp", sizeof(i2c_info.type));
|
||||
isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
|
||||
normal_i2c, NULL);
|
||||
isp1301_i2c_client = i2c_new_scanned_device(i2c_adap, &i2c_info,
|
||||
normal_i2c, NULL);
|
||||
i2c_put_adapter(i2c_adap);
|
||||
(...)
|
||||
}
|
||||
|
@ -153,14 +153,14 @@ simply gives up.
|
|||
The driver which instantiated the I2C device is responsible for destroying
|
||||
it on cleanup. This is done by calling i2c_unregister_device() on the
|
||||
pointer that was earlier returned by i2c_new_device() or
|
||||
i2c_new_probed_device().
|
||||
i2c_new_scanned_device().
|
||||
|
||||
|
||||
Method 3: Probe an I2C bus for certain devices
|
||||
----------------------------------------------
|
||||
|
||||
Sometimes you do not have enough information about an I2C device, not even
|
||||
to call i2c_new_probed_device(). The typical case is hardware monitoring
|
||||
to call i2c_new_scanned_device(). The typical case is hardware monitoring
|
||||
chips on PC mainboards. There are several dozen models, which can live
|
||||
at 25 different addresses. Given the huge number of mainboards out there,
|
||||
it is next to impossible to build an exhaustive list of the hardware
|
||||
|
|
|
@ -185,14 +185,14 @@ Sometimes you know that a device is connected to a given I2C bus, but you
|
|||
don't know the exact address it uses. This happens on TV adapters for
|
||||
example, where the same driver supports dozens of slightly different
|
||||
models, and I2C device addresses change from one model to the next. In
|
||||
that case, you can use the i2c_new_probed_device() variant, which is
|
||||
that case, you can use the i2c_new_scanned_device() variant, which is
|
||||
similar to i2c_new_device(), except that it takes an additional list of
|
||||
possible I2C addresses to probe. A device is created for the first
|
||||
responsive address in the list. If you expect more than one device to be
|
||||
present in the address range, simply call i2c_new_probed_device() that
|
||||
present in the address range, simply call i2c_new_scanned_device() that
|
||||
many times.
|
||||
|
||||
The call to i2c_new_device() or i2c_new_probed_device() typically happens
|
||||
The call to i2c_new_device() or i2c_new_scanned_device() typically happens
|
||||
in the I2C bus driver. You may want to save the returned i2c_client
|
||||
reference for later use.
|
||||
|
||||
|
@ -237,7 +237,7 @@ Device Deletion
|
|||
---------------
|
||||
|
||||
Each I2C device which has been created using i2c_new_device() or
|
||||
i2c_new_probed_device() can be unregistered by calling
|
||||
i2c_new_scanned_device() can be unregistered by calling
|
||||
i2c_unregister_device(). If you don't call it explicitly, it will be
|
||||
called automatically before the underlying I2C bus itself is removed, as a
|
||||
device can't survive its parent in the device driver model.
|
||||
|
|
|
@ -145,6 +145,7 @@ config I2C_I801
|
|||
Comet Lake (PCH)
|
||||
Elkhart Lake (PCH)
|
||||
Tiger Lake (PCH)
|
||||
Jasper Lake (SOC)
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-i801.
|
||||
|
@ -292,7 +293,7 @@ config I2C_VIA
|
|||
select I2C_ALGOBIT
|
||||
help
|
||||
If you say yes to this option, support will be included for the VIA
|
||||
82C586B I2C interface
|
||||
82C586B I2C interface
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-via.
|
||||
|
@ -677,11 +678,11 @@ config I2C_IMX_LPI2C
|
|||
tristate "IMX Low Power I2C interface"
|
||||
depends on ARCH_MXC || COMPILE_TEST
|
||||
help
|
||||
Say Y here if you want to use the Low Power IIC bus controller
|
||||
on the Freescale i.MX processors.
|
||||
Say Y here if you want to use the Low Power IIC bus controller
|
||||
on the Freescale i.MX processors.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-imx-lpi2c.
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-imx-lpi2c.
|
||||
|
||||
config I2C_IOP3XX
|
||||
tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
|
||||
|
@ -874,6 +875,7 @@ config I2C_PXA_PCI
|
|||
config I2C_PXA_SLAVE
|
||||
bool "Intel PXA2XX I2C Slave comms support"
|
||||
depends on I2C_PXA && !X86_32
|
||||
select I2C_SLAVE
|
||||
help
|
||||
Support I2C slave mode communications on the PXA I2C bus. This
|
||||
is necessary for systems where the PXA may be a target on the
|
||||
|
@ -1182,9 +1184,9 @@ config I2C_DIOLAN_U2C
|
|||
will be called i2c-diolan-u2c.
|
||||
|
||||
config I2C_DLN2
|
||||
tristate "Diolan DLN-2 USB I2C adapter"
|
||||
depends on MFD_DLN2
|
||||
help
|
||||
tristate "Diolan DLN-2 USB I2C adapter"
|
||||
depends on MFD_DLN2
|
||||
help
|
||||
If you say yes to this option, support will be included for Diolan
|
||||
DLN2, a USB to I2C interface.
|
||||
|
||||
|
@ -1283,9 +1285,9 @@ config I2C_VIPERBOARD
|
|||
help
|
||||
Say yes here to access the I2C part of the Nano River
|
||||
Technologies Viperboard as I2C master.
|
||||
See viperboard API specification and Nano
|
||||
River Tech's viperboard.h for detailed meaning
|
||||
of the module parameters.
|
||||
See viperboard API specification and Nano
|
||||
River Tech's viperboard.h for detailed meaning
|
||||
of the module parameters.
|
||||
|
||||
comment "Other I2C/SMBus bus drivers"
|
||||
|
||||
|
|
|
@ -952,6 +952,10 @@ static const struct of_device_id aspeed_i2c_bus_of_table[] = {
|
|||
.compatible = "aspeed,ast2500-i2c-bus",
|
||||
.data = aspeed_i2c_25xx_get_clk_reg_val,
|
||||
},
|
||||
{
|
||||
.compatible = "aspeed,ast2600-i2c-bus",
|
||||
.data = aspeed_i2c_25xx_get_clk_reg_val,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, aspeed_i2c_bus_of_table);
|
||||
|
|
|
@ -68,6 +68,9 @@ static struct at91_twi_pdata at91rm9200_config = {
|
|||
.has_unre_flag = true,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata at91sam9261_config = {
|
||||
|
@ -76,6 +79,9 @@ static struct at91_twi_pdata at91sam9261_config = {
|
|||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata at91sam9260_config = {
|
||||
|
@ -84,6 +90,9 @@ static struct at91_twi_pdata at91sam9260_config = {
|
|||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata at91sam9g20_config = {
|
||||
|
@ -92,6 +101,9 @@ static struct at91_twi_pdata at91sam9g20_config = {
|
|||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata at91sam9g10_config = {
|
||||
|
@ -100,6 +112,9 @@ static struct at91_twi_pdata at91sam9g10_config = {
|
|||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static const struct platform_device_id at91_twi_devtypes[] = {
|
||||
|
@ -130,6 +145,9 @@ static struct at91_twi_pdata at91sam9x5_config = {
|
|||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata sama5d4_config = {
|
||||
|
@ -138,6 +156,9 @@ static struct at91_twi_pdata sama5d4_config = {
|
|||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = true,
|
||||
.has_dig_filtr = true,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata sama5d2_config = {
|
||||
|
@ -146,6 +167,20 @@ static struct at91_twi_pdata sama5d2_config = {
|
|||
.has_unre_flag = true,
|
||||
.has_alt_cmd = true,
|
||||
.has_hold_field = true,
|
||||
.has_dig_filtr = true,
|
||||
.has_adv_dig_filtr = true,
|
||||
.has_ana_filtr = true,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata sam9x60_config = {
|
||||
.clk_max_div = 7,
|
||||
.clk_offset = 4,
|
||||
.has_unre_flag = true,
|
||||
.has_alt_cmd = true,
|
||||
.has_hold_field = true,
|
||||
.has_dig_filtr = true,
|
||||
.has_adv_dig_filtr = true,
|
||||
.has_ana_filtr = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id atmel_twi_dt_ids[] = {
|
||||
|
@ -173,6 +208,9 @@ static const struct of_device_id atmel_twi_dt_ids[] = {
|
|||
}, {
|
||||
.compatible = "atmel,sama5d2-i2c",
|
||||
.data = &sama5d2_config,
|
||||
}, {
|
||||
.compatible = "microchip,sam9x60-i2c",
|
||||
.data = &sam9x60_config,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
|
|
|
@ -31,12 +31,32 @@
|
|||
|
||||
void at91_init_twi_bus_master(struct at91_twi_dev *dev)
|
||||
{
|
||||
struct at91_twi_pdata *pdata = dev->pdata;
|
||||
u32 filtr = 0;
|
||||
|
||||
/* FIFO should be enabled immediately after the software reset */
|
||||
if (dev->fifo_size)
|
||||
at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_FIFOEN);
|
||||
at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSEN);
|
||||
at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVDIS);
|
||||
at91_twi_write(dev, AT91_TWI_CWGR, dev->twi_cwgr_reg);
|
||||
|
||||
/* enable digital filter */
|
||||
if (pdata->has_dig_filtr && dev->enable_dig_filt)
|
||||
filtr |= AT91_TWI_FILTR_FILT;
|
||||
|
||||
/* enable advanced digital filter */
|
||||
if (pdata->has_adv_dig_filtr && dev->enable_dig_filt)
|
||||
filtr |= AT91_TWI_FILTR_FILT |
|
||||
(AT91_TWI_FILTR_THRES(dev->filter_width) &
|
||||
AT91_TWI_FILTR_THRES_MASK);
|
||||
|
||||
/* enable analog filter */
|
||||
if (pdata->has_ana_filtr && dev->enable_ana_filt)
|
||||
filtr |= AT91_TWI_FILTR_PADFEN;
|
||||
|
||||
if (filtr)
|
||||
at91_twi_write(dev, AT91_TWI_FILTR, filtr);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -45,7 +65,7 @@ void at91_init_twi_bus_master(struct at91_twi_dev *dev)
|
|||
*/
|
||||
static void at91_calc_twi_clock(struct at91_twi_dev *dev)
|
||||
{
|
||||
int ckdiv, cdiv, div, hold = 0;
|
||||
int ckdiv, cdiv, div, hold = 0, filter_width = 0;
|
||||
struct at91_twi_pdata *pdata = dev->pdata;
|
||||
int offset = pdata->clk_offset;
|
||||
int max_ckdiv = pdata->clk_max_div;
|
||||
|
@ -84,11 +104,29 @@ static void at91_calc_twi_clock(struct at91_twi_dev *dev)
|
|||
}
|
||||
}
|
||||
|
||||
if (pdata->has_adv_dig_filtr) {
|
||||
/*
|
||||
* filter width = 0 to AT91_TWI_FILTR_THRES_MAX
|
||||
* peripheral clocks
|
||||
*/
|
||||
filter_width = DIV_ROUND_UP(t->digital_filter_width_ns
|
||||
* (clk_get_rate(dev->clk) / 1000), 1000000);
|
||||
if (filter_width > AT91_TWI_FILTR_THRES_MAX) {
|
||||
dev_warn(dev->dev,
|
||||
"Filter threshold set to its maximum value (%d instead of %d)\n",
|
||||
AT91_TWI_FILTR_THRES_MAX, filter_width);
|
||||
filter_width = AT91_TWI_FILTR_THRES_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv
|
||||
| AT91_TWI_CWGR_HOLD(hold);
|
||||
|
||||
dev_dbg(dev->dev, "cdiv %d ckdiv %d hold %d (%d ns)\n",
|
||||
cdiv, ckdiv, hold, t->sda_hold_ns);
|
||||
dev->filter_width = filter_width;
|
||||
|
||||
dev_dbg(dev->dev, "cdiv %d ckdiv %d hold %d (%d ns), filter_width %d (%d ns)\n",
|
||||
cdiv, ckdiv, hold, t->sda_hold_ns, filter_width,
|
||||
t->digital_filter_width_ns);
|
||||
}
|
||||
|
||||
static void at91_twi_dma_cleanup(struct at91_twi_dev *dev)
|
||||
|
@ -720,14 +758,14 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr)
|
|||
slave_config.dst_maxburst = 1;
|
||||
slave_config.device_fc = false;
|
||||
|
||||
dma->chan_tx = dma_request_slave_channel_reason(dev->dev, "tx");
|
||||
dma->chan_tx = dma_request_chan(dev->dev, "tx");
|
||||
if (IS_ERR(dma->chan_tx)) {
|
||||
ret = PTR_ERR(dma->chan_tx);
|
||||
dma->chan_tx = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
dma->chan_rx = dma_request_slave_channel_reason(dev->dev, "rx");
|
||||
dma->chan_rx = dma_request_chan(dev->dev, "rx");
|
||||
if (IS_ERR(dma->chan_rx)) {
|
||||
ret = PTR_ERR(dma->chan_rx);
|
||||
dma->chan_rx = NULL;
|
||||
|
@ -793,6 +831,11 @@ int at91_twi_probe_master(struct platform_device *pdev,
|
|||
dev_info(dev->dev, "Using FIFO (%u data)\n", dev->fifo_size);
|
||||
}
|
||||
|
||||
dev->enable_dig_filt = of_property_read_bool(pdev->dev.of_node,
|
||||
"i2c-digital-filter");
|
||||
|
||||
dev->enable_ana_filt = of_property_read_bool(pdev->dev.of_node,
|
||||
"i2c-analog-filter");
|
||||
at91_calc_twi_clock(dev);
|
||||
|
||||
dev->adapter.algo = &at91_twi_algorithm;
|
||||
|
|
|
@ -84,6 +84,13 @@
|
|||
#define AT91_TWI_ACR_DATAL(len) ((len) & 0xff)
|
||||
#define AT91_TWI_ACR_DIR BIT(8)
|
||||
|
||||
#define AT91_TWI_FILTR 0x0044
|
||||
#define AT91_TWI_FILTR_FILT BIT(0)
|
||||
#define AT91_TWI_FILTR_PADFEN BIT(1)
|
||||
#define AT91_TWI_FILTR_THRES(v) ((v) << 8)
|
||||
#define AT91_TWI_FILTR_THRES_MAX 7
|
||||
#define AT91_TWI_FILTR_THRES_MASK GENMASK(10, 8)
|
||||
|
||||
#define AT91_TWI_FMR 0x0050 /* FIFO Mode Register */
|
||||
#define AT91_TWI_FMR_TXRDYM(mode) (((mode) & 0x3) << 0)
|
||||
#define AT91_TWI_FMR_TXRDYM_MASK (0x3 << 0)
|
||||
|
@ -108,6 +115,9 @@ struct at91_twi_pdata {
|
|||
bool has_unre_flag;
|
||||
bool has_alt_cmd;
|
||||
bool has_hold_field;
|
||||
bool has_dig_filtr;
|
||||
bool has_adv_dig_filtr;
|
||||
bool has_ana_filtr;
|
||||
struct at_dma_slave dma_slave;
|
||||
};
|
||||
|
||||
|
@ -145,6 +155,9 @@ struct at91_twi_dev {
|
|||
unsigned smr;
|
||||
struct i2c_client *slave;
|
||||
#endif
|
||||
bool enable_dig_filt;
|
||||
bool enable_ana_filt;
|
||||
u32 filter_width;
|
||||
};
|
||||
|
||||
unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg);
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
#define M_CMD_PROTOCOL_MASK 0xf
|
||||
#define M_CMD_PROTOCOL_BLK_WR 0x7
|
||||
#define M_CMD_PROTOCOL_BLK_RD 0x8
|
||||
#define M_CMD_PROTOCOL_PROCESS 0xa
|
||||
#define M_CMD_PEC_SHIFT 8
|
||||
#define M_CMD_RD_CNT_SHIFT 0
|
||||
#define M_CMD_RD_CNT_MASK 0xff
|
||||
|
@ -675,13 +676,20 @@ static int bcm_iproc_i2c_xfer_wait(struct bcm_iproc_i2c_dev *iproc_i2c,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
|
||||
struct i2c_msg *msg)
|
||||
/*
|
||||
* If 'process_call' is true, then this is a multi-msg transfer that requires
|
||||
* a repeated start between the messages.
|
||||
* More specifically, it must be a write (reg) followed by a read (data).
|
||||
* The i2c quirks are set to enforce this rule.
|
||||
*/
|
||||
static int bcm_iproc_i2c_xfer_internal(struct bcm_iproc_i2c_dev *iproc_i2c,
|
||||
struct i2c_msg *msgs, bool process_call)
|
||||
{
|
||||
int i;
|
||||
u8 addr;
|
||||
u32 val, tmp, val_intr_en;
|
||||
unsigned int tx_bytes;
|
||||
struct i2c_msg *msg = &msgs[0];
|
||||
|
||||
/* check if bus is busy */
|
||||
if (!!(iproc_i2c_rd_reg(iproc_i2c,
|
||||
|
@ -707,14 +715,29 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
|
|||
val = msg->buf[i];
|
||||
|
||||
/* mark the last byte */
|
||||
if (i == msg->len - 1)
|
||||
val |= BIT(M_TX_WR_STATUS_SHIFT);
|
||||
if (!process_call && (i == msg->len - 1))
|
||||
val |= 1 << M_TX_WR_STATUS_SHIFT;
|
||||
|
||||
iproc_i2c_wr_reg(iproc_i2c, M_TX_OFFSET, val);
|
||||
}
|
||||
iproc_i2c->tx_bytes = tx_bytes;
|
||||
}
|
||||
|
||||
/* Process the read message if this is process call */
|
||||
if (process_call) {
|
||||
msg++;
|
||||
iproc_i2c->msg = msg; /* point to second msg */
|
||||
|
||||
/*
|
||||
* The last byte to be sent out should be a slave
|
||||
* address with read operation
|
||||
*/
|
||||
addr = i2c_8bit_addr_from_msg(msg);
|
||||
/* mark it the last byte out */
|
||||
val = addr | (1 << M_TX_WR_STATUS_SHIFT);
|
||||
iproc_i2c_wr_reg(iproc_i2c, M_TX_OFFSET, val);
|
||||
}
|
||||
|
||||
/* mark as incomplete before starting the transaction */
|
||||
if (iproc_i2c->irq)
|
||||
reinit_completion(&iproc_i2c->done);
|
||||
|
@ -733,7 +756,7 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
|
|||
* underrun interrupt, which will be triggerred when the TX FIFO is
|
||||
* empty. When that happens we can then pump more data into the FIFO
|
||||
*/
|
||||
if (!(msg->flags & I2C_M_RD) &&
|
||||
if (!process_call && !(msg->flags & I2C_M_RD) &&
|
||||
msg->len > iproc_i2c->tx_bytes)
|
||||
val_intr_en |= BIT(IE_M_TX_UNDERRUN_SHIFT);
|
||||
|
||||
|
@ -743,6 +766,8 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
|
|||
*/
|
||||
val = BIT(M_CMD_START_BUSY_SHIFT);
|
||||
if (msg->flags & I2C_M_RD) {
|
||||
u32 protocol;
|
||||
|
||||
iproc_i2c->rx_bytes = 0;
|
||||
if (msg->len > M_RX_FIFO_MAX_THLD_VALUE)
|
||||
iproc_i2c->thld_bytes = M_RX_FIFO_THLD_VALUE;
|
||||
|
@ -758,7 +783,10 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
|
|||
/* enable the RX threshold interrupt */
|
||||
val_intr_en |= BIT(IE_M_RX_THLD_SHIFT);
|
||||
|
||||
val |= (M_CMD_PROTOCOL_BLK_RD << M_CMD_PROTOCOL_SHIFT) |
|
||||
protocol = process_call ?
|
||||
M_CMD_PROTOCOL_PROCESS : M_CMD_PROTOCOL_BLK_RD;
|
||||
|
||||
val |= (protocol << M_CMD_PROTOCOL_SHIFT) |
|
||||
(msg->len << M_CMD_RD_CNT_SHIFT);
|
||||
} else {
|
||||
val |= (M_CMD_PROTOCOL_BLK_WR << M_CMD_PROTOCOL_SHIFT);
|
||||
|
@ -774,17 +802,24 @@ static int bcm_iproc_i2c_xfer(struct i2c_adapter *adapter,
|
|||
struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(adapter);
|
||||
int ret, i;
|
||||
bool process_call = false;
|
||||
int ret;
|
||||
|
||||
/* go through all messages */
|
||||
for (i = 0; i < num; i++) {
|
||||
ret = bcm_iproc_i2c_xfer_single_msg(iproc_i2c, &msgs[i]);
|
||||
if (ret) {
|
||||
dev_dbg(iproc_i2c->device, "xfer failed\n");
|
||||
return ret;
|
||||
if (num == 2) {
|
||||
/* Repeated start, use process call */
|
||||
process_call = true;
|
||||
if (msgs[1].flags & I2C_M_NOSTART) {
|
||||
dev_err(iproc_i2c->device, "Invalid repeated start\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
ret = bcm_iproc_i2c_xfer_internal(iproc_i2c, msgs, process_call);
|
||||
if (ret) {
|
||||
dev_dbg(iproc_i2c->device, "xfer failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
|
@ -809,6 +844,8 @@ static struct i2c_algorithm bcm_iproc_algo = {
|
|||
};
|
||||
|
||||
static const struct i2c_adapter_quirks bcm_iproc_i2c_quirks = {
|
||||
.flags = I2C_AQ_COMB_WRITE_THEN_READ,
|
||||
.max_comb_1st_msg_len = M_TX_RX_FIFO_SIZE,
|
||||
.max_read_len = M_RX_MAX_READ_LEN,
|
||||
};
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
//
|
||||
// Copyright (C) 2013 Google, Inc.
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
|
@ -240,7 +241,6 @@ static const struct i2c_algorithm ec_i2c_algorithm = {
|
|||
|
||||
static int ec_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ec_i2c_device *bus = NULL;
|
||||
|
@ -256,7 +256,7 @@ static int ec_i2c_probe(struct platform_device *pdev)
|
|||
if (bus == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
err = of_property_read_u32(np, "google,remote-bus", &remote_bus);
|
||||
err = device_property_read_u32(dev, "google,remote-bus", &remote_bus);
|
||||
if (err) {
|
||||
dev_err(dev, "Couldn't read remote-bus property\n");
|
||||
return err;
|
||||
|
@ -271,7 +271,7 @@ static int ec_i2c_probe(struct platform_device *pdev)
|
|||
bus->adap.algo = &ec_i2c_algorithm;
|
||||
bus->adap.algo_data = bus;
|
||||
bus->adap.dev.parent = &pdev->dev;
|
||||
bus->adap.dev.of_node = np;
|
||||
bus->adap.dev.of_node = pdev->dev.of_node;
|
||||
bus->adap.retries = I2C_MAX_RETRIES;
|
||||
|
||||
err = i2c_add_adapter(&bus->adap);
|
||||
|
@ -291,19 +291,24 @@ static int ec_i2c_remove(struct platform_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id cros_ec_i2c_of_match[] = {
|
||||
{ .compatible = "google,cros-ec-i2c-tunnel" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cros_ec_i2c_of_match);
|
||||
#endif
|
||||
|
||||
static const struct acpi_device_id cros_ec_i2c_tunnel_acpi_id[] = {
|
||||
{ "GOOG001A", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, cros_ec_i2c_tunnel_acpi_id);
|
||||
|
||||
static struct platform_driver ec_i2c_tunnel_driver = {
|
||||
.probe = ec_i2c_probe,
|
||||
.remove = ec_i2c_remove,
|
||||
.driver = {
|
||||
.name = "cros-ec-i2c-tunnel",
|
||||
.acpi_match_table = ACPI_PTR(cros_ec_i2c_tunnel_acpi_id),
|
||||
.of_match_table = of_match_ptr(cros_ec_i2c_of_match),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -64,8 +64,10 @@
|
|||
* Cedar Fork (PCH) 0x18df 32 hard yes yes yes
|
||||
* Ice Lake-LP (PCH) 0x34a3 32 hard yes yes yes
|
||||
* Comet Lake (PCH) 0x02a3 32 hard yes yes yes
|
||||
* Comet Lake-H (PCH) 0x06a3 32 hard yes yes yes
|
||||
* Elkhart Lake (PCH) 0x4b23 32 hard yes yes yes
|
||||
* Tiger Lake-LP (PCH) 0xa0a3 32 hard yes yes yes
|
||||
* Jasper Lake (SOC) 0x4da3 32 hard yes yes yes
|
||||
*
|
||||
* Features supported by this driver:
|
||||
* Software PEC no
|
||||
|
@ -205,6 +207,7 @@
|
|||
|
||||
/* Older devices have their ID defined in <linux/pci_ids.h> */
|
||||
#define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS 0x02a3
|
||||
#define PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS 0x06a3
|
||||
#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12
|
||||
#define PCI_DEVICE_ID_INTEL_CDF_SMBUS 0x18df
|
||||
#define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df
|
||||
|
@ -223,6 +226,7 @@
|
|||
#define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS 0x34a3
|
||||
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
|
||||
#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23
|
||||
#define PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS 0x4da3
|
||||
#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4
|
||||
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
|
||||
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS 0x8ca2
|
||||
|
@ -1069,8 +1073,10 @@ static const struct pci_device_id i801_ids[] = {
|
|||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS) },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
|
@ -1750,8 +1756,10 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
case PCI_DEVICE_ID_INTEL_CDF_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS:
|
||||
priv->features |= FEATURE_BLOCK_PROC;
|
||||
priv->features |= FEATURE_I2C_BLOCK_READ;
|
||||
priv->features |= FEATURE_IRQ;
|
||||
|
|
|
@ -122,7 +122,6 @@ static int icy_probe(struct zorro_dev *z,
|
|||
struct fwnode_handle *new_fwnode;
|
||||
struct i2c_board_info ltc2990_info = {
|
||||
.type = "ltc2990",
|
||||
.addr = 0x4c,
|
||||
};
|
||||
|
||||
i2c = devm_kzalloc(&z->dev, sizeof(*i2c), GFP_KERNEL);
|
||||
|
@ -188,10 +187,10 @@ static int icy_probe(struct zorro_dev *z,
|
|||
ltc2990_info.fwnode = new_fwnode;
|
||||
|
||||
i2c->ltc2990_client =
|
||||
i2c_new_probed_device(&i2c->adapter,
|
||||
<c2990_info,
|
||||
icy_ltc2990_addresses,
|
||||
NULL);
|
||||
i2c_new_scanned_device(&i2c->adapter,
|
||||
<c2990_info,
|
||||
icy_ltc2990_addresses,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c-pxa.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -180,7 +179,7 @@ struct pxa_i2c {
|
|||
struct i2c_adapter adap;
|
||||
struct clk *clk;
|
||||
#ifdef CONFIG_I2C_PXA_SLAVE
|
||||
struct i2c_slave_client *slave;
|
||||
struct i2c_client *slave;
|
||||
#endif
|
||||
|
||||
unsigned int irqlogidx;
|
||||
|
@ -544,22 +543,23 @@ static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr)
|
|||
if (isr & ISR_BED) {
|
||||
/* what should we do here? */
|
||||
} else {
|
||||
int ret = 0;
|
||||
u8 byte = 0;
|
||||
|
||||
if (i2c->slave != NULL)
|
||||
ret = i2c->slave->read(i2c->slave->data);
|
||||
i2c_slave_event(i2c->slave, I2C_SLAVE_READ_PROCESSED,
|
||||
&byte);
|
||||
|
||||
writel(ret, _IDBR(i2c));
|
||||
writel(byte, _IDBR(i2c));
|
||||
writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c)); /* allow next byte */
|
||||
}
|
||||
}
|
||||
|
||||
static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr)
|
||||
{
|
||||
unsigned int byte = readl(_IDBR(i2c));
|
||||
u8 byte = readl(_IDBR(i2c));
|
||||
|
||||
if (i2c->slave != NULL)
|
||||
i2c->slave->write(i2c->slave->data, byte);
|
||||
i2c_slave_event(i2c->slave, I2C_SLAVE_WRITE_RECEIVED, &byte);
|
||||
|
||||
writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));
|
||||
}
|
||||
|
@ -572,9 +572,18 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
|
|||
dev_dbg(&i2c->adap.dev, "SAD, mode is slave-%cx\n",
|
||||
(isr & ISR_RWM) ? 'r' : 't');
|
||||
|
||||
if (i2c->slave != NULL)
|
||||
i2c->slave->event(i2c->slave->data,
|
||||
(isr & ISR_RWM) ? I2C_SLAVE_EVENT_START_READ : I2C_SLAVE_EVENT_START_WRITE);
|
||||
if (i2c->slave != NULL) {
|
||||
if (isr & ISR_RWM) {
|
||||
u8 byte = 0;
|
||||
|
||||
i2c_slave_event(i2c->slave, I2C_SLAVE_READ_REQUESTED,
|
||||
&byte);
|
||||
writel(byte, _IDBR(i2c));
|
||||
} else {
|
||||
i2c_slave_event(i2c->slave, I2C_SLAVE_WRITE_REQUESTED,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* slave could interrupt in the middle of us generating a
|
||||
|
@ -607,7 +616,7 @@ static void i2c_pxa_slave_stop(struct pxa_i2c *i2c)
|
|||
dev_dbg(&i2c->adap.dev, "ISR: SSD (Slave Stop)\n");
|
||||
|
||||
if (i2c->slave != NULL)
|
||||
i2c->slave->event(i2c->slave->data, I2C_SLAVE_EVENT_STOP);
|
||||
i2c_slave_event(i2c->slave, I2C_SLAVE_STOP, NULL);
|
||||
|
||||
if (i2c_debug > 2)
|
||||
dev_dbg(&i2c->adap.dev, "ISR: SSD (Slave Stop) acked\n");
|
||||
|
@ -619,6 +628,38 @@ static void i2c_pxa_slave_stop(struct pxa_i2c *i2c)
|
|||
if (i2c->msg)
|
||||
i2c_pxa_master_complete(i2c, I2C_RETRY);
|
||||
}
|
||||
|
||||
static int i2c_pxa_slave_reg(struct i2c_client *slave)
|
||||
{
|
||||
struct pxa_i2c *i2c = slave->adapter->algo_data;
|
||||
|
||||
if (i2c->slave)
|
||||
return -EBUSY;
|
||||
|
||||
if (!i2c->reg_isar)
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
i2c->slave = slave;
|
||||
i2c->slave_addr = slave->addr;
|
||||
|
||||
writel(i2c->slave_addr, _ISAR(i2c));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_pxa_slave_unreg(struct i2c_client *slave)
|
||||
{
|
||||
struct pxa_i2c *i2c = slave->adapter->algo_data;
|
||||
|
||||
WARN_ON(!i2c->slave);
|
||||
|
||||
i2c->slave_addr = I2C_PXA_SLAVE_ADDR;
|
||||
writel(i2c->slave_addr, _ISAR(i2c));
|
||||
|
||||
i2c->slave = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr)
|
||||
{
|
||||
|
@ -1141,11 +1182,19 @@ static u32 i2c_pxa_functionality(struct i2c_adapter *adap)
|
|||
static const struct i2c_algorithm i2c_pxa_algorithm = {
|
||||
.master_xfer = i2c_pxa_xfer,
|
||||
.functionality = i2c_pxa_functionality,
|
||||
#ifdef CONFIG_I2C_PXA_SLAVE
|
||||
.reg_slave = i2c_pxa_slave_reg,
|
||||
.unreg_slave = i2c_pxa_slave_unreg,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
|
||||
.master_xfer = i2c_pxa_pio_xfer,
|
||||
.functionality = i2c_pxa_functionality,
|
||||
#ifdef CONFIG_I2C_PXA_SLAVE
|
||||
.reg_slave = i2c_pxa_slave_reg,
|
||||
.unreg_slave = i2c_pxa_slave_unreg,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct of_device_id i2c_pxa_dt_ids[] = {
|
||||
|
@ -1270,10 +1319,6 @@ static int i2c_pxa_probe(struct platform_device *dev)
|
|||
i2c->highmode_enter = false;
|
||||
|
||||
if (plat) {
|
||||
#ifdef CONFIG_I2C_PXA_SLAVE
|
||||
i2c->slave_addr = plat->slave_addr;
|
||||
i2c->slave = plat->slave;
|
||||
#endif
|
||||
i2c->adap.class = plat->class;
|
||||
}
|
||||
|
||||
|
|
|
@ -628,7 +628,7 @@ static int qup_i2c_req_dma(struct qup_i2c_dev *qup)
|
|||
int err;
|
||||
|
||||
if (!qup->btx.dma) {
|
||||
qup->btx.dma = dma_request_slave_channel_reason(qup->dev, "tx");
|
||||
qup->btx.dma = dma_request_chan(qup->dev, "tx");
|
||||
if (IS_ERR(qup->btx.dma)) {
|
||||
err = PTR_ERR(qup->btx.dma);
|
||||
qup->btx.dma = NULL;
|
||||
|
@ -638,7 +638,7 @@ static int qup_i2c_req_dma(struct qup_i2c_dev *qup)
|
|||
}
|
||||
|
||||
if (!qup->brx.dma) {
|
||||
qup->brx.dma = dma_request_slave_channel_reason(qup->dev, "rx");
|
||||
qup->brx.dma = dma_request_chan(qup->dev, "rx");
|
||||
if (IS_ERR(qup->brx.dma)) {
|
||||
dev_err(qup->dev, "\n rx channel not available");
|
||||
err = PTR_ERR(qup->brx.dma);
|
||||
|
|
|
@ -317,7 +317,7 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, struct i2c_timin
|
|||
|
||||
scgd_find:
|
||||
dev_dbg(dev, "clk %d/%d(%lu), round %u, CDF:0x%x, SCGD: 0x%x\n",
|
||||
scl, t->bus_freq_hz, clk_get_rate(priv->clk), round, cdf, scgd);
|
||||
scl, t->bus_freq_hz, rate, round, cdf, scgd);
|
||||
|
||||
/* keep icccr value */
|
||||
priv->icccr = scgd << cdf_width | cdf;
|
||||
|
|
|
@ -486,7 +486,7 @@ static struct dma_chan *sh_mobile_i2c_request_dma_chan(struct device *dev,
|
|||
char *chan_name = dir == DMA_MEM_TO_DEV ? "tx" : "rx";
|
||||
int ret;
|
||||
|
||||
chan = dma_request_slave_channel_reason(dev, chan_name);
|
||||
chan = dma_request_chan(dev, chan_name);
|
||||
if (IS_ERR(chan)) {
|
||||
dev_dbg(dev, "request_channel failed for %s (%ld)\n", chan_name,
|
||||
PTR_ERR(chan));
|
||||
|
|
|
@ -20,13 +20,13 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
|
|||
|
||||
dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
|
||||
if (!dma)
|
||||
return NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* Request and configure I2C TX dma channel */
|
||||
dma->chan_tx = dma_request_slave_channel(dev, "tx");
|
||||
if (!dma->chan_tx) {
|
||||
dma->chan_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(dma->chan_tx)) {
|
||||
dev_dbg(dev, "can't request DMA tx channel\n");
|
||||
ret = -EINVAL;
|
||||
ret = PTR_ERR(dma->chan_tx);
|
||||
goto fail_al;
|
||||
}
|
||||
|
||||
|
@ -42,10 +42,10 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
|
|||
}
|
||||
|
||||
/* Request and configure I2C RX dma channel */
|
||||
dma->chan_rx = dma_request_slave_channel(dev, "rx");
|
||||
if (!dma->chan_rx) {
|
||||
dma->chan_rx = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(dma->chan_rx)) {
|
||||
dev_err(dev, "can't request DMA rx channel\n");
|
||||
ret = -EINVAL;
|
||||
ret = PTR_ERR(dma->chan_rx);
|
||||
goto fail_tx;
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ fail_al:
|
|||
devm_kfree(dev, dma);
|
||||
dev_info(dev, "can't use DMA\n");
|
||||
|
||||
return NULL;
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
void stm32_i2c_dma_free(struct stm32_i2c_dma *dma)
|
||||
|
|
|
@ -1267,8 +1267,8 @@ static int stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev *i2c_dev,
|
|||
* slave[0] supports 7-bit and 10-bit slave address
|
||||
* slave[1] supports 7-bit slave address only
|
||||
*/
|
||||
for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) {
|
||||
if (i == 1 && (slave->flags & I2C_CLIENT_PEC))
|
||||
for (i = STM32F7_I2C_MAX_SLAVE - 1; i >= 0; i--) {
|
||||
if (i == 1 && (slave->flags & I2C_CLIENT_TEN))
|
||||
continue;
|
||||
if (!i2c_dev->slave[i]) {
|
||||
*id = i;
|
||||
|
@ -1955,6 +1955,15 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
|||
i2c_dev->dma = stm32_i2c_dma_request(i2c_dev->dev, phy_addr,
|
||||
STM32F7_I2C_TXDR,
|
||||
STM32F7_I2C_RXDR);
|
||||
if (PTR_ERR(i2c_dev->dma) == -ENODEV)
|
||||
i2c_dev->dma = NULL;
|
||||
else if (IS_ERR(i2c_dev->dma)) {
|
||||
ret = PTR_ERR(i2c_dev->dma);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to request dma error %i\n", ret);
|
||||
goto clk_free;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, i2c_dev);
|
||||
|
||||
|
@ -1985,6 +1994,11 @@ pm_disable:
|
|||
pm_runtime_set_suspended(i2c_dev->dev);
|
||||
pm_runtime_dont_use_autosuspend(i2c_dev->dev);
|
||||
|
||||
if (i2c_dev->dma) {
|
||||
stm32_i2c_dma_free(i2c_dev->dma);
|
||||
i2c_dev->dma = NULL;
|
||||
}
|
||||
|
||||
clk_free:
|
||||
clk_disable_unprepare(i2c_dev->clk);
|
||||
|
||||
|
@ -1995,21 +2009,21 @@ static int stm32f7_i2c_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
|
||||
if (i2c_dev->dma) {
|
||||
stm32_i2c_dma_free(i2c_dev->dma);
|
||||
i2c_dev->dma = NULL;
|
||||
}
|
||||
|
||||
i2c_del_adapter(&i2c_dev->adap);
|
||||
pm_runtime_get_sync(i2c_dev->dev);
|
||||
|
||||
clk_disable_unprepare(i2c_dev->clk);
|
||||
|
||||
pm_runtime_put_noidle(i2c_dev->dev);
|
||||
pm_runtime_disable(i2c_dev->dev);
|
||||
pm_runtime_set_suspended(i2c_dev->dev);
|
||||
pm_runtime_dont_use_autosuspend(i2c_dev->dev);
|
||||
|
||||
if (i2c_dev->dma) {
|
||||
stm32_i2c_dma_free(i2c_dev->dma);
|
||||
i2c_dev->dma = NULL;
|
||||
}
|
||||
|
||||
clk_disable_unprepare(i2c_dev->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -413,7 +413,7 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
chan = dma_request_slave_channel_reason(i2c_dev->dev, "rx");
|
||||
chan = dma_request_chan(i2c_dev->dev, "rx");
|
||||
if (IS_ERR(chan)) {
|
||||
err = PTR_ERR(chan);
|
||||
goto err_out;
|
||||
|
@ -421,7 +421,7 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
|
|||
|
||||
i2c_dev->rx_dma_chan = chan;
|
||||
|
||||
chan = dma_request_slave_channel_reason(i2c_dev->dev, "tx");
|
||||
chan = dma_request_chan(i2c_dev->dev, "tx");
|
||||
if (IS_ERR(chan)) {
|
||||
err = PTR_ERR(chan);
|
||||
goto err_out;
|
||||
|
|
|
@ -46,6 +46,7 @@ enum xiic_endian {
|
|||
|
||||
/**
|
||||
* struct xiic_i2c - Internal representation of the XIIC I2C bus
|
||||
* @dev: Pointer to device structure
|
||||
* @base: Memory base of the HW registers
|
||||
* @wait: Wait queue for callers
|
||||
* @adap: Kernel adapter representation
|
||||
|
@ -57,6 +58,7 @@ enum xiic_endian {
|
|||
* @rx_msg: Current RX message
|
||||
* @rx_pos: Position within current RX message
|
||||
* @endianness: big/little-endian byte order
|
||||
* @clk: Pointer to AXI4-lite input clock
|
||||
*/
|
||||
struct xiic_i2c {
|
||||
struct device *dev;
|
||||
|
|
|
@ -1656,6 +1656,12 @@ void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_de
|
|||
t->sda_fall_ns = t->scl_fall_ns;
|
||||
|
||||
device_property_read_u32(dev, "i2c-sda-hold-time-ns", &t->sda_hold_ns);
|
||||
|
||||
device_property_read_u32(dev, "i2c-digital-filter-width-ns",
|
||||
&t->digital_filter_width_ns);
|
||||
|
||||
device_property_read_u32(dev, "i2c-analog-filter-cutoff-frequency",
|
||||
&t->analog_filter_cutoff_freq_hz);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_parse_fw_timings);
|
||||
|
||||
|
@ -1737,38 +1743,6 @@ EXPORT_SYMBOL(i2c_del_driver);
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* i2c_use_client - increments the reference count of the i2c client structure
|
||||
* @client: the client being referenced
|
||||
*
|
||||
* Each live reference to a client should be refcounted. The driver model does
|
||||
* that automatically as part of driver binding, so that most drivers don't
|
||||
* need to do this explicitly: they hold a reference until they're unbound
|
||||
* from the device.
|
||||
*
|
||||
* A pointer to the client with the incremented reference counter is returned.
|
||||
*/
|
||||
struct i2c_client *i2c_use_client(struct i2c_client *client)
|
||||
{
|
||||
if (client && get_device(&client->dev))
|
||||
return client;
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_use_client);
|
||||
|
||||
/**
|
||||
* i2c_release_client - release a use of the i2c client structure
|
||||
* @client: the client being no longer referenced
|
||||
*
|
||||
* Must be called when a user of a client is finished with it.
|
||||
*/
|
||||
void i2c_release_client(struct i2c_client *client)
|
||||
{
|
||||
if (client)
|
||||
put_device(&client->dev);
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_release_client);
|
||||
|
||||
struct i2c_cmd_arg {
|
||||
unsigned cmd;
|
||||
void *arg;
|
||||
|
@ -2271,10 +2245,10 @@ int i2c_probe_func_quick_read(struct i2c_adapter *adap, unsigned short addr)
|
|||
EXPORT_SYMBOL_GPL(i2c_probe_func_quick_read);
|
||||
|
||||
struct i2c_client *
|
||||
i2c_new_probed_device(struct i2c_adapter *adap,
|
||||
struct i2c_board_info *info,
|
||||
unsigned short const *addr_list,
|
||||
int (*probe)(struct i2c_adapter *adap, unsigned short addr))
|
||||
i2c_new_scanned_device(struct i2c_adapter *adap,
|
||||
struct i2c_board_info *info,
|
||||
unsigned short const *addr_list,
|
||||
int (*probe)(struct i2c_adapter *adap, unsigned short addr))
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -2304,11 +2278,24 @@ i2c_new_probed_device(struct i2c_adapter *adap,
|
|||
|
||||
if (addr_list[i] == I2C_CLIENT_END) {
|
||||
dev_dbg(&adap->dev, "Probing failed, no device found\n");
|
||||
return NULL;
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
info->addr = addr_list[i];
|
||||
return i2c_new_device(adap, info);
|
||||
return i2c_new_client_device(adap, info);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_new_scanned_device);
|
||||
|
||||
struct i2c_client *
|
||||
i2c_new_probed_device(struct i2c_adapter *adap,
|
||||
struct i2c_board_info *info,
|
||||
unsigned short const *addr_list,
|
||||
int (*probe)(struct i2c_adapter *adap, unsigned short addr))
|
||||
{
|
||||
struct i2c_client *client;
|
||||
|
||||
client = i2c_new_scanned_device(adap, info, addr_list, probe);
|
||||
return IS_ERR(client) ? NULL : client;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_new_probed_device);
|
||||
|
||||
|
|
|
@ -66,7 +66,6 @@ static irqreturn_t smbus_alert(int irq, void *d)
|
|||
{
|
||||
struct i2c_smbus_alert *alert = d;
|
||||
struct i2c_client *ara;
|
||||
unsigned short prev_addr = 0; /* Not a valid address */
|
||||
|
||||
ara = alert->ara;
|
||||
|
||||
|
@ -90,18 +89,12 @@ static irqreturn_t smbus_alert(int irq, void *d)
|
|||
data.addr = status >> 1;
|
||||
data.type = I2C_PROTOCOL_SMBUS_ALERT;
|
||||
|
||||
if (data.addr == prev_addr) {
|
||||
dev_warn(&ara->dev, "Duplicate SMBALERT# from dev "
|
||||
"0x%02x, skipping\n", data.addr);
|
||||
break;
|
||||
}
|
||||
dev_dbg(&ara->dev, "SMBALERT# from dev 0x%02x, flag %d\n",
|
||||
data.addr, data.data);
|
||||
|
||||
/* Notify driver for the device which issued the alert */
|
||||
device_for_each_child(&ara->adapter->dev, &data,
|
||||
smbus_do_alert);
|
||||
prev_addr = data.addr;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
|
|
@ -109,14 +109,14 @@ config I2C_DEMUX_PINCTRL
|
|||
want to change the I2C master at run-time depending on features.
|
||||
|
||||
config I2C_MUX_MLXCPLD
|
||||
tristate "Mellanox CPLD based I2C multiplexer"
|
||||
help
|
||||
If you say yes to this option, support will be included for a
|
||||
CPLD based I2C multiplexer. This driver provides access to
|
||||
I2C busses connected through a MUX, which is controlled
|
||||
by a CPLD register.
|
||||
tristate "Mellanox CPLD based I2C multiplexer"
|
||||
help
|
||||
If you say yes to this option, support will be included for a
|
||||
CPLD based I2C multiplexer. This driver provides access to
|
||||
I2C busses connected through a MUX, which is controlled
|
||||
by a CPLD register.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-mux-mlxcpld.
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-mux-mlxcpld.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -716,9 +716,12 @@ static int at24_probe(struct i2c_client *client)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_info(dev, "%u byte %s EEPROM, %s, %u bytes/write\n",
|
||||
byte_len, client->name,
|
||||
writable ? "writable" : "read-only", at24->write_max);
|
||||
if (writable)
|
||||
dev_info(dev, "%u byte %s EEPROM, writable, %u bytes/write\n",
|
||||
byte_len, client->name, at24->write_max);
|
||||
else
|
||||
dev_info(dev, "%u byte %s EEPROM, read-only\n",
|
||||
byte_len, client->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -191,8 +191,8 @@ static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) {
|
|||
0x1b, I2C_CLIENT_END
|
||||
};
|
||||
|
||||
i2c_new_probed_device(&m2info->maven.adapter,
|
||||
&maven_info, addr_list, NULL);
|
||||
i2c_new_scanned_device(&m2info->maven.adapter,
|
||||
&maven_info, addr_list, NULL);
|
||||
}
|
||||
}
|
||||
return m2info;
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _LINUX_I2C_ALGO_PXA_H
|
||||
#define _LINUX_I2C_ALGO_PXA_H
|
||||
|
||||
typedef enum i2c_slave_event_e {
|
||||
I2C_SLAVE_EVENT_START_READ,
|
||||
I2C_SLAVE_EVENT_START_WRITE,
|
||||
I2C_SLAVE_EVENT_STOP
|
||||
} i2c_slave_event_t;
|
||||
|
||||
struct i2c_slave_client {
|
||||
void *data;
|
||||
void (*event)(void *ptr, i2c_slave_event_t event);
|
||||
int (*read) (void *ptr);
|
||||
void (*write)(void *ptr, unsigned int val);
|
||||
};
|
||||
|
||||
#endif /* _LINUX_I2C_ALGO_PXA_H */
|
|
@ -452,10 +452,16 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
|
|||
* a default probing method is used.
|
||||
*/
|
||||
extern struct i2c_client *
|
||||
i2c_new_scanned_device(struct i2c_adapter *adap,
|
||||
struct i2c_board_info *info,
|
||||
unsigned short const *addr_list,
|
||||
int (*probe)(struct i2c_adapter *adap, unsigned short addr));
|
||||
|
||||
extern struct i2c_client *
|
||||
i2c_new_probed_device(struct i2c_adapter *adap,
|
||||
struct i2c_board_info *info,
|
||||
unsigned short const *addr_list,
|
||||
int (*probe)(struct i2c_adapter *adap, unsigned short addr));
|
||||
struct i2c_board_info *info,
|
||||
unsigned short const *addr_list,
|
||||
int (*probe)(struct i2c_adapter *adap, unsigned short addr));
|
||||
|
||||
/* Common custom probe functions */
|
||||
extern int i2c_probe_func_quick_read(struct i2c_adapter *adap, unsigned short addr);
|
||||
|
@ -575,6 +581,10 @@ struct i2c_lock_operations {
|
|||
* @scl_int_delay_ns: time IP core additionally needs to setup SCL in ns
|
||||
* @sda_fall_ns: time SDA signal takes to fall in ns; t(f) in the I2C specification
|
||||
* @sda_hold_ns: time IP core additionally needs to hold SDA in ns
|
||||
* @digital_filter_width_ns: width in ns of spikes on i2c lines that the IP core
|
||||
* digital filter can filter out
|
||||
* @analog_filter_cutoff_freq_hz: threshold frequency for the low pass IP core
|
||||
* analog filter
|
||||
*/
|
||||
struct i2c_timings {
|
||||
u32 bus_freq_hz;
|
||||
|
@ -583,6 +593,8 @@ struct i2c_timings {
|
|||
u32 scl_int_delay_ns;
|
||||
u32 sda_fall_ns;
|
||||
u32 sda_hold_ns;
|
||||
u32 digital_filter_width_ns;
|
||||
u32 analog_filter_cutoff_freq_hz;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -844,9 +856,6 @@ extern void i2c_del_driver(struct i2c_driver *driver);
|
|||
#define i2c_add_driver(driver) \
|
||||
i2c_register_driver(THIS_MODULE, driver)
|
||||
|
||||
extern struct i2c_client *i2c_use_client(struct i2c_client *client);
|
||||
extern void i2c_release_client(struct i2c_client *client);
|
||||
|
||||
/* call the i2c_client->command() of all attached clients with
|
||||
* the given arguments */
|
||||
extern void i2c_clients_command(struct i2c_adapter *adap,
|
||||
|
|
|
@ -55,11 +55,7 @@
|
|||
*/
|
||||
#define I2C_ISR_INIT 0x7FF /* status register init */
|
||||
|
||||
struct i2c_slave_client;
|
||||
|
||||
struct i2c_pxa_platform_data {
|
||||
unsigned int slave_addr;
|
||||
struct i2c_slave_client *slave;
|
||||
unsigned int class;
|
||||
unsigned int use_pio :1;
|
||||
unsigned int fast_mode :1;
|
||||
|
|
Loading…
Reference in New Issue