Skip to content

Commit

Permalink
Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
Linus Torvalds committed Jun 11, 2016
2 parents 90735c9 + 9f05e62 commit 5d1f702
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ Required properties:
- 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.
Note that some implementations may only support a single other master.
- Standard I2C mux properties. See mux.txt in this directory.
- Single I2C child bus node at reg 0. 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 i2c-mux.txt in this directory.

Optional properties:
- slew-delay-us: microseconds to wait for a GPIO to go high. Default is 10 us.
Expand Down
3 changes: 2 additions & 1 deletion Documentation/devicetree/bindings/i2c/i2c-demux-pinctrl.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ Required properties:
- i2c-bus-name: The name of this bus. Also needed as pinctrl-name for the I2C
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:

Expand Down
6 changes: 3 additions & 3 deletions Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ Required properties:
- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
port is connected to.
- mux-gpios: list of gpios used to control the muxer
* Standard I2C mux properties. See mux.txt in this directory.
* I2C child bus nodes. See mux.txt in this directory.
* Standard I2C mux properties. See i2c-mux.txt in this directory.
* I2C child bus nodes. See i2c-mux.txt in this directory.

Optional properties:
- idle-state: value to set the muxer to when idle. When no value is
Expand All @@ -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.

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.

If an idle state is defined, using the idle-state (optional) property,
Expand Down
4 changes: 2 additions & 2 deletions Documentation/devicetree/bindings/i2c/i2c-mux-pinctrl.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ Also required are:
* Standard pinctrl properties that specify the pin mux state for each child
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
will be created. I2C child bus numbers are assigned based on the index into
Expand Down
6 changes: 3 additions & 3 deletions Documentation/devicetree/bindings/i2c/i2c-mux-reg.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ Required properties:
- compatible: i2c-mux-reg
- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
port is connected to.
* Standard I2C mux properties. See mux.txt in this directory.
* I2C child bus nodes. See mux.txt in this directory.
* Standard I2C mux properties. See i2c-mux.txt in this directory.
* I2C child bus nodes. See i2c-mux.txt in this directory.

Optional properties:
- reg: this pair of <offset size> specifies the register to control the mux.
Expand All @@ -24,7 +24,7 @@ Optional properties:
given, it defaults to the last value used.

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,
whenever an access is not being made to a device on a child bus, the
Expand Down
99 changes: 96 additions & 3 deletions drivers/i2c/busses/i2c-i801.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,13 @@ struct i801_priv {
struct platform_device *mux_pdev;
#endif
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)
Expand Down Expand Up @@ -718,6 +725,12 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
int ret = 0, xact = 0;
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);

hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
Expand Down Expand Up @@ -820,6 +833,7 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
out:
pm_runtime_mark_last_busy(&priv->pci_dev->dev);
pm_runtime_put_autosuspend(&priv->pci_dev->dev);
mutex_unlock(&priv->acpi_lock);
return ret;
}

Expand Down Expand Up @@ -1257,6 +1271,83 @@ static void i801_add_tco(struct i801_priv *priv)
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)
{
unsigned char temp;
Expand All @@ -1274,6 +1365,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
priv->adapter.dev.parent = &dev->dev;
ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev));
priv->adapter.retries = 3;
mutex_init(&priv->acpi_lock);

priv->pci_dev = dev;
switch (dev->device) {
Expand Down Expand Up @@ -1336,10 +1428,8 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
return -ENODEV;
}

err = acpi_check_resource_conflict(&dev->resource[SMBBAR]);
if (err) {
if (i801_acpi_probe(priv))
return -ENODEV;
}

err = pcim_iomap_regions(dev, 1 << SMBBAR,
dev_driver_string(&dev->dev));
Expand All @@ -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",
priv->smba,
(unsigned long long)pci_resource_end(dev, SMBBAR));
i801_acpi_remove(priv);
return err;
}

Expand Down Expand Up @@ -1412,6 +1503,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
err = i2c_add_adapter(&priv->adapter);
if (err) {
dev_err(&dev->dev, "Failed to add SMBus adapter\n");
i801_acpi_remove(priv);
return err;
}

Expand All @@ -1438,6 +1530,7 @@ static void i801_remove(struct pci_dev *dev)

i801_del_mux(priv);
i2c_del_adapter(&priv->adapter);
i801_acpi_remove(priv);
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);

platform_device_unregister(priv->tco_pdev);
Expand Down
17 changes: 10 additions & 7 deletions drivers/i2c/busses/i2c-octeon.c
Original file line number Diff line number Diff line change
Expand Up @@ -934,8 +934,15 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
return result;

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;

/* clear iflg to allow next event */
Expand All @@ -950,12 +957,8 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,

data[i] = octeon_i2c_data_read(i2c);
if (recv_len && i == 0) {
if (data[i] > I2C_SMBUS_BLOCK_MAX + 1) {
dev_err(i2c->dev,
"%s: read len > I2C_SMBUS_BLOCK_MAX %d\n",
__func__, data[i]);
if (data[i] > I2C_SMBUS_BLOCK_MAX + 1)
return -EPROTO;
}
length += data[i];
}

Expand Down
1 change: 1 addition & 0 deletions drivers/i2c/muxes/i2c-mux-reg.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ static struct platform_driver i2c_mux_reg_driver = {
.remove = i2c_mux_reg_remove,
.driver = {
.name = "i2c-mux-reg",
.of_match_table = of_match_ptr(i2c_mux_reg_of_match),
},
};

Expand Down

0 comments on commit 5d1f702

Please sign in to comment.