Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c fixes from Wolfram Sang: - a bigger fix for i801 to finally be able to be loaded on some machines again - smaller driver fixes - documentation update because of a renamed file * 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: i2c: mux: reg: Provide of_match_table i2c: mux: refer to i2c-mux.txt i2c: octeon: Avoid printk after too long SMBUS message i2c: octeon: Missing AAK flag in case of I2C_M_RECV_LEN i2c: i801: Allow ACPI SystemIO OpRegion to conflict with PCI BAR
This commit is contained in:
commit
5d1f7023fb
@ -44,8 +44,8 @@ Required properties:
|
|||||||
- our-claim-gpio: The GPIO that we use to claim the bus.
|
- our-claim-gpio: The GPIO that we use to claim the bus.
|
||||||
- their-claim-gpios: The GPIOs that the other sides use to claim the bus.
|
- their-claim-gpios: The GPIOs that the other sides use to claim the bus.
|
||||||
Note that some implementations may only support a single other master.
|
Note that some implementations may only support a single other master.
|
||||||
- Standard I2C mux properties. See mux.txt in this directory.
|
- Standard I2C mux properties. See i2c-mux.txt in this directory.
|
||||||
- Single I2C child bus node at reg 0. See mux.txt in this directory.
|
- Single I2C child bus node at reg 0. See i2c-mux.txt in this directory.
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
- slew-delay-us: microseconds to wait for a GPIO to go high. Default is 10 us.
|
- slew-delay-us: microseconds to wait for a GPIO to go high. Default is 10 us.
|
||||||
|
@ -27,7 +27,8 @@ Required properties:
|
|||||||
- i2c-bus-name: The name of this bus. Also needed as pinctrl-name for the I2C
|
- i2c-bus-name: The name of this bus. Also needed as pinctrl-name for the I2C
|
||||||
parents.
|
parents.
|
||||||
|
|
||||||
Furthermore, I2C mux properties and child nodes. See mux.txt in this directory.
|
Furthermore, I2C mux properties and child nodes. See i2c-mux.txt in this
|
||||||
|
directory.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -22,8 +22,8 @@ Required properties:
|
|||||||
- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
|
- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
|
||||||
port is connected to.
|
port is connected to.
|
||||||
- mux-gpios: list of gpios used to control the muxer
|
- mux-gpios: list of gpios used to control the muxer
|
||||||
* Standard I2C mux properties. See mux.txt in this directory.
|
* Standard I2C mux properties. See i2c-mux.txt in this directory.
|
||||||
* I2C child bus nodes. See mux.txt in this directory.
|
* I2C child bus nodes. See i2c-mux.txt in this directory.
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
- idle-state: value to set the muxer to when idle. When no value is
|
- idle-state: value to set the muxer to when idle. When no value is
|
||||||
@ -33,7 +33,7 @@ For each i2c child node, an I2C child bus will be created. They will
|
|||||||
be numbered based on their order in the device tree.
|
be numbered based on their order in the device tree.
|
||||||
|
|
||||||
Whenever an access is made to a device on a child bus, the value set
|
Whenever an access is made to a device on a child bus, the value set
|
||||||
in the revelant node's reg property will be output using the list of
|
in the relevant node's reg property will be output using the list of
|
||||||
GPIOs, the first in the list holding the least-significant value.
|
GPIOs, the first in the list holding the least-significant value.
|
||||||
|
|
||||||
If an idle state is defined, using the idle-state (optional) property,
|
If an idle state is defined, using the idle-state (optional) property,
|
||||||
|
@ -28,9 +28,9 @@ Also required are:
|
|||||||
* Standard pinctrl properties that specify the pin mux state for each child
|
* Standard pinctrl properties that specify the pin mux state for each child
|
||||||
bus. See ../pinctrl/pinctrl-bindings.txt.
|
bus. See ../pinctrl/pinctrl-bindings.txt.
|
||||||
|
|
||||||
* Standard I2C mux properties. See mux.txt in this directory.
|
* Standard I2C mux properties. See i2c-mux.txt in this directory.
|
||||||
|
|
||||||
* I2C child bus nodes. See mux.txt in this directory.
|
* I2C child bus nodes. See i2c-mux.txt in this directory.
|
||||||
|
|
||||||
For each named state defined in the pinctrl-names property, an I2C child bus
|
For each named state defined in the pinctrl-names property, an I2C child bus
|
||||||
will be created. I2C child bus numbers are assigned based on the index into
|
will be created. I2C child bus numbers are assigned based on the index into
|
||||||
|
@ -7,8 +7,8 @@ Required properties:
|
|||||||
- compatible: i2c-mux-reg
|
- compatible: i2c-mux-reg
|
||||||
- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
|
- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
|
||||||
port is connected to.
|
port is connected to.
|
||||||
* Standard I2C mux properties. See mux.txt in this directory.
|
* Standard I2C mux properties. See i2c-mux.txt in this directory.
|
||||||
* I2C child bus nodes. See mux.txt in this directory.
|
* I2C child bus nodes. See i2c-mux.txt in this directory.
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
- reg: this pair of <offset size> specifies the register to control the mux.
|
- reg: this pair of <offset size> specifies the register to control the mux.
|
||||||
@ -24,7 +24,7 @@ Optional properties:
|
|||||||
given, it defaults to the last value used.
|
given, it defaults to the last value used.
|
||||||
|
|
||||||
Whenever an access is made to a device on a child bus, the value set
|
Whenever an access is made to a device on a child bus, the value set
|
||||||
in the revelant node's reg property will be output to the register.
|
in the relevant node's reg property will be output to the register.
|
||||||
|
|
||||||
If an idle state is defined, using the idle-state (optional) property,
|
If an idle state is defined, using the idle-state (optional) property,
|
||||||
whenever an access is not being made to a device on a child bus, the
|
whenever an access is not being made to a device on a child bus, the
|
||||||
|
@ -245,6 +245,13 @@ struct i801_priv {
|
|||||||
struct platform_device *mux_pdev;
|
struct platform_device *mux_pdev;
|
||||||
#endif
|
#endif
|
||||||
struct platform_device *tco_pdev;
|
struct platform_device *tco_pdev;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If set to true the host controller registers are reserved for
|
||||||
|
* ACPI AML use. Protected by acpi_lock.
|
||||||
|
*/
|
||||||
|
bool acpi_reserved;
|
||||||
|
struct mutex acpi_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FEATURE_SMBUS_PEC (1 << 0)
|
#define FEATURE_SMBUS_PEC (1 << 0)
|
||||||
@ -718,6 +725,12 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
|
|||||||
int ret = 0, xact = 0;
|
int ret = 0, xact = 0;
|
||||||
struct i801_priv *priv = i2c_get_adapdata(adap);
|
struct i801_priv *priv = i2c_get_adapdata(adap);
|
||||||
|
|
||||||
|
mutex_lock(&priv->acpi_lock);
|
||||||
|
if (priv->acpi_reserved) {
|
||||||
|
mutex_unlock(&priv->acpi_lock);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
pm_runtime_get_sync(&priv->pci_dev->dev);
|
pm_runtime_get_sync(&priv->pci_dev->dev);
|
||||||
|
|
||||||
hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
|
hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
|
||||||
@ -820,6 +833,7 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
|
|||||||
out:
|
out:
|
||||||
pm_runtime_mark_last_busy(&priv->pci_dev->dev);
|
pm_runtime_mark_last_busy(&priv->pci_dev->dev);
|
||||||
pm_runtime_put_autosuspend(&priv->pci_dev->dev);
|
pm_runtime_put_autosuspend(&priv->pci_dev->dev);
|
||||||
|
mutex_unlock(&priv->acpi_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1257,6 +1271,83 @@ static void i801_add_tco(struct i801_priv *priv)
|
|||||||
priv->tco_pdev = pdev;
|
priv->tco_pdev = pdev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_ACPI
|
||||||
|
static acpi_status
|
||||||
|
i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
|
||||||
|
u64 *value, void *handler_context, void *region_context)
|
||||||
|
{
|
||||||
|
struct i801_priv *priv = handler_context;
|
||||||
|
struct pci_dev *pdev = priv->pci_dev;
|
||||||
|
acpi_status status;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Once BIOS AML code touches the OpRegion we warn and inhibit any
|
||||||
|
* further access from the driver itself. This device is now owned
|
||||||
|
* by the system firmware.
|
||||||
|
*/
|
||||||
|
mutex_lock(&priv->acpi_lock);
|
||||||
|
|
||||||
|
if (!priv->acpi_reserved) {
|
||||||
|
priv->acpi_reserved = true;
|
||||||
|
|
||||||
|
dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n");
|
||||||
|
dev_warn(&pdev->dev, "Driver SMBus register access inhibited\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BIOS is accessing the host controller so prevent it from
|
||||||
|
* suspending automatically from now on.
|
||||||
|
*/
|
||||||
|
pm_runtime_get_sync(&pdev->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((function & ACPI_IO_MASK) == ACPI_READ)
|
||||||
|
status = acpi_os_read_port(address, (u32 *)value, bits);
|
||||||
|
else
|
||||||
|
status = acpi_os_write_port(address, (u32)*value, bits);
|
||||||
|
|
||||||
|
mutex_unlock(&priv->acpi_lock);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int i801_acpi_probe(struct i801_priv *priv)
|
||||||
|
{
|
||||||
|
struct acpi_device *adev;
|
||||||
|
acpi_status status;
|
||||||
|
|
||||||
|
adev = ACPI_COMPANION(&priv->pci_dev->dev);
|
||||||
|
if (adev) {
|
||||||
|
status = acpi_install_address_space_handler(adev->handle,
|
||||||
|
ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler,
|
||||||
|
NULL, priv);
|
||||||
|
if (ACPI_SUCCESS(status))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return acpi_check_resource_conflict(&priv->pci_dev->resource[SMBBAR]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void i801_acpi_remove(struct i801_priv *priv)
|
||||||
|
{
|
||||||
|
struct acpi_device *adev;
|
||||||
|
|
||||||
|
adev = ACPI_COMPANION(&priv->pci_dev->dev);
|
||||||
|
if (!adev)
|
||||||
|
return;
|
||||||
|
|
||||||
|
acpi_remove_address_space_handler(adev->handle,
|
||||||
|
ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler);
|
||||||
|
|
||||||
|
mutex_lock(&priv->acpi_lock);
|
||||||
|
if (priv->acpi_reserved)
|
||||||
|
pm_runtime_put(&priv->pci_dev->dev);
|
||||||
|
mutex_unlock(&priv->acpi_lock);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; }
|
||||||
|
static inline void i801_acpi_remove(struct i801_priv *priv) { }
|
||||||
|
#endif
|
||||||
|
|
||||||
static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||||
{
|
{
|
||||||
unsigned char temp;
|
unsigned char temp;
|
||||||
@ -1274,6 +1365,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||||||
priv->adapter.dev.parent = &dev->dev;
|
priv->adapter.dev.parent = &dev->dev;
|
||||||
ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev));
|
ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev));
|
||||||
priv->adapter.retries = 3;
|
priv->adapter.retries = 3;
|
||||||
|
mutex_init(&priv->acpi_lock);
|
||||||
|
|
||||||
priv->pci_dev = dev;
|
priv->pci_dev = dev;
|
||||||
switch (dev->device) {
|
switch (dev->device) {
|
||||||
@ -1336,10 +1428,8 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = acpi_check_resource_conflict(&dev->resource[SMBBAR]);
|
if (i801_acpi_probe(priv))
|
||||||
if (err) {
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
|
||||||
|
|
||||||
err = pcim_iomap_regions(dev, 1 << SMBBAR,
|
err = pcim_iomap_regions(dev, 1 << SMBBAR,
|
||||||
dev_driver_string(&dev->dev));
|
dev_driver_string(&dev->dev));
|
||||||
@ -1348,6 +1438,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||||||
"Failed to request SMBus region 0x%lx-0x%Lx\n",
|
"Failed to request SMBus region 0x%lx-0x%Lx\n",
|
||||||
priv->smba,
|
priv->smba,
|
||||||
(unsigned long long)pci_resource_end(dev, SMBBAR));
|
(unsigned long long)pci_resource_end(dev, SMBBAR));
|
||||||
|
i801_acpi_remove(priv);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1412,6 +1503,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||||||
err = i2c_add_adapter(&priv->adapter);
|
err = i2c_add_adapter(&priv->adapter);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&dev->dev, "Failed to add SMBus adapter\n");
|
dev_err(&dev->dev, "Failed to add SMBus adapter\n");
|
||||||
|
i801_acpi_remove(priv);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1438,6 +1530,7 @@ static void i801_remove(struct pci_dev *dev)
|
|||||||
|
|
||||||
i801_del_mux(priv);
|
i801_del_mux(priv);
|
||||||
i2c_del_adapter(&priv->adapter);
|
i2c_del_adapter(&priv->adapter);
|
||||||
|
i801_acpi_remove(priv);
|
||||||
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
|
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
|
||||||
|
|
||||||
platform_device_unregister(priv->tco_pdev);
|
platform_device_unregister(priv->tco_pdev);
|
||||||
|
@ -934,8 +934,15 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
for (i = 0; i < length; i++) {
|
for (i = 0; i < length; i++) {
|
||||||
/* for the last byte TWSI_CTL_AAK must not be set */
|
/*
|
||||||
if (i + 1 == length)
|
* For the last byte to receive TWSI_CTL_AAK must not be set.
|
||||||
|
*
|
||||||
|
* A special case is I2C_M_RECV_LEN where we don't know the
|
||||||
|
* additional length yet. If recv_len is set we assume we're
|
||||||
|
* not reading the final byte and therefore need to set
|
||||||
|
* TWSI_CTL_AAK.
|
||||||
|
*/
|
||||||
|
if ((i + 1 == length) && !(recv_len && i == 0))
|
||||||
final_read = true;
|
final_read = true;
|
||||||
|
|
||||||
/* clear iflg to allow next event */
|
/* clear iflg to allow next event */
|
||||||
@ -950,12 +957,8 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
|
|||||||
|
|
||||||
data[i] = octeon_i2c_data_read(i2c);
|
data[i] = octeon_i2c_data_read(i2c);
|
||||||
if (recv_len && i == 0) {
|
if (recv_len && i == 0) {
|
||||||
if (data[i] > I2C_SMBUS_BLOCK_MAX + 1) {
|
if (data[i] > I2C_SMBUS_BLOCK_MAX + 1)
|
||||||
dev_err(i2c->dev,
|
|
||||||
"%s: read len > I2C_SMBUS_BLOCK_MAX %d\n",
|
|
||||||
__func__, data[i]);
|
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
}
|
|
||||||
length += data[i];
|
length += data[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,6 +260,7 @@ static struct platform_driver i2c_mux_reg_driver = {
|
|||||||
.remove = i2c_mux_reg_remove,
|
.remove = i2c_mux_reg_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "i2c-mux-reg",
|
.name = "i2c-mux-reg",
|
||||||
|
.of_match_table = of_match_ptr(i2c_mux_reg_of_match),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user