From 0f614d834bccd3537881c5d0933803b407ce3283 Mon Sep 17 00:00:00 2001 From: Jean-Michel Hautbois Date: Sun, 31 Jan 2016 16:33:00 +0100 Subject: i2c: Add generic support passing secondary devices addresses Some I2C devices have multiple addresses assigned, for example each address corresponding to a different internal register map page of the device. So far drivers which need support for this have handled this with a driver specific and non-generic implementation, e.g. passing the additional address via platform data. This patch provides a new helper function called i2c_new_secondary_device() which is intended to provide a generic way to get the secondary address as well as instantiate a struct i2c_client for the secondary address. The function expects a pointer to the primary i2c_client, a name for the secondary address and an optional default address. The name is used as a handle to specify which secondary address to get. The default address is used as a fallback in case no secondary address was explicitly specified. In case no secondary address and no default address were specified the function returns NULL. For now the function only supports look-up of the secondary address from devicetree, but it can be extended in the future to for example support board files and/or ACPI. Signed-off-by: Jean-Michel Hautbois Acked-by: Rob Herring Acked-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index af11b658984d..952d2f0c02c5 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1145,6 +1145,47 @@ struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address) } EXPORT_SYMBOL_GPL(i2c_new_dummy); +/** + * i2c_new_secondary_device - Helper to get the instantiated secondary address + * and create the associated device + * @client: Handle to the primary client + * @name: Handle to specify which secondary address to get + * @default_addr: Used as a fallback if no secondary address was specified + * Context: can sleep + * + * I2C clients can be composed of multiple I2C slaves bound together in a single + * component. The I2C client driver then binds to the master I2C slave and needs + * to create I2C dummy clients to communicate with all the other slaves. + * + * This function creates and returns an I2C dummy client whose I2C address is + * retrieved from the platform firmware based on the given slave name. If no + * address is specified by the firmware default_addr is used. + * + * On DT-based platforms the address is retrieved from the "reg" property entry + * cell whose "reg-names" value matches the slave name. + * + * This returns the new i2c client, which should be saved for later use with + * i2c_unregister_device(); or NULL to indicate an error. + */ +struct i2c_client *i2c_new_secondary_device(struct i2c_client *client, + const char *name, + u16 default_addr) +{ + struct device_node *np = client->dev.of_node; + u32 addr = default_addr; + int i; + + if (np) { + i = of_property_match_string(np, "reg-names", name); + if (i >= 0) + of_property_read_u32_index(np, "reg", i, &addr); + } + + dev_dbg(&client->adapter->dev, "Address for %s : 0x%x\n", name, addr); + return i2c_new_dummy(client->adapter, addr); +} +EXPORT_SYMBOL_GPL(i2c_new_secondary_device); + /* ------------------------------------------------------------------------- */ /* I2C bus adapters -- one roots each I2C or SMBUS segment */ -- cgit v1.2.3-59-g8ed1b From a90bc5d9a77a4e0d5e65f69ef56eb40627f50e3e Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 25 May 2016 09:37:02 +0200 Subject: i2c: i801: Drop needless bit-wise OR The interrupt handling code makes it look like several status values may be merged together before being processed, while this will never happen. Change from bit-wise OR to simple assignment to make it more obvious and avoid misunderstanding. Signed-off-by: Jean Delvare Reviewed-by: Mika Westerberg Reviewed-by: Daniel Kurtz Reviewed-by: Benjamin Tissoires Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 4a60ad214747..b43696394d5b 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -547,7 +547,7 @@ static irqreturn_t i801_isr(int irq, void *dev_id) status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS; if (status) { outb_p(status, SMBHSTSTS(priv)); - priv->status |= status; + priv->status = status; wake_up(&priv->waitq); } -- cgit v1.2.3-59-g8ed1b From 27bfeb5a0619554d9734fb39e14f0e80fa7c342c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 5 Jun 2016 11:41:42 +0200 Subject: i2c: jz4780: drop superfluous init David reported that the length for memset was incorrect (element sizes were not taken into account). Then I saw that we are clearing kzalloced memory, so we can simply drop this code. Reported-by: David Binderman Reviewed-by: Axel Lin Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-jz4780.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c index ba14a863b451..cd9872594fe2 100644 --- a/drivers/i2c/busses/i2c-jz4780.c +++ b/drivers/i2c/busses/i2c-jz4780.c @@ -791,10 +791,6 @@ static int jz4780_i2c_probe(struct platform_device *pdev) jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0); - i2c->cmd = 0; - memset(i2c->cmd_buf, 0, BUFSIZE); - memset(i2c->data_buf, 0, BUFSIZE); - i2c->irq = platform_get_irq(pdev, 0); ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0, dev_name(&pdev->dev), i2c); -- cgit v1.2.3-59-g8ed1b From 33c77abcf4aa5e9679f702a2f979d44a470f6e6e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 2 Jun 2016 13:28:48 +0800 Subject: i2c: robotfuzz-osif: Constify osif_table osif_table is never modified, so declare it as const. Signed-off-by: Axel Lin Acked-by: Andrew Lunn Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-robotfuzz-osif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-robotfuzz-osif.c b/drivers/i2c/busses/i2c-robotfuzz-osif.c index ced9c6a308d1..89d8b41b6668 100644 --- a/drivers/i2c/busses/i2c-robotfuzz-osif.c +++ b/drivers/i2c/busses/i2c-robotfuzz-osif.c @@ -125,7 +125,7 @@ static struct i2c_algorithm osif_algorithm = { #define USB_OSIF_VENDOR_ID 0x1964 #define USB_OSIF_PRODUCT_ID 0x0001 -static struct usb_device_id osif_table[] = { +static const struct usb_device_id osif_table[] = { { USB_DEVICE(USB_OSIF_VENDOR_ID, USB_OSIF_PRODUCT_ID) }, { } }; -- cgit v1.2.3-59-g8ed1b From b4f210541fc319bd643ad9a4fdbfe2ce31be6cfc Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 9 Jun 2016 16:53:47 +0200 Subject: i2c: add a protocol parameter to the alert callback .alert() is meant to be generic, but there is currently no way for the device driver to know which protocol generated the alert. Add a parameter in .alert() to help the device driver to understand what is given in data. This patch is required to have the support of SMBus Host Notify protocol through .alert(). Tested-by: Andrew Duggan For hwmon: Acked-by: Guenter Roeck For IPMI: Acked-by: Corey Minyard Signed-off-by: Benjamin Tissoires Signed-off-by: Wolfram Sang --- drivers/char/ipmi/ipmi_ssif.c | 6 +++++- drivers/hwmon/lm90.c | 6 +++++- drivers/i2c/i2c-smbus.c | 3 ++- include/linux/i2c.h | 7 ++++++- 4 files changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 097c86898608..5673ffff00be 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -568,12 +568,16 @@ static void retry_timeout(unsigned long data) } -static void ssif_alert(struct i2c_client *client, unsigned int data) +static void ssif_alert(struct i2c_client *client, enum i2c_alert_protocol type, + unsigned int data) { struct ssif_info *ssif_info = i2c_get_clientdata(client); unsigned long oflags, *flags; bool do_get = false; + if (type != I2C_PROTOCOL_SMBUS_ALERT) + return; + ssif_inc_stat(ssif_info, alerts); flags = ipmi_ssif_lock_cond(ssif_info, &oflags); diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index e30a5939dc0d..5b62c57e8bfc 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -1624,10 +1624,14 @@ static int lm90_remove(struct i2c_client *client) return 0; } -static void lm90_alert(struct i2c_client *client, unsigned int flag) +static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type, + unsigned int flag) { u16 alarms; + if (type != I2C_PROTOCOL_SMBUS_ALERT) + return; + if (lm90_is_tripped(client, &alarms)) { /* * Disable ALERT# output, because these chips don't implement diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index abb55d3e76f3..3b6765a4ebe9 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -56,7 +56,8 @@ static int smbus_do_alert(struct device *dev, void *addrp) if (client->dev.driver) { driver = to_i2c_driver(client->dev.driver); if (driver->alert) - driver->alert(client, data->flag); + driver->alert(client, I2C_PROTOCOL_SMBUS_ALERT, + data->flag); else dev_warn(&client->dev, "no driver alert()!\n"); } else diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 6df7bad8c26c..37a45dcd6592 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -126,6 +126,10 @@ i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, u8 command, u8 length, u8 *values); #endif /* I2C */ +enum i2c_alert_protocol { + I2C_PROTOCOL_SMBUS_ALERT, +}; + /** * struct i2c_driver - represent an I2C device driver * @class: What kind of i2c device we instantiate (for detect) @@ -181,7 +185,8 @@ struct i2c_driver { * For the SMBus alert protocol, there is a single bit of data passed * as the alert response's low bit ("event flag"). */ - void (*alert)(struct i2c_client *, unsigned int data); + void (*alert)(struct i2c_client *, enum i2c_alert_protocol protocol, + unsigned int data); /* a ioctl like command that can be used to perform specific functions * with the device. -- cgit v1.2.3-59-g8ed1b From e456cd37bc28abe47dc65189df916ac0510ac1d4 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 9 Jun 2016 16:53:48 +0200 Subject: i2c: smbus: add SMBus Host Notify support SMBus Host Notify allows a slave device to act as a master on a bus to notify the host of an interrupt. On Intel chipsets, the functionality is directly implemented in the firmware. We just need to export a function to call .alert() on the proper device driver. i2c_handle_smbus_host_notify() behaves like i2c_handle_smbus_alert(). When called, it schedules a task that will be able to sleep to go through the list of devices attached to the adapter. The current implementation allows one Host Notification to be scheduled while an other is running. Tested-by: Andrew Duggan Signed-off-by: Benjamin Tissoires Signed-off-by: Wolfram Sang --- Documentation/i2c/smbus-protocol | 6 +++ drivers/i2c/i2c-smbus.c | 113 +++++++++++++++++++++++++++++++++++++-- include/linux/i2c-smbus.h | 44 +++++++++++++++ include/linux/i2c.h | 3 ++ include/uapi/linux/i2c.h | 1 + 5 files changed, 162 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/Documentation/i2c/smbus-protocol b/Documentation/i2c/smbus-protocol index 6012b12b3510..14d4ec1be245 100644 --- a/Documentation/i2c/smbus-protocol +++ b/Documentation/i2c/smbus-protocol @@ -199,6 +199,12 @@ alerting device's address. [S] [HostAddr] [Wr] A [DevAddr] A [DataLow] A [DataHigh] A [P] +This is implemented in the following way in the Linux kernel: +* I2C bus drivers which support SMBus Host Notify should call + i2c_setup_smbus_host_notify() to setup SMBus Host Notify support. +* I2C drivers for devices which can trigger SMBus Host Notify should implement + the optional alert() callback. + Packet Error Checking (PEC) =========================== diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index 3b6765a4ebe9..f574995b41c1 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -33,7 +33,8 @@ struct i2c_smbus_alert { struct alert_data { unsigned short addr; - u8 flag:1; + enum i2c_alert_protocol type; + unsigned int data; }; /* If this is the alerting device, notify its driver */ @@ -56,8 +57,7 @@ static int smbus_do_alert(struct device *dev, void *addrp) if (client->dev.driver) { driver = to_i2c_driver(client->dev.driver); if (driver->alert) - driver->alert(client, I2C_PROTOCOL_SMBUS_ALERT, - data->flag); + driver->alert(client, data->type, data->data); else dev_warn(&client->dev, "no driver alert()!\n"); } else @@ -97,8 +97,9 @@ static void smbus_alert(struct work_struct *work) if (status < 0) break; - data.flag = status & 1; + data.data = status & 1; data.addr = status >> 1; + data.type = I2C_PROTOCOL_SMBUS_ALERT; if (data.addr == prev_addr) { dev_warn(&ara->dev, "Duplicate SMBALERT# from dev " @@ -106,7 +107,7 @@ static void smbus_alert(struct work_struct *work) break; } dev_dbg(&ara->dev, "SMBALERT# from dev 0x%02x, flag %d\n", - data.addr, data.flag); + data.addr, data.data); /* Notify driver for the device which issued the alert */ device_for_each_child(&ara->adapter->dev, &data, @@ -240,6 +241,108 @@ int i2c_handle_smbus_alert(struct i2c_client *ara) } EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert); +static void smbus_host_notify_work(struct work_struct *work) +{ + struct alert_data alert; + struct i2c_adapter *adapter; + unsigned long flags; + u16 payload; + u8 addr; + struct smbus_host_notify *data; + + data = container_of(work, struct smbus_host_notify, work); + + spin_lock_irqsave(&data->lock, flags); + payload = data->payload; + addr = data->addr; + adapter = data->adapter; + + /* clear the pending bit and release the spinlock */ + data->pending = false; + spin_unlock_irqrestore(&data->lock, flags); + + if (!adapter || !addr) + return; + + alert.type = I2C_PROTOCOL_SMBUS_HOST_NOTIFY; + alert.addr = addr; + alert.data = payload; + + device_for_each_child(&adapter->dev, &alert, smbus_do_alert); +} + +/** + * i2c_setup_smbus_host_notify - Allocate a new smbus_host_notify for the given + * I2C adapter. + * @adapter: the adapter we want to associate a Host Notify function + * + * Returns a struct smbus_host_notify pointer on success, and NULL on failure. + * The resulting smbus_host_notify must not be freed afterwards, it is a + * managed resource already. + */ +struct smbus_host_notify *i2c_setup_smbus_host_notify(struct i2c_adapter *adap) +{ + struct smbus_host_notify *host_notify; + + host_notify = devm_kzalloc(&adap->dev, sizeof(struct smbus_host_notify), + GFP_KERNEL); + if (!host_notify) + return NULL; + + host_notify->adapter = adap; + + spin_lock_init(&host_notify->lock); + INIT_WORK(&host_notify->work, smbus_host_notify_work); + + return host_notify; +} +EXPORT_SYMBOL_GPL(i2c_setup_smbus_host_notify); + +/** + * i2c_handle_smbus_host_notify - Forward a Host Notify event to the correct + * I2C client. + * @host_notify: the struct host_notify attached to the relevant adapter + * @data: the Host Notify data which contains the payload and address of the + * client + * Context: can't sleep + * + * Helper function to be called from an I2C bus driver's interrupt + * handler. It will schedule the Host Notify work, in turn calling the + * corresponding I2C device driver's alert function. + * + * host_notify should be a valid pointer previously returned by + * i2c_setup_smbus_host_notify(). + */ +int i2c_handle_smbus_host_notify(struct smbus_host_notify *host_notify, + unsigned short addr, unsigned int data) +{ + unsigned long flags; + struct i2c_adapter *adapter; + + if (!host_notify || !host_notify->adapter) + return -EINVAL; + + adapter = host_notify->adapter; + + spin_lock_irqsave(&host_notify->lock, flags); + + if (host_notify->pending) { + spin_unlock_irqrestore(&host_notify->lock, flags); + dev_warn(&adapter->dev, "Host Notify already scheduled.\n"); + return -EBUSY; + } + + host_notify->payload = data; + host_notify->addr = addr; + + /* Mark that there is a pending notification and release the lock */ + host_notify->pending = true; + spin_unlock_irqrestore(&host_notify->lock, flags); + + return schedule_work(&host_notify->work); +} +EXPORT_SYMBOL_GPL(i2c_handle_smbus_host_notify); + module_i2c_driver(smbalert_driver); MODULE_AUTHOR("Jean Delvare "); diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h index 8f1b086ca5bc..4ac95bbe53ef 100644 --- a/include/linux/i2c-smbus.h +++ b/include/linux/i2c-smbus.h @@ -23,6 +23,8 @@ #define _LINUX_I2C_SMBUS_H #include +#include +#include /** @@ -48,4 +50,46 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, struct i2c_smbus_alert_setup *setup); int i2c_handle_smbus_alert(struct i2c_client *ara); +/** + * smbus_host_notify - internal structure used by the Host Notify mechanism. + * @adapter: the I2C adapter associated with this struct + * @work: worker used to schedule the IRQ in the slave device + * @lock: spinlock to check if a notification is already pending + * @pending: flag set when a notification is pending (any new notification will + * be rejected if pending is true) + * @payload: the actual payload of the Host Notify event + * @addr: the address of the slave device which raised the notification + * + * This struct needs to be allocated by i2c_setup_smbus_host_notify() and does + * not need to be freed. Internally, i2c_setup_smbus_host_notify() uses a + * managed resource to clean this up when the adapter get released. + */ +struct smbus_host_notify { + struct i2c_adapter *adapter; + struct work_struct work; + spinlock_t lock; + bool pending; + u16 payload; + u8 addr; +}; + +#if IS_ENABLED(CONFIG_I2C_SMBUS) +struct smbus_host_notify *i2c_setup_smbus_host_notify(struct i2c_adapter *adap); +int i2c_handle_smbus_host_notify(struct smbus_host_notify *host_notify, + unsigned short addr, unsigned int data); +#else +static inline struct smbus_host_notify * +i2c_setup_smbus_host_notify(struct i2c_adapter *adap) +{ + return NULL; +} + +static inline int +i2c_handle_smbus_host_notify(struct smbus_host_notify *host_notify, + unsigned short addr, unsigned int data) +{ + return 0; +} +#endif /* I2C_SMBUS */ + #endif /* _LINUX_I2C_SMBUS_H */ diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 37a45dcd6592..fffdc270ca18 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -128,6 +128,7 @@ i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, enum i2c_alert_protocol { I2C_PROTOCOL_SMBUS_ALERT, + I2C_PROTOCOL_SMBUS_HOST_NOTIFY, }; /** @@ -184,6 +185,8 @@ struct i2c_driver { * The format and meaning of the data value depends on the protocol. * For the SMBus alert protocol, there is a single bit of data passed * as the alert response's low bit ("event flag"). + * For the SMBus Host Notify protocol, the data corresponds to the + * 16-bit payload data reported by the slave device acting as master. */ void (*alert)(struct i2c_client *, enum i2c_alert_protocol protocol, unsigned int data); diff --git a/include/uapi/linux/i2c.h b/include/uapi/linux/i2c.h index adcbef4bff61..009e27bb9abe 100644 --- a/include/uapi/linux/i2c.h +++ b/include/uapi/linux/i2c.h @@ -102,6 +102,7 @@ struct i2c_msg { #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 #define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ +#define I2C_FUNC_SMBUS_HOST_NOTIFY 0x10000000 #define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ I2C_FUNC_SMBUS_WRITE_BYTE) -- cgit v1.2.3-59-g8ed1b From 0a6ad2f95f36bf1686c6598697d8afc7daca2a03 Mon Sep 17 00:00:00 2001 From: David Wu Date: Mon, 16 May 2016 21:57:36 +0800 Subject: i2c: rk3x: add documentation to fields in "struct rk3x_i2c" Add kernel-doc documentation for the elements of the previously undocumented struct rk3x_i2c. Signed-off-by: David Wu Reviewed-by: Douglas Anderson Reviewed-by: Heiko Stuebner Tested-by: Heiko Stuebner Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rk3x.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 80bed02cd942..7e45d5101d32 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -90,6 +90,26 @@ struct rk3x_i2c_soc_data { int grf_offset; }; +/** + * struct rk3x_i2c - private data of the controller + * @adap: corresponding I2C adapter + * @dev: device for this controller + * @soc_data: related soc data struct + * @regs: virtual memory area + * @clk: clock of i2c bus + * @clk_rate_nb: i2c clk rate change notify + * @t: I2C known timing information + * @lock: spinlock for the i2c bus + * @wait: the waitqueue to wait for i2c transfer + * @busy: the condition for the event to wait for + * @msg: current i2c message + * @addr: addr of i2c slave device + * @mode: mode of i2c transfer + * @is_last_msg: flag determines whether it is the last msg in this transfer + * @state: state of i2c transfer + * @processed: byte length which has been send or received + * @error: error code for i2c transfer + */ struct rk3x_i2c { struct i2c_adapter adap; struct device *dev; @@ -116,7 +136,7 @@ struct rk3x_i2c { /* I2C state machine */ enum rk3x_i2c_state state; - unsigned int processed; /* sent/received bytes */ + unsigned int processed; int error; }; -- cgit v1.2.3-59-g8ed1b From e26747bf53b145dc4a64ad518915da8c9a40fef2 Mon Sep 17 00:00:00 2001 From: David Wu Date: Mon, 16 May 2016 21:57:37 +0800 Subject: i2c: rk3x: use struct "rk3x_i2c_calced_timings" The "div_high" and "div_low" values are always used together. Group them into a structure to make it easier to pass them both around. This structure also provides a place for future calculated timings. Signed-off-by: David Wu Reviewed-by: Douglas Anderson Tested-by: Heiko Stuebner Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rk3x.c | 55 +++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 7e45d5101d32..1e2677ae1638 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -75,6 +75,16 @@ enum { #define WAIT_TIMEOUT 1000 /* ms */ #define DEFAULT_SCL_RATE (100 * 1000) /* Hz */ +/** + * struct rk3x_i2c_calced_timings: + * @div_low: Divider output for low + * @div_high: Divider output for high + */ +struct rk3x_i2c_calced_timings { + unsigned long div_low; + unsigned long div_high; +}; + enum rk3x_i2c_state { STATE_IDLE, STATE_START, @@ -454,9 +464,8 @@ out: * Calculate divider values for desired SCL frequency * * @clk_rate: I2C input clock rate - * @t: Known I2C timing information. - * @div_low: Divider output for low - * @div_high: Divider output for high + * @t: Known I2C timing information + * @t_calc: Caculated rk3x private timings that would be written into regs * * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case * a best-effort divider value is returned in divs. If the target rate is @@ -464,8 +473,7 @@ out: */ static int rk3x_i2c_calc_divs(unsigned long clk_rate, struct i2c_timings *t, - unsigned long *div_low, - unsigned long *div_high) + struct rk3x_i2c_calced_timings *t_calc) { unsigned long spec_min_low_ns, spec_min_high_ns; unsigned long spec_setup_start, spec_max_data_hold_ns; @@ -572,8 +580,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, * Time needed to meet hold requirements is important. * Just use that. */ - *div_low = min_low_div; - *div_high = min_high_div; + t_calc->div_low = min_low_div; + t_calc->div_high = min_high_div; } else { /* * We've got to distribute some time among the low and high @@ -602,25 +610,25 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, /* Give low the "ideal" and give high whatever extra is left */ extra_low_div = ideal_low_div - min_low_div; - *div_low = ideal_low_div; - *div_high = min_high_div + (extra_div - extra_low_div); + t_calc->div_low = ideal_low_div; + t_calc->div_high = min_high_div + (extra_div - extra_low_div); } /* * Adjust to the fact that the hardware has an implicit "+1". * NOTE: Above calculations always produce div_low > 0 and div_high > 0. */ - *div_low = *div_low - 1; - *div_high = *div_high - 1; + t_calc->div_low--; + t_calc->div_high--; /* Maximum divider supported by hw is 0xffff */ - if (*div_low > 0xffff) { - *div_low = 0xffff; + if (t_calc->div_low > 0xffff) { + t_calc->div_low = 0xffff; ret = -EINVAL; } - if (*div_high > 0xffff) { - *div_high = 0xffff; + if (t_calc->div_high > 0xffff) { + t_calc->div_high = 0xffff; ret = -EINVAL; } @@ -630,19 +638,21 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate) { struct i2c_timings *t = &i2c->t; - unsigned long div_low, div_high; + struct rk3x_i2c_calced_timings calc; u64 t_low_ns, t_high_ns; int ret; - ret = rk3x_i2c_calc_divs(clk_rate, t, &div_low, &div_high); + ret = rk3x_i2c_calc_divs(clk_rate, t, &calc); WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz); clk_enable(i2c->clk); - i2c_writel(i2c, (div_high << 16) | (div_low & 0xffff), REG_CLKDIV); + i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff), + REG_CLKDIV); clk_disable(i2c->clk); - t_low_ns = div_u64(((u64)div_low + 1) * 8 * 1000000000, clk_rate); - t_high_ns = div_u64(((u64)div_high + 1) * 8 * 1000000000, clk_rate); + t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate); + t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000, + clk_rate); dev_dbg(i2c->dev, "CLK %lukhz, Req %uns, Act low %lluns high %lluns\n", clk_rate / 1000, @@ -672,12 +682,11 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long { struct clk_notifier_data *ndata = data; struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb); - unsigned long div_low, div_high; + struct rk3x_i2c_calced_timings calc; switch (event) { case PRE_RATE_CHANGE: - if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t, - &div_low, &div_high) != 0) + if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t, &calc) != 0) return NOTIFY_STOP; /* scale up */ -- cgit v1.2.3-59-g8ed1b From 69eda367ac4240428b9d16ab0c81113753ea079a Mon Sep 17 00:00:00 2001 From: David Wu Date: Mon, 16 May 2016 21:57:38 +0800 Subject: i2c: rk3x: Remove redundant rk3x_i2c_clean_ipd() rk3x_i2c_setup() gets called directly before rk3x_i2c_start(), and the last thing in setup was to clean the IPD, so no reason to do it at the beginning of start. Signed-off-by: David Wu Reviewed-by: Douglas Anderson Reviewed-by: Heiko Stuebner Tested-by: Heiko Stuebner Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rk3x.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 1e2677ae1638..9eeb4e5312f3 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -174,7 +174,6 @@ static void rk3x_i2c_start(struct rk3x_i2c *i2c) { u32 val; - rk3x_i2c_clean_ipd(i2c); i2c_writel(i2c, REG_INT_START, REG_IEN); /* enable adapter with correct mode, send START condition */ -- cgit v1.2.3-59-g8ed1b From bef358c4fe2efa7467297303cafe973748afda93 Mon Sep 17 00:00:00 2001 From: David Wu Date: Mon, 16 May 2016 21:57:39 +0800 Subject: i2c: rk3x: Change SoC data to not use array Specifying the i2c SoC data in an array provides very little benefit and gets unwieldly / confusing as the array grows since the next bit of code needs to refer to elements in the array by their raw integral index. Let's just create a single 'static const' structure for each SoC so that we can refer to these structures by ID. Signed-off-by: David Wu Reviewed-by: Heiko Stuebner Suggested-by: Douglas Anderson Reviewed-by: Douglas Anderson Tested-by: Heiko Stuebner Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rk3x.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 9eeb4e5312f3..d7a871f9a52d 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -864,17 +864,39 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = { .functionality = rk3x_i2c_func, }; -static struct rk3x_i2c_soc_data soc_data[3] = { - { .grf_offset = 0x154 }, /* rk3066 */ - { .grf_offset = 0x0a4 }, /* rk3188 */ - { .grf_offset = -1 }, /* no I2C switching needed */ +static const struct rk3x_i2c_soc_data rk3066_soc_data = { + .grf_offset = 0x154, +}; + +static const struct rk3x_i2c_soc_data rk3188_soc_data = { + .grf_offset = 0x0a4, +}; + +static const struct rk3x_i2c_soc_data rk3228_soc_data = { + .grf_offset = -1, +}; + +static const struct rk3x_i2c_soc_data rk3288_soc_data = { + .grf_offset = -1, }; static const struct of_device_id rk3x_i2c_match[] = { - { .compatible = "rockchip,rk3066-i2c", .data = (void *)&soc_data[0] }, - { .compatible = "rockchip,rk3188-i2c", .data = (void *)&soc_data[1] }, - { .compatible = "rockchip,rk3228-i2c", .data = (void *)&soc_data[2] }, - { .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] }, + { + .compatible = "rockchip,rk3066-i2c", + .data = (void *)&rk3066_soc_data + }, + { + .compatible = "rockchip,rk3188-i2c", + .data = (void *)&rk3188_soc_data + }, + { + .compatible = "rockchip,rk3228-i2c", + .data = (void *)&rk3228_soc_data + }, + { + .compatible = "rockchip,rk3288-i2c", + .data = (void *)&rk3288_soc_data + }, {}, }; MODULE_DEVICE_TABLE(of, rk3x_i2c_match); -- cgit v1.2.3-59-g8ed1b From b58fd3be40a21a88520d4a3682330abbbc021cc7 Mon Sep 17 00:00:00 2001 From: David Wu Date: Mon, 16 May 2016 22:03:24 +0800 Subject: i2c: rk3x: Move spec timing data to "static const" structs The i2c timing specs are really just constant data. There's no reason to write code to init them, so move them out to structures. This not only is a cleaner solution but it will reduce code duplication when we introduce a new variant of rk3x_i2c_calc_divs() in a future patch. Signed-off-by: David Wu Suggested-by: Douglas Anderson Reviewed-by: Douglas Anderson Tested-by: Heiko Stuebner Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rk3x.c | 83 ++++++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index d7a871f9a52d..97917978ddd9 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -75,6 +75,34 @@ enum { #define WAIT_TIMEOUT 1000 /* ms */ #define DEFAULT_SCL_RATE (100 * 1000) /* Hz */ +/** + * struct i2c_spec_values: + * @min_low_ns: min LOW period of the SCL clock + * @min_high_ns: min HIGH period of the SCL cloc + * @min_setup_start_ns: min set-up time for a repeated START conditio + * @max_data_hold_ns: max data hold time + */ +struct i2c_spec_values { + unsigned long min_low_ns; + unsigned long min_high_ns; + unsigned long min_setup_start_ns; + unsigned long max_data_hold_ns; +}; + +static const struct i2c_spec_values standard_mode_spec = { + .min_low_ns = 4700, + .min_high_ns = 4000, + .min_setup_start_ns = 4700, + .max_data_hold_ns = 3450, +}; + +static const struct i2c_spec_values fast_mode_spec = { + .min_low_ns = 1300, + .min_high_ns = 600, + .min_setup_start_ns = 600, + .max_data_hold_ns = 900, +}; + /** * struct rk3x_i2c_calced_timings: * @div_low: Divider output for low @@ -459,6 +487,21 @@ out: return IRQ_HANDLED; } +/** + * Get timing values of I2C specification + * + * @speed: Desired SCL frequency + * + * Returns: Matched i2c spec values. + */ +static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed) +{ + if (speed <= 100000) + return &standard_mode_spec; + else + return &fast_mode_spec; +} + /** * Calculate divider values for desired SCL frequency * @@ -474,10 +517,6 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, struct i2c_timings *t, struct rk3x_i2c_calced_timings *t_calc) { - unsigned long spec_min_low_ns, spec_min_high_ns; - unsigned long spec_setup_start, spec_max_data_hold_ns; - unsigned long data_hold_buffer_ns; - unsigned long min_low_ns, min_high_ns; unsigned long max_low_ns, min_total_ns; @@ -489,6 +528,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long min_div_for_hold, min_total_div; unsigned long extra_div, extra_low_div, ideal_low_div; + unsigned long data_hold_buffer_ns = 50; + const struct i2c_spec_values *spec; int ret = 0; /* Only support standard-mode and fast-mode */ @@ -511,22 +552,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, * This is because the i2c host on Rockchip holds the data line * for half the low time. */ - if (t->bus_freq_hz <= 100000) { - /* Standard-mode */ - spec_min_low_ns = 4700; - spec_setup_start = 4700; - spec_min_high_ns = 4000; - spec_max_data_hold_ns = 3450; - data_hold_buffer_ns = 50; - } else { - /* Fast-mode */ - spec_min_low_ns = 1300; - spec_setup_start = 600; - spec_min_high_ns = 600; - spec_max_data_hold_ns = 900; - data_hold_buffer_ns = 50; - } - min_high_ns = t->scl_rise_ns + spec_min_high_ns; + spec = rk3x_i2c_get_spec(t->bus_freq_hz); + min_high_ns = t->scl_rise_ns + spec->min_high_ns; /* * Timings for repeated start: @@ -536,14 +563,14 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, * We need to account for those rules in picking our "high" time so * we meet tSU;STA and tHD;STA times. */ - min_high_ns = max(min_high_ns, - DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start) * 1000, 875)); - min_high_ns = max(min_high_ns, - DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start + - t->sda_fall_ns + spec_min_high_ns), 2)); - - min_low_ns = t->scl_fall_ns + spec_min_low_ns; - max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns; + min_high_ns = max(min_high_ns, DIV_ROUND_UP( + (t->scl_rise_ns + spec->min_setup_start_ns) * 1000, 875)); + min_high_ns = max(min_high_ns, DIV_ROUND_UP( + (t->scl_rise_ns + spec->min_setup_start_ns + t->sda_fall_ns + + spec->min_high_ns), 2)); + + min_low_ns = t->scl_fall_ns + spec->min_low_ns; + max_low_ns = spec->max_data_hold_ns * 2 - data_hold_buffer_ns; min_total_ns = min_low_ns + min_high_ns; /* Adjust to avoid overflow */ -- cgit v1.2.3-59-g8ed1b From 7e086c3fc2df099f82371f320fef8d683f050be4 Mon Sep 17 00:00:00 2001 From: David Wu Date: Mon, 16 May 2016 22:05:03 +0800 Subject: i2c: rk3x: add i2c support for rk3399 soc - new method to caculate i2c timings for rk3399: There was an timing issue about "repeated start" time at the I2C controller of version0, controller appears to drop SDA at .875x (7/8) programmed clk high. On version 1 of the controller, the rule(.875x) isn't enough to meet tSU;STA requirements on 100k's Standard-mode. To resolve this issue, sda_update_config, start_setup_config and stop_setup_config for I2C timing information are added, new rules are designed to calculate the timing information at new v1. - pclk and function clk are separated at rk3399 Signed-off-by: David Wu Tested-by: Caesar Wang Tested-by: Heiko Stuebner Reviewed-by: Douglas Anderson [wsa: fixed whitespace issue] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rk3x.c | 294 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 274 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 97917978ddd9..e9ce6a33e8c4 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -58,6 +58,12 @@ enum { #define REG_CON_LASTACK BIT(5) /* 1: send NACK after last received byte */ #define REG_CON_ACTACK BIT(6) /* 1: stop if NACK is received */ +#define REG_CON_TUNING_MASK GENMASK(15, 8) + +#define REG_CON_SDA_CFG(cfg) ((cfg) << 8) +#define REG_CON_STA_CFG(cfg) ((cfg) << 12) +#define REG_CON_STO_CFG(cfg) ((cfg) << 14) + /* REG_MRXADDR bits */ #define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */ @@ -77,40 +83,62 @@ enum { /** * struct i2c_spec_values: + * @min_hold_start_ns: min hold time (repeated) START condition * @min_low_ns: min LOW period of the SCL clock * @min_high_ns: min HIGH period of the SCL cloc * @min_setup_start_ns: min set-up time for a repeated START conditio * @max_data_hold_ns: max data hold time + * @min_data_setup_ns: min data set-up time + * @min_setup_stop_ns: min set-up time for STOP condition + * @min_hold_buffer_ns: min bus free time between a STOP and + * START condition */ struct i2c_spec_values { + unsigned long min_hold_start_ns; unsigned long min_low_ns; unsigned long min_high_ns; unsigned long min_setup_start_ns; unsigned long max_data_hold_ns; + unsigned long min_data_setup_ns; + unsigned long min_setup_stop_ns; + unsigned long min_hold_buffer_ns; }; static const struct i2c_spec_values standard_mode_spec = { + .min_hold_start_ns = 4000, .min_low_ns = 4700, .min_high_ns = 4000, .min_setup_start_ns = 4700, .max_data_hold_ns = 3450, + .min_data_setup_ns = 250, + .min_setup_stop_ns = 4000, + .min_hold_buffer_ns = 4700, }; static const struct i2c_spec_values fast_mode_spec = { + .min_hold_start_ns = 600, .min_low_ns = 1300, .min_high_ns = 600, .min_setup_start_ns = 600, .max_data_hold_ns = 900, + .min_data_setup_ns = 100, + .min_setup_stop_ns = 600, + .min_hold_buffer_ns = 1300, }; /** * struct rk3x_i2c_calced_timings: * @div_low: Divider output for low * @div_high: Divider output for high + * @tuning: Used to adjust setup/hold data time, + * setup/hold start time and setup stop time for + * v1's calc_timings, the tuning should all be 0 + * for old hardware anyone using v0's calc_timings. */ struct rk3x_i2c_calced_timings { unsigned long div_low; unsigned long div_high; + unsigned int tuning; }; enum rk3x_i2c_state { @@ -123,9 +151,12 @@ enum rk3x_i2c_state { /** * @grf_offset: offset inside the grf regmap for setting the i2c type + * @calc_timings: Callback function for i2c timing information calculated */ struct rk3x_i2c_soc_data { int grf_offset; + int (*calc_timings)(unsigned long, struct i2c_timings *, + struct rk3x_i2c_calced_timings *); }; /** @@ -134,7 +165,8 @@ struct rk3x_i2c_soc_data { * @dev: device for this controller * @soc_data: related soc data struct * @regs: virtual memory area - * @clk: clock of i2c bus + * @clk: function clk for rk3399 or function & Bus clks for others + * @pclk: Bus clk for rk3399 * @clk_rate_nb: i2c clk rate change notify * @t: I2C known timing information * @lock: spinlock for the i2c bus @@ -156,6 +188,7 @@ struct rk3x_i2c { /* Hardware resources */ void __iomem *regs; struct clk *clk; + struct clk *pclk; struct notifier_block clk_rate_nb; /* Settings */ @@ -200,12 +233,12 @@ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c) */ static void rk3x_i2c_start(struct rk3x_i2c *i2c) { - u32 val; + u32 val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; i2c_writel(i2c, REG_INT_START, REG_IEN); /* enable adapter with correct mode, send START condition */ - val = REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START; + val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START; /* if we want to react to NACK, set ACTACK bit */ if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) @@ -246,7 +279,8 @@ static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error) * get the intended effect by resetting its internal state * and issuing an ordinary START. */ - i2c_writel(i2c, 0, REG_CON); + ctrl = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; + i2c_writel(i2c, ctrl, REG_CON); /* signal that we are finished with the current msg */ wake_up(&i2c->wait); @@ -513,9 +547,9 @@ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed) * a best-effort divider value is returned in divs. If the target rate is * too high, we silently use the highest possible rate. */ -static int rk3x_i2c_calc_divs(unsigned long clk_rate, - struct i2c_timings *t, - struct rk3x_i2c_calced_timings *t_calc) +static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate, + struct i2c_timings *t, + struct rk3x_i2c_calced_timings *t_calc) { unsigned long min_low_ns, min_high_ns; unsigned long max_low_ns, min_total_ns; @@ -661,20 +695,191 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, return ret; } +/** + * Calculate timing values for desired SCL frequency + * + * @clk_rate: I2C input clock rate + * @t: Known I2C timing information + * @t_calc: Caculated rk3x private timings that would be written into regs + * + * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case + * a best-effort divider value is returned in divs. If the target rate is + * too high, we silently use the highest possible rate. + * The following formulas are v1's method to calculate timings. + * + * l = divl + 1; + * h = divh + 1; + * s = sda_update_config + 1; + * u = start_setup_config + 1; + * p = stop_setup_config + 1; + * T = Tclk_i2c; + * + * tHigh = 8 * h * T; + * tLow = 8 * l * T; + * + * tHD;sda = (l * s + 1) * T; + * tSU;sda = [(8 - s) * l + 1] * T; + * tI2C = 8 * (l + h) * T; + * + * tSU;sta = (8h * u + 1) * T; + * tHD;sta = [8h * (u + 1) - 1] * T; + * tSU;sto = (8h * p + 1) * T; + */ +static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate, + struct i2c_timings *t, + struct rk3x_i2c_calced_timings *t_calc) +{ + unsigned long min_low_ns, min_high_ns, min_total_ns; + unsigned long min_setup_start_ns, min_setup_data_ns; + unsigned long min_setup_stop_ns, max_hold_data_ns; + + unsigned long clk_rate_khz, scl_rate_khz; + + unsigned long min_low_div, min_high_div; + + unsigned long min_div_for_hold, min_total_div; + unsigned long extra_div, extra_low_div; + unsigned long sda_update_cfg, stp_sta_cfg, stp_sto_cfg; + + const struct i2c_spec_values *spec; + int ret = 0; + + /* Support standard-mode and fast-mode */ + if (WARN_ON(t->bus_freq_hz > 400000)) + t->bus_freq_hz = 400000; + + /* prevent scl_rate_khz from becoming 0 */ + if (WARN_ON(t->bus_freq_hz < 1000)) + t->bus_freq_hz = 1000; + + /* + * min_low_ns: The minimum number of ns we need to hold low to + * meet I2C specification, should include fall time. + * min_high_ns: The minimum number of ns we need to hold high to + * meet I2C specification, should include rise time. + */ + spec = rk3x_i2c_get_spec(t->bus_freq_hz); + + /* calculate min-divh and min-divl */ + clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000); + scl_rate_khz = t->bus_freq_hz / 1000; + min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8); + + min_high_ns = t->scl_rise_ns + spec->min_high_ns; + min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000); + + min_low_ns = t->scl_fall_ns + spec->min_low_ns; + min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000); + + /* + * Final divh and divl must be greater than 0, otherwise the + * hardware would not output the i2c clk. + */ + min_high_div = (min_high_div < 1) ? 2 : min_high_div; + min_low_div = (min_low_div < 1) ? 2 : min_low_div; + + /* These are the min dividers needed for min hold times. */ + min_div_for_hold = (min_low_div + min_high_div); + min_total_ns = min_low_ns + min_high_ns; + + /* + * This is the maximum divider so we don't go over the maximum. + * We don't round up here (we round down) since this is a maximum. + */ + if (min_div_for_hold >= min_total_div) { + /* + * Time needed to meet hold requirements is important. + * Just use that. + */ + t_calc->div_low = min_low_div; + t_calc->div_high = min_high_div; + } else { + /* + * We've got to distribute some time among the low and high + * so we don't run too fast. + * We'll try to split things up by the scale of min_low_div and + * min_high_div, biasing slightly towards having a higher div + * for low (spend more time low). + */ + extra_div = min_total_div - min_div_for_hold; + extra_low_div = DIV_ROUND_UP(min_low_div * extra_div, + min_div_for_hold); + + t_calc->div_low = min_low_div + extra_low_div; + t_calc->div_high = min_high_div + (extra_div - extra_low_div); + } + + /* + * calculate sda data hold count by the rules, data_upd_st:3 + * is a appropriate value to reduce calculated times. + */ + for (sda_update_cfg = 3; sda_update_cfg > 0; sda_update_cfg--) { + max_hold_data_ns = DIV_ROUND_UP((sda_update_cfg + * (t_calc->div_low) + 1) + * 1000000, clk_rate_khz); + min_setup_data_ns = DIV_ROUND_UP(((8 - sda_update_cfg) + * (t_calc->div_low) + 1) + * 1000000, clk_rate_khz); + if ((max_hold_data_ns < spec->max_data_hold_ns) && + (min_setup_data_ns > spec->min_data_setup_ns)) + break; + } + + /* calculate setup start config */ + min_setup_start_ns = t->scl_rise_ns + spec->min_setup_start_ns; + stp_sta_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns + - 1000000, 8 * 1000000 * (t_calc->div_high)); + + /* calculate setup stop config */ + min_setup_stop_ns = t->scl_rise_ns + spec->min_setup_stop_ns; + stp_sto_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_stop_ns + - 1000000, 8 * 1000000 * (t_calc->div_high)); + + t_calc->tuning = REG_CON_SDA_CFG(--sda_update_cfg) | + REG_CON_STA_CFG(--stp_sta_cfg) | + REG_CON_STO_CFG(--stp_sto_cfg); + + t_calc->div_low--; + t_calc->div_high--; + + /* Maximum divider supported by hw is 0xffff */ + if (t_calc->div_low > 0xffff) { + t_calc->div_low = 0xffff; + ret = -EINVAL; + } + + if (t_calc->div_high > 0xffff) { + t_calc->div_high = 0xffff; + ret = -EINVAL; + } + + return ret; +} + static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate) { struct i2c_timings *t = &i2c->t; struct rk3x_i2c_calced_timings calc; u64 t_low_ns, t_high_ns; + unsigned long flags; + u32 val; int ret; - ret = rk3x_i2c_calc_divs(clk_rate, t, &calc); + ret = i2c->soc_data->calc_timings(clk_rate, t, &calc); WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz); - clk_enable(i2c->clk); + clk_enable(i2c->pclk); + + spin_lock_irqsave(&i2c->lock, flags); + val = i2c_readl(i2c, REG_CON); + val &= ~REG_CON_TUNING_MASK; + val |= calc.tuning; + i2c_writel(i2c, val, REG_CON); i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff), REG_CLKDIV); - clk_disable(i2c->clk); + spin_unlock_irqrestore(&i2c->lock, flags); + + clk_disable(i2c->pclk); t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate); t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000, @@ -712,7 +917,13 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long switch (event) { case PRE_RATE_CHANGE: - if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t, &calc) != 0) + /* + * Try the calculation (but don't store the result) ahead of + * time to see if we need to block the clock change. Timings + * shouldn't actually take effect until rk3x_i2c_adapt_div(). + */ + if (i2c->soc_data->calc_timings(ndata->new_rate, &i2c->t, + &calc) != 0) return NOTIFY_STOP; /* scale up */ @@ -822,12 +1033,14 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap, { struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data; unsigned long timeout, flags; + u32 val; int ret = 0; int i; spin_lock_irqsave(&i2c->lock, flags); clk_enable(i2c->clk); + clk_enable(i2c->pclk); i2c->is_last_msg = false; @@ -861,7 +1074,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap, /* Force a STOP condition without interrupt */ i2c_writel(i2c, 0, REG_IEN); - i2c_writel(i2c, REG_CON_EN | REG_CON_STOP, REG_CON); + val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; + val |= REG_CON_EN | REG_CON_STOP; + i2c_writel(i2c, val, REG_CON); i2c->state = STATE_IDLE; @@ -875,7 +1090,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap, } } + clk_disable(i2c->pclk); clk_disable(i2c->clk); + spin_unlock_irqrestore(&i2c->lock, flags); return ret < 0 ? ret : num; @@ -893,18 +1110,27 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = { static const struct rk3x_i2c_soc_data rk3066_soc_data = { .grf_offset = 0x154, + .calc_timings = rk3x_i2c_v0_calc_timings, }; static const struct rk3x_i2c_soc_data rk3188_soc_data = { .grf_offset = 0x0a4, + .calc_timings = rk3x_i2c_v0_calc_timings, }; static const struct rk3x_i2c_soc_data rk3228_soc_data = { .grf_offset = -1, + .calc_timings = rk3x_i2c_v0_calc_timings, }; static const struct rk3x_i2c_soc_data rk3288_soc_data = { .grf_offset = -1, + .calc_timings = rk3x_i2c_v0_calc_timings, +}; + +static const struct rk3x_i2c_soc_data rk3399_soc_data = { + .grf_offset = -1, + .calc_timings = rk3x_i2c_v1_calc_timings, }; static const struct of_device_id rk3x_i2c_match[] = { @@ -924,6 +1150,10 @@ static const struct of_device_id rk3x_i2c_match[] = { .compatible = "rockchip,rk3288-i2c", .data = (void *)&rk3288_soc_data }, + { + .compatible = "rockchip,rk3399-i2c", + .data = (void *)&rk3399_soc_data + }, {}, }; MODULE_DEVICE_TABLE(of, rk3x_i2c_match); @@ -963,12 +1193,6 @@ static int rk3x_i2c_probe(struct platform_device *pdev) spin_lock_init(&i2c->lock); init_waitqueue_head(&i2c->wait); - i2c->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(i2c->clk)) { - dev_err(&pdev->dev, "cannot get clock\n"); - return PTR_ERR(i2c->clk); - } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); i2c->regs = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(i2c->regs)) @@ -1022,17 +1246,44 @@ static int rk3x_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); + if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) { + /* Only one clock to use for bus clock and peripheral clock */ + i2c->clk = devm_clk_get(&pdev->dev, NULL); + i2c->pclk = i2c->clk; + } else { + i2c->clk = devm_clk_get(&pdev->dev, "i2c"); + i2c->pclk = devm_clk_get(&pdev->dev, "pclk"); + } + + if (IS_ERR(i2c->clk)) { + ret = PTR_ERR(i2c->clk); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "Can't get bus clk: %d\n", ret); + return ret; + } + if (IS_ERR(i2c->pclk)) { + ret = PTR_ERR(i2c->pclk); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "Can't get periph clk: %d\n", ret); + return ret; + } + ret = clk_prepare(i2c->clk); if (ret < 0) { - dev_err(&pdev->dev, "Could not prepare clock\n"); + dev_err(&pdev->dev, "Can't prepare bus clk: %d\n", ret); return ret; } + ret = clk_prepare(i2c->pclk); + if (ret < 0) { + dev_err(&pdev->dev, "Can't prepare periph clock: %d\n", ret); + goto err_clk; + } i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb; ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb); if (ret != 0) { dev_err(&pdev->dev, "Unable to register clock notifier\n"); - goto err_clk; + goto err_pclk; } clk_rate = clk_get_rate(i2c->clk); @@ -1050,6 +1301,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev) err_clk_notifier: clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb); +err_pclk: + clk_unprepare(i2c->pclk); err_clk: clk_unprepare(i2c->clk); return ret; @@ -1062,6 +1315,7 @@ static int rk3x_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&i2c->adap); clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb); + clk_unprepare(i2c->pclk); clk_unprepare(i2c->clk); return 0; -- cgit v1.2.3-59-g8ed1b From a02f3d081a79ec702b85b9c1a91edf770cf1eab2 Mon Sep 17 00:00:00 2001 From: David Wu Date: Mon, 16 May 2016 22:06:29 +0800 Subject: i2c: rk3x: support fast-mode plus for rk3399 Implement fast mode plus that allows bus speeds of up to 1MHz. Signed-off-by: David Wu Reviewed-by: Douglas Anderson Tested-by: Caesar Wang Reviewed-by: Heiko Stuebner Tested-by: Heiko Stuebner Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-rk3x.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index e9ce6a33e8c4..2bc8b01153d6 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -126,6 +126,17 @@ static const struct i2c_spec_values fast_mode_spec = { .min_hold_buffer_ns = 1300, }; +static const struct i2c_spec_values fast_mode_plus_spec = { + .min_hold_start_ns = 260, + .min_low_ns = 500, + .min_high_ns = 260, + .min_setup_start_ns = 260, + .max_data_hold_ns = 400, + .min_data_setup_ns = 50, + .min_setup_stop_ns = 260, + .min_hold_buffer_ns = 500, +}; + /** * struct rk3x_i2c_calced_timings: * @div_low: Divider output for low @@ -532,8 +543,10 @@ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed) { if (speed <= 100000) return &standard_mode_spec; - else + else if (speed <= 400000) return &fast_mode_spec; + else + return &fast_mode_plus_spec; } /** @@ -744,9 +757,9 @@ static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate, const struct i2c_spec_values *spec; int ret = 0; - /* Support standard-mode and fast-mode */ - if (WARN_ON(t->bus_freq_hz > 400000)) - t->bus_freq_hz = 400000; + /* Support standard-mode, fast-mode and fast-mode plus */ + if (WARN_ON(t->bus_freq_hz > 1000000)) + t->bus_freq_hz = 1000000; /* prevent scl_rate_khz from becoming 0 */ if (WARN_ON(t->bus_freq_hz < 1000)) -- cgit v1.2.3-59-g8ed1b From 685983f4decc5fa5700a0ab083859a2fe59acf10 Mon Sep 17 00:00:00 2001 From: Sricharan R Date: Fri, 10 Jun 2016 23:38:19 +0530 Subject: i2c: qup: Fix broken dma when CONFIG_DEBUG_SG is enabled With CONFIG_DEBUG_SG is enabled and when dma mode is used, below dump is seen, ------------[ cut here ]------------ kernel BUG at include/linux/scatterlist.h:140! Internal error: Oops - BUG: 0 [#1] PREEMPT SMP Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.4.0-00459-g9f087b9-dirty #7 Hardware name: Qualcomm Technologies, Inc. APQ 8016 SBC (DT) task: ffffffc036868000 ti: ffffffc036870000 task.ti: ffffffc036870000 PC is at qup_sg_set_buf.isra.13+0x138/0x154 LR is at qup_sg_set_buf.isra.13+0x50/0x154 pc : [] lr : [] pstate: 60000145 sp : ffffffc0368735c0 x29: ffffffc0368735c0 x28: ffffffc036873752 x27: ffffffc035233018 x26: ffffffc000c4e000 x25: 0000000000000000 x24: 0000000000000004 x23: 0000000000000000 x22: ffffffc035233668 x21: ffffff80004e3000 x20: ffffffc0352e0018 x19: 0000004000000000 x18: 0000000000000028 x17: 0000000000000004 x16: ffffffc0017a39c8 x15: 0000000000001cdf x14: ffffffc0019929d8 x13: ffffffc0352e0018 x12: 0000000000000000 x11: 0000000000000001 x10: 0000000000000001 x9 : ffffffc0012b2d70 x8 : ffffff80004e3000 x7 : 0000000000000018 x6 : 0000000030000000 x5 : ffffffc00199f018 x4 : ffffffc035233018 x3 : 0000000000000004 x2 : 00000000c0000000 x1 : 0000000000000003 x0 : 0000000000000000 Process swapper/0 (pid: 1, stack limit = 0xffffffc036870020) Stack: (0xffffffc0368735c0 to 0xffffffc036874000) sg_set_bug expects that the buf parameter passed in should be from lowmem and a valid pageframe. This is not true for pages from dma_alloc_coherent which can be carveouts, hence the check fails. Change allocation of sg buffers from dma_coherent memory to kzalloc to fix the issue. Note that now dma_map/unmap is used to make the kzalloc'ed buffers coherent before passing it to the dmaengine. Signed-off-by: Sricharan R Reviewed-by: Andy Gross Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 51 +++++++++++++------------------------------- 1 file changed, 15 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index cc6439ab3f71..43adc2d8759b 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -585,8 +585,8 @@ static void qup_i2c_bam_cb(void *data) } static int qup_sg_set_buf(struct scatterlist *sg, void *buf, - struct qup_i2c_tag *tg, unsigned int buflen, - struct qup_i2c_dev *qup, int map, int dir) + unsigned int buflen, struct qup_i2c_dev *qup, + int dir) { int ret; @@ -595,9 +595,6 @@ static int qup_sg_set_buf(struct scatterlist *sg, void *buf, if (!ret) return -EINVAL; - if (!map) - sg_dma_address(sg) = tg->addr + ((u8 *)buf - tg->start); - return 0; } @@ -670,16 +667,15 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, /* scratch buf to read the start and len tags */ ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++], &qup->brx.tag.start[0], - &qup->brx.tag, - 2, qup, 0, 0); + 2, qup, DMA_FROM_DEVICE); if (ret) return ret; ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++], &msg->buf[limit * i], - NULL, tlen, qup, - 1, DMA_FROM_DEVICE); + tlen, qup, + DMA_FROM_DEVICE); if (ret) return ret; @@ -688,7 +684,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, } ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], &qup->start_tag.start[off], - &qup->start_tag, len, qup, 0, 0); + len, qup, DMA_TO_DEVICE); if (ret) return ret; @@ -696,8 +692,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, /* scratch buf to read the BAM EOT and FLUSH tags */ ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++], &qup->brx.tag.start[0], - &qup->brx.tag, 2, - qup, 0, 0); + 2, qup, DMA_FROM_DEVICE); if (ret) return ret; } else { @@ -709,17 +704,15 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, len = qup_i2c_set_tags(tags, qup, msg, 1); ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], - tags, - &qup->start_tag, len, - qup, 0, 0); + tags, len, + qup, DMA_TO_DEVICE); if (ret) return ret; tx_len += len; ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], &msg->buf[limit * i], - NULL, tlen, qup, 1, - DMA_TO_DEVICE); + tlen, qup, DMA_TO_DEVICE); if (ret) return ret; i++; @@ -738,8 +731,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, QUP_BAM_FLUSH_STOP; ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], &qup->btx.tag.start[0], - &qup->btx.tag, len, - qup, 0, 0); + len, qup, DMA_TO_DEVICE); if (ret) return ret; tx_nents += 1; @@ -1407,27 +1399,21 @@ static int qup_i2c_probe(struct platform_device *pdev) /* 2 tag bytes for each block + 5 for start, stop tags */ size = blocks * 2 + 5; - qup->dpool = dma_pool_create("qup_i2c-dma-pool", &pdev->dev, - size, 4, 0); - qup->start_tag.start = dma_pool_alloc(qup->dpool, GFP_KERNEL, - &qup->start_tag.addr); + qup->start_tag.start = devm_kzalloc(&pdev->dev, + size, GFP_KERNEL); if (!qup->start_tag.start) { ret = -ENOMEM; goto fail_dma; } - qup->brx.tag.start = dma_pool_alloc(qup->dpool, - GFP_KERNEL, - &qup->brx.tag.addr); + qup->brx.tag.start = devm_kzalloc(&pdev->dev, 2, GFP_KERNEL); if (!qup->brx.tag.start) { ret = -ENOMEM; goto fail_dma; } - qup->btx.tag.start = dma_pool_alloc(qup->dpool, - GFP_KERNEL, - &qup->btx.tag.addr); + qup->btx.tag.start = devm_kzalloc(&pdev->dev, 2, GFP_KERNEL); if (!qup->btx.tag.start) { ret = -ENOMEM; goto fail_dma; @@ -1566,13 +1552,6 @@ static int qup_i2c_remove(struct platform_device *pdev) struct qup_i2c_dev *qup = platform_get_drvdata(pdev); if (qup->is_dma) { - dma_pool_free(qup->dpool, qup->start_tag.start, - qup->start_tag.addr); - dma_pool_free(qup->dpool, qup->brx.tag.start, - qup->brx.tag.addr); - dma_pool_free(qup->dpool, qup->btx.tag.start, - qup->btx.tag.addr); - dma_pool_destroy(qup->dpool); dma_release_channel(qup->btx.dma); dma_release_channel(qup->brx.dma); } -- cgit v1.2.3-59-g8ed1b From fbf9921f8b35d9b241a1ee0008d310a3a5390273 Mon Sep 17 00:00:00 2001 From: Sricharan R Date: Fri, 10 Jun 2016 23:38:21 +0530 Subject: i2c: qup: Fix error handling Among the bus errors reported from the QUP_MASTER_STATUS register only NACK is considered and transfer gets suspended, while other errors are ignored. Correct this and suspend the transfer for other errors as well. This avoids unnecessary 'timeouts' which happens when waiting for events that would never happen when there is already an error condition on the bus. Also the error handling procedure should be the same for both NACK and other bus errors in case of dma mode. So correct that as well. Signed-off-by: Sricharan R Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 76 ++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 43adc2d8759b..3e5fac88376d 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -310,6 +310,7 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, u32 opflags; u32 status; u32 shift = __ffs(op); + int ret = 0; len *= qup->one_byte_t; /* timeout after a wait of twice the max time */ @@ -321,18 +322,28 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, if (((opflags & op) >> shift) == val) { if ((op == QUP_OUT_NOT_EMPTY) && qup->is_last) { - if (!(status & I2C_STATUS_BUS_ACTIVE)) - return 0; + if (!(status & I2C_STATUS_BUS_ACTIVE)) { + ret = 0; + goto done; + } } else { - return 0; + ret = 0; + goto done; } } - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; - + if (time_after(jiffies, timeout)) { + ret = -ETIMEDOUT; + goto done; + } usleep_range(len, len * 2); } + +done: + if (qup->bus_err || qup->qup_err) + ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO; + + return ret; } static void qup_i2c_set_write_mode_v2(struct qup_i2c_dev *qup, @@ -793,39 +804,35 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, } if (ret || qup->bus_err || qup->qup_err) { - if (qup->bus_err & QUP_I2C_NACK_FLAG) { - msg--; - dev_err(qup->dev, "NACK from %x\n", msg->addr); - ret = -EIO; + if (qup_i2c_change_state(qup, QUP_RUN_STATE)) { + dev_err(qup->dev, "change to run state timed out"); + goto desc_err; + } - if (qup_i2c_change_state(qup, QUP_RUN_STATE)) { - dev_err(qup->dev, "change to run state timed out"); - return ret; - } + if (rx_nents) + writel(QUP_BAM_INPUT_EOT, + qup->base + QUP_OUT_FIFO_BASE); - if (rx_nents) - writel(QUP_BAM_INPUT_EOT, - qup->base + QUP_OUT_FIFO_BASE); + writel(QUP_BAM_FLUSH_STOP, qup->base + QUP_OUT_FIFO_BASE); - writel(QUP_BAM_FLUSH_STOP, - qup->base + QUP_OUT_FIFO_BASE); + qup_i2c_flush(qup); - qup_i2c_flush(qup); + /* wait for remaining interrupts to occur */ + if (!wait_for_completion_timeout(&qup->xfer, HZ)) + dev_err(qup->dev, "flush timed out\n"); - /* wait for remaining interrupts to occur */ - if (!wait_for_completion_timeout(&qup->xfer, HZ)) - dev_err(qup->dev, "flush timed out\n"); + qup_i2c_rel_dma(qup); - qup_i2c_rel_dma(qup); - } + ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO; } +desc_err: dma_unmap_sg(qup->dev, qup->btx.sg, tx_nents, DMA_TO_DEVICE); if (rx_nents) dma_unmap_sg(qup->dev, qup->brx.sg, rx_nents, DMA_FROM_DEVICE); -desc_err: + return ret; } @@ -841,9 +848,6 @@ static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, if (ret) goto out; - qup->bus_err = 0; - qup->qup_err = 0; - writel(0, qup->base + QUP_MX_INPUT_CNT); writel(0, qup->base + QUP_MX_OUTPUT_CNT); @@ -881,12 +885,8 @@ static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup, ret = -ETIMEDOUT; } - if (qup->bus_err || qup->qup_err) { - if (qup->bus_err & QUP_I2C_NACK_FLAG) { - dev_err(qup->dev, "NACK from %x\n", msg->addr); - ret = -EIO; - } - } + if (qup->bus_err || qup->qup_err) + ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO; return ret; } @@ -1178,6 +1178,9 @@ static int qup_i2c_xfer(struct i2c_adapter *adap, if (ret < 0) goto out; + qup->bus_err = 0; + qup->qup_err = 0; + writel(1, qup->base + QUP_SW_RESET); ret = qup_i2c_poll_state(qup, QUP_RESET_STATE); if (ret) @@ -1227,6 +1230,9 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap, struct qup_i2c_dev *qup = i2c_get_adapdata(adap); int ret, len, idx = 0, use_dma = 0; + qup->bus_err = 0; + qup->qup_err = 0; + ret = pm_runtime_get_sync(qup->dev); if (ret < 0) goto out; -- cgit v1.2.3-59-g8ed1b From 0130944bc1d212ad4b33584424d56fe7c049eb65 Mon Sep 17 00:00:00 2001 From: Naveen Kaje Date: Thu, 5 May 2016 12:33:17 -0600 Subject: i2c: qup: use address helper function in read transfer qup_i2c_issue_read() derives the address from i2c_msg. This called in the read path when I2C_M_RD flag is set. Therefore, use the 8 bit address helper function. Signed-off-by: Naveen Kaje Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 3e5fac88376d..69849a95d479 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -1012,7 +1012,7 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg) { u32 addr, len, val; - addr = (msg->addr << 1) | 1; + addr = i2c_8bit_addr_from_msg(msg); /* 0 is used to specify a length 256 (QUP_READ_LIMIT) */ len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len; -- cgit v1.2.3-59-g8ed1b From d0bcd8df9aea2bcdbfcb074d408bdc7136031bc5 Mon Sep 17 00:00:00 2001 From: Weifeng Voon Date: Fri, 17 Jun 2016 09:46:35 +0800 Subject: i2c: designware: Use transfer timeout from ioctl I2C_TIMEOUT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows applications to set the transfer timeout in 10ms increments via ioctl I2C_TIMEOUT. Signed-off-by: Weifeng Voon Acked-by: Jarkko Nikula Acked-by: Uwe Kleine-König Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 99b54be6ba73..c6922b806fb7 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -663,7 +663,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) i2c_dw_xfer_init(dev); /* wait for tx to complete */ - if (!wait_for_completion_timeout(&dev->cmd_complete, HZ)) { + if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) { dev_err(dev->dev, "controller timed out\n"); /* i2c_dw_init implicitly disables the adapter */ i2c_dw_init(dev); -- cgit v1.2.3-59-g8ed1b From f41021bba68371b7ff4bcb0fc764473de1782c14 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 10 Dec 2015 13:48:44 +0200 Subject: i2c: designware: Allow build Baytrail semaphore support when IOSF_MBI=m I believe i2c-designware-baytrail.c doesn't have strict dependency that Intel SoC IOSF Sideband support must be always built-in in order to be able to compile support for Intel Baytrail I2C bus sharing HW semaphore. Redefine build dependencies so that CONFIG_IOSF_MBI=y is required only when CONFIG_I2C_DESIGNWARE_PLATFORM is built-in. Signed-off-by: Jarkko Nikula Acked-by: David Box Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index f167021b8c21..efa3d9bfe294 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -490,7 +490,9 @@ config I2C_DESIGNWARE_PCI config I2C_DESIGNWARE_BAYTRAIL bool "Intel Baytrail I2C semaphore support" - depends on I2C_DESIGNWARE_PLATFORM && IOSF_MBI=y && ACPI + depends on ACPI + depends on (I2C_DESIGNWARE_PLATFORM=m && IOSF_MBI) || \ + (I2C_DESIGNWARE_PLATFORM=y && IOSF_MBI=y) help This driver enables managed host access to the PMIC I2C bus on select Intel BayTrail platforms using the X-Powers AXP288 PMIC. It allows -- cgit v1.2.3-59-g8ed1b From ed1bf03470b8c666d6d0d81e8faa8cbb32a5656e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Jun 2016 18:05:05 +0300 Subject: i2c: designware-pci: Make bus number allocation robust On some platforms, such as Intel Medfield, the I2C slave devices are enumerated through SFI tables where bus numbering is expected to be defined in the OS. Make the bus number allocation robust for such platforms. Signed-off-by: Andy Shevchenko Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-core.h | 1 + drivers/i2c/busses/i2c-designware-pcidrv.c | 87 +++++++++++++----------------- 2 files changed, 38 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index cd409e7fbc71..38493a7142ad 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -26,6 +26,7 @@ #define DW_IC_CON_MASTER 0x1 #define DW_IC_CON_SPEED_STD 0x2 #define DW_IC_CON_SPEED_FAST 0x4 +#define DW_IC_CON_SPEED_MASK 0x6 #define DW_IC_CON_10BITADDR_MASTER 0x10 #define DW_IC_CON_RESTART_EN 0x20 #define DW_IC_CON_SLAVE_DISABLE 0x40 diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 7368be000c96..586c8d85b4eb 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -41,13 +41,7 @@ #define DRIVER_NAME "i2c-designware-pci" enum dw_pci_ctl_id_t { - medfield_0, - medfield_1, - medfield_2, - medfield_3, - medfield_4, - medfield_5, - + medfield, baytrail, haswell, }; @@ -68,6 +62,7 @@ struct dw_pci_controller { u32 clk_khz; u32 functionality; struct dw_scl_sda_cfg *scl_sda_cfg; + int (*setup)(struct pci_dev *pdev, struct dw_pci_controller *c); }; #define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \ @@ -98,48 +93,33 @@ static struct dw_scl_sda_cfg hsw_config = { .sda_hold = 0x9, }; +static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c) +{ + switch (pdev->device) { + case 0x0817: + c->bus_cfg &= ~DW_IC_CON_SPEED_MASK; + c->bus_cfg |= DW_IC_CON_SPEED_STD; + case 0x0818: + case 0x0819: + c->bus_num = pdev->device - 0x817 + 3; + return 0; + case 0x082C: + case 0x082D: + case 0x082E: + c->bus_num = pdev->device - 0x82C + 0; + return 0; + } + return -ENODEV; +} + static struct dw_pci_controller dw_pci_controllers[] = { - [medfield_0] = { - .bus_num = 0, - .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, - .tx_fifo_depth = 32, - .rx_fifo_depth = 32, - .clk_khz = 25000, - }, - [medfield_1] = { - .bus_num = 1, - .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, - .tx_fifo_depth = 32, - .rx_fifo_depth = 32, - .clk_khz = 25000, - }, - [medfield_2] = { - .bus_num = 2, - .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, - .tx_fifo_depth = 32, - .rx_fifo_depth = 32, - .clk_khz = 25000, - }, - [medfield_3] = { - .bus_num = 3, - .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD, - .tx_fifo_depth = 32, - .rx_fifo_depth = 32, - .clk_khz = 25000, - }, - [medfield_4] = { - .bus_num = 4, - .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, - .tx_fifo_depth = 32, - .rx_fifo_depth = 32, - .clk_khz = 25000, - }, - [medfield_5] = { - .bus_num = 5, + [medfield] = { + .bus_num = -1, .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, .tx_fifo_depth = 32, .rx_fifo_depth = 32, .clk_khz = 25000, + .setup = mfld_setup, }, [baytrail] = { .bus_num = -1, @@ -224,6 +204,13 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, dev->base = pcim_iomap_table(pdev)[0]; dev->dev = &pdev->dev; dev->irq = pdev->irq; + + if (controller->setup) { + r = controller->setup(pdev, controller); + if (r) + return r; + } + dev->functionality = controller->functionality | DW_DEFAULT_FUNCTIONALITY; @@ -276,12 +263,12 @@ MODULE_ALIAS("i2c_designware-pci"); static const struct pci_device_id i2_designware_pci_ids[] = { /* Medfield */ - { PCI_VDEVICE(INTEL, 0x0817), medfield_3 }, - { PCI_VDEVICE(INTEL, 0x0818), medfield_4 }, - { PCI_VDEVICE(INTEL, 0x0819), medfield_5 }, - { PCI_VDEVICE(INTEL, 0x082C), medfield_0 }, - { PCI_VDEVICE(INTEL, 0x082D), medfield_1 }, - { PCI_VDEVICE(INTEL, 0x082E), medfield_2 }, + { PCI_VDEVICE(INTEL, 0x0817), medfield }, + { PCI_VDEVICE(INTEL, 0x0818), medfield }, + { PCI_VDEVICE(INTEL, 0x0819), medfield }, + { PCI_VDEVICE(INTEL, 0x082C), medfield }, + { PCI_VDEVICE(INTEL, 0x082D), medfield }, + { PCI_VDEVICE(INTEL, 0x082E), medfield }, /* Baytrail */ { PCI_VDEVICE(INTEL, 0x0F41), baytrail }, { PCI_VDEVICE(INTEL, 0x0F42), baytrail }, -- cgit v1.2.3-59-g8ed1b From b20551c184f5e9ebe75e385fd5af74640be1ec31 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Jun 2016 18:05:06 +0300 Subject: i2c: designware-pci: Introduce Merrifield support This patch enables I2C controllers found on Intel Edison board. Signed-off-by: Andy Shevchenko Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 39 ++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 586c8d85b4eb..a7aab105f73b 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -42,6 +42,7 @@ enum dw_pci_ctl_id_t { medfield, + merrifield, baytrail, haswell, }; @@ -75,6 +76,14 @@ struct dw_pci_controller { I2C_FUNC_SMBUS_WORD_DATA | \ I2C_FUNC_SMBUS_I2C_BLOCK) +/* Merrifield HCNT/LCNT/SDA hold time */ +static struct dw_scl_sda_cfg mrfld_config = { + .ss_hcnt = 0x2f8, + .fs_hcnt = 0x87, + .ss_lcnt = 0x37b, + .fs_lcnt = 0x10a, +}; + /* BayTrail HCNT/LCNT/SDA hold time */ static struct dw_scl_sda_cfg byt_config = { .ss_hcnt = 0x200, @@ -112,6 +121,25 @@ static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c) return -ENODEV; } +static int mrfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c) +{ + /* + * On Intel Merrifield the i2c busses are enumerated [1..7]. So, we add + * 1 to shift the default range. Besides that the first PCI slot + * provides 4 functions, that's why we have to add 0 to the head slot + * and 4 to the tail one. + */ + switch (PCI_SLOT(pdev->devfn)) { + case 8: + c->bus_num = PCI_FUNC(pdev->devfn) + 0 + 1; + return 0; + case 9: + c->bus_num = PCI_FUNC(pdev->devfn) + 4 + 1; + return 0; + } + return -ENODEV; +} + static struct dw_pci_controller dw_pci_controllers[] = { [medfield] = { .bus_num = -1, @@ -121,6 +149,14 @@ static struct dw_pci_controller dw_pci_controllers[] = { .clk_khz = 25000, .setup = mfld_setup, }, + [merrifield] = { + .bus_num = -1, + .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, + .tx_fifo_depth = 64, + .rx_fifo_depth = 64, + .scl_sda_cfg = &mrfld_config, + .setup = mrfld_setup, + }, [baytrail] = { .bus_num = -1, .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, @@ -269,6 +305,9 @@ static const struct pci_device_id i2_designware_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x082C), medfield }, { PCI_VDEVICE(INTEL, 0x082D), medfield }, { PCI_VDEVICE(INTEL, 0x082E), medfield }, + /* Merrifield */ + { PCI_VDEVICE(INTEL, 0x1195), merrifield }, + { PCI_VDEVICE(INTEL, 0x1196), merrifield }, /* Baytrail */ { PCI_VDEVICE(INTEL, 0x0F41), baytrail }, { PCI_VDEVICE(INTEL, 0x0F42), baytrail }, -- cgit v1.2.3-59-g8ed1b From 45bc35ef0d14423cb3fbdba14112261f387d536e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Jun 2016 18:05:07 +0300 Subject: i2c: designware-pci: Sort header block alphabetically Simply sort header block alphabetically. While here fix an indentation in one place and update a copyright line for Intel. Signed-off-by: Andy Shevchenko Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index a7aab105f73b..b66c31acb184 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -6,7 +6,7 @@ * Copyright (C) 2006 Texas Instruments. * Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2009 Provigent Ltd. - * Copyright (C) 2011, 2015 Intel Corporation. + * Copyright (C) 2011, 2015, 2016 Intel Corporation. * * ---------------------------------------------------------------------------- * @@ -23,19 +23,20 @@ * */ -#include -#include +#include #include -#include -#include -#include #include +#include +#include #include #include -#include +#include +#include #include #include -#include +#include +#include + #include "i2c-designware-core.h" #define DRIVER_NAME "i2c-designware-pci" @@ -206,7 +207,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, struct dw_i2c_dev *dev; struct i2c_adapter *adap; int r; - struct dw_pci_controller *controller; + struct dw_pci_controller *controller; struct dw_scl_sda_cfg *cfg; if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) { -- cgit v1.2.3-59-g8ed1b From 9e55c0739670585f0d1bad58fa713865348be943 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 31 May 2016 11:37:13 -0400 Subject: i2c: elektor: Utilize the module_isa_driver macro This driver does not do anything special in module init/exit. This patch eliminates the module init/exit boilerplate code by utilizing the module_isa_driver macro. Signed-off-by: William Breathitt Gray Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-elektor.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index 92e8c0ce1625..8af62fb3fe41 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -319,16 +319,6 @@ static struct isa_driver i2c_elektor_driver = { }, }; -static int __init i2c_pcfisa_init(void) -{ - return isa_register_driver(&i2c_elektor_driver, 1); -} - -static void __exit i2c_pcfisa_exit(void) -{ - isa_unregister_driver(&i2c_elektor_driver); -} - MODULE_AUTHOR("Hans Berglund "); MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter"); MODULE_LICENSE("GPL"); @@ -338,6 +328,4 @@ module_param(irq, int, 0); module_param(clock, int, 0); module_param(own, int, 0); module_param(mmapped, int, 0); - -module_init(i2c_pcfisa_init); -module_exit(i2c_pcfisa_exit); +module_isa_driver(i2c_elektor_driver, 1); -- cgit v1.2.3-59-g8ed1b From e0f6431c1ef00e6160c9c36a9ca3b7405518db3d Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 31 May 2016 12:22:34 -0400 Subject: i2c: pca-isa: Utilize the module_isa_driver macro This driver does not do anything special in module init/exit. This patch eliminates the module init/exit boilerplate code by utilizing the module_isa_driver macro. Signed-off-by: William Breathitt Gray [wsa: remove two empty lines while here] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pca-isa.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index e0eb4ca0102e..ba88f17f636c 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c @@ -193,23 +193,12 @@ static struct isa_driver pca_isa_driver = { } }; -static int __init pca_isa_init(void) -{ - return isa_register_driver(&pca_isa_driver, 1); -} - -static void __exit pca_isa_exit(void) -{ - isa_unregister_driver(&pca_isa_driver); -} - MODULE_AUTHOR("Ian Campbell "); MODULE_DESCRIPTION("ISA base PCA9564/PCA9665 driver"); MODULE_LICENSE("GPL"); module_param(base, ulong, 0); MODULE_PARM_DESC(base, "I/O base address"); - module_param(irq, int, 0); MODULE_PARM_DESC(irq, "IRQ"); module_param(clock, int, 0); @@ -220,6 +209,4 @@ MODULE_PARM_DESC(clock, "Clock rate in hertz.\n\t\t" "\t\t\t\tFast: 100100 - 400099\n" "\t\t\t\tFast+: 400100 - 10000099\n" "\t\t\t\tTurbo: Up to 1265800"); - -module_init(pca_isa_init); -module_exit(pca_isa_exit); +module_isa_driver(pca_isa_driver, 1); -- cgit v1.2.3-59-g8ed1b From 97d34ec136a9ff10259ea636a45d3a41beda0e4f Mon Sep 17 00:00:00 2001 From: Ellen Wang Date: Fri, 1 Jul 2016 22:42:15 +0200 Subject: i2c: i801: recover from hardware PEC errors On a CRC error while using hardware-supported PEC, an additional error bit is set in the auxiliary status register. If this bit isn't cleared, all subsequent operations will fail, essentially hanging the controller. The fix is simple: check, report, and clear the bit in i801_check_post(). Also, in case the driver starts with the hardware in that state, clear it in i801_check_pre() as well. Signed-off-by: Ellen Wang Tested-by: Jean Delvare Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 53 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index b43696394d5b..ae5df147327b 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -144,6 +144,10 @@ /* TCO configuration bits for TCOCTL */ #define TCOCTL_EN 0x0100 +/* Auxiliary status register bits, ICH4+ only */ +#define SMBAUXSTS_CRCE 1 +#define SMBAUXSTS_STCO 2 + /* Auxiliary control register bits, ICH4+ only */ #define SMBAUXCTL_CRC 1 #define SMBAUXCTL_E32B 2 @@ -305,6 +309,29 @@ static int i801_check_pre(struct i801_priv *priv) } } + /* + * Clear CRC status if needed. + * During normal operation, i801_check_post() takes care + * of it after every operation. We do it here only in case + * the hardware was already in this state when the driver + * started. + */ + if (priv->features & FEATURE_SMBUS_PEC) { + status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; + if (status) { + dev_dbg(&priv->pci_dev->dev, + "Clearing aux status flags (%02x)\n", status); + outb_p(status, SMBAUXSTS(priv)); + status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; + if (status) { + dev_err(&priv->pci_dev->dev, + "Failed clearing aux status flags (%02x)\n", + status); + return -EBUSY; + } + } + } + return 0; } @@ -348,8 +375,30 @@ static int i801_check_post(struct i801_priv *priv, int status) dev_err(&priv->pci_dev->dev, "Transaction failed\n"); } if (status & SMBHSTSTS_DEV_ERR) { - result = -ENXIO; - dev_dbg(&priv->pci_dev->dev, "No response\n"); + /* + * This may be a PEC error, check and clear it. + * + * AUXSTS is handled differently from HSTSTS. + * For HSTSTS, i801_isr() or i801_wait_intr() + * has already cleared the error bits in hardware, + * and we are passed a copy of the original value + * in "status". + * For AUXSTS, the hardware register is left + * for us to handle here. + * This is asymmetric, slightly iffy, but safe, + * since all this code is serialized and the CRCE + * bit is harmless as long as it's cleared before + * the next operation. + */ + if ((priv->features & FEATURE_SMBUS_PEC) && + (inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE)) { + outb_p(SMBAUXSTS_CRCE, SMBAUXSTS(priv)); + result = -EBADMSG; + dev_dbg(&priv->pci_dev->dev, "PEC error\n"); + } else { + result = -ENXIO; + dev_dbg(&priv->pci_dev->dev, "No response\n"); + } } if (status & SMBHSTSTS_BUS_ERR) { result = -EAGAIN; -- cgit v1.2.3-59-g8ed1b From 7b0ed334b8468dccd3340778bd04c0a8be46b81d Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 24 Jun 2016 16:39:49 +0200 Subject: i2c: i801: add support of Host Notify The i801 chip can handle the Host Notify feature since ICH 3 as mentioned in http://www.intel.com/content/dam/doc/datasheet/82801ca-io-controller-hub-3-datasheet.pdf Enable the functionality unconditionally and propagate the alert on each notification. With a T440s and a Synaptics touchpad that implements Host Notify, the payload data is always 0x0000, so I am not sure if the device actually sends the payload or if there is a problem regarding the implementation. Tested-by: Andrew Duggan Signed-off-by: Benjamin Tissoires Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 1 + drivers/i2c/busses/i2c-i801.c | 88 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 86 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index efa3d9bfe294..b4b6cb067457 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -91,6 +91,7 @@ config I2C_I801 tristate "Intel 82801 (ICH/PCH)" depends on PCI select CHECK_SIGNATURE if X86 && DMI + select I2C_SMBUS help If you say yes to this option, support will be included for the Intel 801 family of mainboard I2C interfaces. Specifically, the following diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ae5df147327b..68cec6128ac0 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -72,6 +72,7 @@ * Block process call transaction no * I2C block read transaction yes (doesn't use the block buffer) * Slave mode no + * SMBus Host Notify yes * Interrupt processing yes * * See the file Documentation/i2c/busses/i2c-i801 for details. @@ -86,6 +87,7 @@ #include #include #include +#include #include #include #include @@ -113,6 +115,10 @@ #define SMBPEC(p) (8 + (p)->smba) /* ICH3 and later */ #define SMBAUXSTS(p) (12 + (p)->smba) /* ICH4 and later */ #define SMBAUXCTL(p) (13 + (p)->smba) /* ICH4 and later */ +#define SMBSLVSTS(p) (16 + (p)->smba) /* ICH3 and later */ +#define SMBSLVCMD(p) (17 + (p)->smba) /* ICH3 and later */ +#define SMBNTFDADD(p) (20 + (p)->smba) /* ICH3 and later */ +#define SMBNTFDDAT(p) (22 + (p)->smba) /* ICH3 and later */ /* PCI Address Constants */ #define SMBBAR 4 @@ -181,6 +187,12 @@ #define SMBHSTSTS_INTR 0x02 #define SMBHSTSTS_HOST_BUSY 0x01 +/* Host Notify Status registers bits */ +#define SMBSLVSTS_HST_NTFY_STS 1 + +/* Host Notify Command registers bits */ +#define SMBSLVCMD_HST_NTFY_INTREN 0x01 + #define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \ SMBHSTSTS_DEV_ERR) @@ -256,13 +268,17 @@ struct i801_priv { */ bool acpi_reserved; struct mutex acpi_lock; + struct smbus_host_notify *host_notify; }; +#define SMBHSTNTFY_SIZE 8 + #define FEATURE_SMBUS_PEC (1 << 0) #define FEATURE_BLOCK_BUFFER (1 << 1) #define FEATURE_BLOCK_PROC (1 << 2) #define FEATURE_I2C_BLOCK_READ (1 << 3) #define FEATURE_IRQ (1 << 4) +#define FEATURE_HOST_NOTIFY (1 << 5) /* Not really a feature, but it's convenient to handle it as such */ #define FEATURE_IDF (1 << 15) #define FEATURE_TCO (1 << 16) @@ -273,6 +289,7 @@ static const char *i801_feature_names[] = { "Block process call", "I2C block read", "Interrupt", + "SMBus Host Notify", }; static unsigned int disable_features; @@ -281,7 +298,8 @@ MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n" "\t\t 0x01 disable SMBus PEC\n" "\t\t 0x02 disable the block buffer\n" "\t\t 0x08 disable the I2C block read functionality\n" - "\t\t 0x10 don't use interrupts "); + "\t\t 0x10 don't use interrupts\n" + "\t\t 0x20 disable SMBus Host Notify "); /* Make sure the SMBus host is ready to start transmitting. Return 0 if it is, -EBUSY if it is not. */ @@ -560,8 +578,23 @@ static void i801_isr_byte_done(struct i801_priv *priv) outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); } +static irqreturn_t i801_host_notify_isr(struct i801_priv *priv) +{ + unsigned short addr; + unsigned int data; + + addr = inb_p(SMBNTFDADD(priv)) >> 1; + data = inw_p(SMBNTFDDAT(priv)); + + i2c_handle_smbus_host_notify(priv->host_notify, addr, data); + + /* clear Host Notify bit and return */ + outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); + return IRQ_HANDLED; +} + /* - * There are two kinds of interrupts: + * There are three kinds of interrupts: * * 1) i801 signals transaction completion with one of these interrupts: * INTR - Success @@ -573,6 +606,8 @@ static void i801_isr_byte_done(struct i801_priv *priv) * * 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt * occurs for each byte of a byte-by-byte to prepare the next byte. + * + * 3) Host Notify interrupts */ static irqreturn_t i801_isr(int irq, void *dev_id) { @@ -585,6 +620,12 @@ static irqreturn_t i801_isr(int irq, void *dev_id) if (!(pcists & SMBPCISTS_INTS)) return IRQ_NONE; + if (priv->features & FEATURE_HOST_NOTIFY) { + status = inb_p(SMBSLVSTS(priv)); + if (status & SMBSLVSTS_HST_NTFY_STS) + return i801_host_notify_isr(priv); + } + status = inb_p(SMBHSTSTS(priv)); if (status & SMBHSTSTS_BYTE_DONE) i801_isr_byte_done(priv); @@ -896,7 +937,28 @@ static u32 i801_func(struct i2c_adapter *adapter) I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | ((priv->features & FEATURE_I2C_BLOCK_READ) ? - I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0); + I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) | + ((priv->features & FEATURE_HOST_NOTIFY) ? + I2C_FUNC_SMBUS_HOST_NOTIFY : 0); +} + +static int i801_enable_host_notify(struct i2c_adapter *adapter) +{ + struct i801_priv *priv = i2c_get_adapdata(adapter); + + if (!(priv->features & FEATURE_HOST_NOTIFY)) + return -ENOTSUPP; + + if (!priv->host_notify) + priv->host_notify = i2c_setup_smbus_host_notify(adapter); + if (!priv->host_notify) + return -ENOMEM; + + outb_p(SMBSLVCMD_HST_NTFY_INTREN, SMBSLVCMD(priv)); + /* clear Host Notify bit to allow a new notification */ + outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); + + return 0; } static const struct i2c_algorithm smbus_algorithm = { @@ -1428,6 +1490,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) priv->features |= FEATURE_SMBUS_PEC; priv->features |= FEATURE_BLOCK_BUFFER; priv->features |= FEATURE_TCO; + priv->features |= FEATURE_HOST_NOTIFY; break; case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0: @@ -1447,6 +1510,8 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) priv->features |= FEATURE_BLOCK_BUFFER; /* fall through */ case PCI_DEVICE_ID_INTEL_82801CA_3: + priv->features |= FEATURE_HOST_NOTIFY; + /* fall through */ case PCI_DEVICE_ID_INTEL_82801BA_2: case PCI_DEVICE_ID_INTEL_82801AB_3: case PCI_DEVICE_ID_INTEL_82801AA_3: @@ -1556,6 +1621,15 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) return err; } + /* + * Enable Host Notify for chips that supports it. + * It is done after i2c_add_adapter() so that we are sure the work queue + * is not used if i2c_add_adapter() fails. + */ + err = i801_enable_host_notify(&priv->adapter); + if (err && err != -ENOTSUPP) + dev_warn(&dev->dev, "Unable to enable SMBus Host Notify\n"); + i801_probe_optional_slaves(priv); /* We ignore errors - multiplexing is optional */ i801_add_mux(priv); @@ -1602,6 +1676,14 @@ static int i801_suspend(struct device *dev) static int i801_resume(struct device *dev) { + struct pci_dev *pci_dev = to_pci_dev(dev); + struct i801_priv *priv = pci_get_drvdata(pci_dev); + int err; + + err = i801_enable_host_notify(&priv->adapter); + if (err && err != -ENOTSUPP) + dev_warn(dev, "Unable to enable SMBus Host Notify\n"); + return 0; } #endif -- cgit v1.2.3-59-g8ed1b From ec2790e9d72e87c90d9247430c3f08df1fce3c75 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 20 Jun 2016 11:58:09 +0300 Subject: i2c: designware-pci: clarify a comment for Merrifield There are more than 7 busses, but only 7 are user visible. Update comment accordingly. Acked-by: Jarkko Nikula Signed-off-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index b66c31acb184..96f8230cd2d3 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -125,10 +125,10 @@ static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c) static int mrfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c) { /* - * On Intel Merrifield the i2c busses are enumerated [1..7]. So, we add - * 1 to shift the default range. Besides that the first PCI slot - * provides 4 functions, that's why we have to add 0 to the head slot - * and 4 to the tail one. + * On Intel Merrifield the user visible i2c busses are enumerated + * [1..7]. So, we add 1 to shift the default range. Besides that the + * first PCI slot provides 4 functions, that's why we have to add 0 to + * the first slot and 4 to the next one. */ switch (PCI_SLOT(pdev->devfn)) { case 8: -- cgit v1.2.3-59-g8ed1b From 5136ed4fcb05cd4981cc6034a11e66370ed84789 Mon Sep 17 00:00:00 2001 From: viresh kumar Date: Tue, 5 Jul 2016 19:57:06 -0700 Subject: i2c-dev: don't get i2c adapter via i2c_dev There is no code protecting i2c_dev to be freed after it is returned from i2c_dev_get_by_minor() and using it to access the value which we already have (minor) isn't safe really. Avoid using it and get the adapter directly from 'minor'. Signed-off-by: Viresh Kumar Reviewed-by: Jean Delvare Tested-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-dev.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 6ecfd76270f2..66f323fd3982 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -485,13 +485,8 @@ static int i2cdev_open(struct inode *inode, struct file *file) unsigned int minor = iminor(inode); struct i2c_client *client; struct i2c_adapter *adap; - struct i2c_dev *i2c_dev; - - i2c_dev = i2c_dev_get_by_minor(minor); - if (!i2c_dev) - return -ENODEV; - adap = i2c_get_adapter(i2c_dev->adap->nr); + adap = i2c_get_adapter(minor); if (!adap) return -ENODEV; -- cgit v1.2.3-59-g8ed1b From 914017836afb6aff86afdf819cb270944e89c2ac Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 6 Jul 2016 21:17:05 +0100 Subject: i2c: meson: allow build with COMPILE_TEST This driver should be buildable with COMPILE_TEST so add this to the dependency for it. Signed-off-by: Ben Dooks Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index b4b6cb067457..4cefc6617892 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -638,7 +638,7 @@ config I2C_LPC2K config I2C_MESON tristate "Amlogic Meson I2C controller" - depends on ARCH_MESON + depends on ARCH_MESON || COMPILE_TEST help If you say yes to this option, support will be included for the I2C interface on the Amlogic Meson family of SoCs. -- cgit v1.2.3-59-g8ed1b From 748c0bbbf170700d5c612e09e8d89904ddf7ebc5 Mon Sep 17 00:00:00 2001 From: Tanmay Jagdale Date: Mon, 20 Jun 2016 14:56:18 +0530 Subject: i2c: xlp9xx: add ACPI support for Broadcom Vulcan Added ACPI support for the I2C controller present on Broadcom's Vulcan ARM64 processor. ACPI ID used by the controller is BRCM9007. Changed the xlp9xx_i2c_get_frequency() function to use device_property_read_u32() API so that the "clock-frequency" value can be read from _DSD in ACPI mode. Signed-off-by: Tanmay Jagdale Reviewed-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xlp9xx.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index c941418f06f5..55a7bef1b2e1 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -6,6 +6,7 @@ * warranty of any kind, whether express or implied. */ +#include #include #include #include @@ -341,11 +342,10 @@ static struct i2c_algorithm xlp9xx_i2c_algo = { static int xlp9xx_i2c_get_frequency(struct platform_device *pdev, struct xlp9xx_i2c_dev *priv) { - struct device_node *np = pdev->dev.of_node; u32 freq; int err; - err = of_property_read_u32(np, "clock-frequency", &freq); + err = device_property_read_u32(&pdev->dev, "clock-frequency", &freq); if (err) { freq = XLP9XX_I2C_DEFAULT_FREQ; dev_dbg(&pdev->dev, "using default frequency %u\n", freq); @@ -429,12 +429,21 @@ static const struct of_device_id xlp9xx_i2c_of_match[] = { { /* sentinel */ }, }; +#ifdef CONFIG_ACPI +static const struct acpi_device_id xlp9xx_i2c_acpi_ids[] = { + {"BRCM9007", 0}, + {} +}; +MODULE_DEVICE_TABLE(acpi, xlp9xx_i2c_acpi_ids); +#endif + static struct platform_driver xlp9xx_i2c_driver = { .probe = xlp9xx_i2c_probe, .remove = xlp9xx_i2c_remove, .driver = { .name = "xlp9xx-i2c", .of_match_table = xlp9xx_i2c_of_match, + .acpi_match_table = ACPI_PTR(xlp9xx_i2c_acpi_ids), }, }; -- cgit v1.2.3-59-g8ed1b From 9f6db9bfb58e0008c0d041d69cef3bcb6247dc52 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 9 Jul 2016 13:31:23 +0800 Subject: i2c: versatile: Allow compile test build There is no build dependency for this driver, so enable COMPILE_TEST to get better build coverage. Signed-off-by: Axel Lin Tested-by: Liviu Dudau Acked-by: Liviu Dudau Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 4cefc6617892..2f0fd11b8057 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -927,7 +927,7 @@ config I2C_UNIPHIER_F config I2C_VERSATILE tristate "ARM Versatile/Realview I2C bus support" - depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS + depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS || COMPILE_TEST select I2C_ALGOBIT help Say yes if you want to support the I2C serial bus on ARMs Versatile -- cgit v1.2.3-59-g8ed1b From cc4618813e4bc409cd22641f6001118ef4479cfc Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 9 Jul 2016 13:32:23 +0800 Subject: i2c: versatile: Convert to use resource managed devm_* APIs Use devm_* APIs to simplify the code a bit. This patch also fixes the memory leak when unload the module. Signed-off-by: Axel Lin Tested-by: Liviu Dudau Acked-by: Liviu Dudau Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-versatile.c | 46 +++++++++++--------------------------- 1 file changed, 13 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c index 240637f01d11..c73d2d22009e 100644 --- a/drivers/i2c/busses/i2c-versatile.c +++ b/drivers/i2c/busses/i2c-versatile.c @@ -70,28 +70,14 @@ static int i2c_versatile_probe(struct platform_device *dev) struct resource *r; int ret; + i2c = devm_kzalloc(&dev->dev, sizeof(struct i2c_versatile), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + r = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!r) { - ret = -EINVAL; - goto err_out; - } - - if (!request_mem_region(r->start, resource_size(r), "versatile-i2c")) { - ret = -EBUSY; - goto err_out; - } - - i2c = kzalloc(sizeof(struct i2c_versatile), GFP_KERNEL); - if (!i2c) { - ret = -ENOMEM; - goto err_release; - } - - i2c->base = ioremap(r->start, resource_size(r)); - if (!i2c->base) { - ret = -ENOMEM; - goto err_free; - } + i2c->base = devm_ioremap_resource(&dev->dev, r); + if (IS_ERR(i2c->base)) + return PTR_ERR(i2c->base); writel(SCL | SDA, i2c->base + I2C_CONTROLS); @@ -105,18 +91,12 @@ static int i2c_versatile_probe(struct platform_device *dev) i2c->adap.nr = dev->id; ret = i2c_bit_add_numbered_bus(&i2c->adap); - if (ret >= 0) { - platform_set_drvdata(dev, i2c); - return 0; - } - - iounmap(i2c->base); - err_free: - kfree(i2c); - err_release: - release_mem_region(r->start, resource_size(r)); - err_out: - return ret; + if (ret < 0) + return ret; + + platform_set_drvdata(dev, i2c); + + return 0; } static int i2c_versatile_remove(struct platform_device *dev) -- cgit v1.2.3-59-g8ed1b From ce0dffafd403e7824ae78a806d08c04ff8112e79 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 9 Jul 2016 13:34:58 +0900 Subject: i2c: free idr when sanity checks in i2c_register_adapter() fail On error, we should give idr back to the pool in any case. Signed-off-by: Wolfram Sang Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 952d2f0c02c5..9f53751e49a7 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1554,7 +1554,7 @@ static int __process_new_adapter(struct device_driver *d, void *data) static int i2c_register_adapter(struct i2c_adapter *adap) { - int res = 0; + int res = -EINVAL; /* Can't register until after driver model init */ if (WARN_ON(!is_registered)) { @@ -1566,12 +1566,12 @@ static int i2c_register_adapter(struct i2c_adapter *adap) if (unlikely(adap->name[0] == '\0')) { pr_err("i2c-core: Attempt to register an adapter with " "no name!\n"); - return -EINVAL; + goto out_list; } if (unlikely(!adap->algo)) { pr_err("i2c-core: Attempt to register adapter '%s' with " "no algo!\n", adap->name); - return -EINVAL; + goto out_list; } if (!adap->lock_bus) { -- cgit v1.2.3-59-g8ed1b From d3b11d8380d05e3121e2694af0dd95e7f63399bd Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 9 Jul 2016 13:34:59 +0900 Subject: i2c: cleanup i2c_register_adapter() by refactoring recovery init Move recovery init to a seperate function to let have i2c_register_adapter() less lines and to avoid goto and a label. Refactor string handling there for consistency and to save some bytes. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 76 ++++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 9f53751e49a7..ef6def72a654 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -666,6 +666,47 @@ int i2c_recover_bus(struct i2c_adapter *adap) } EXPORT_SYMBOL_GPL(i2c_recover_bus); +static void i2c_init_recovery(struct i2c_adapter *adap) +{ + struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; + char *err_str; + + if (!bri) + return; + + if (!bri->recover_bus) { + err_str = "no recover_bus() found"; + goto err; + } + + /* Generic GPIO recovery */ + if (bri->recover_bus == i2c_generic_gpio_recovery) { + if (!gpio_is_valid(bri->scl_gpio)) { + err_str = "invalid SCL gpio"; + goto err; + } + + if (gpio_is_valid(bri->sda_gpio)) + bri->get_sda = get_sda_gpio_value; + else + bri->get_sda = NULL; + + bri->get_scl = get_scl_gpio_value; + bri->set_scl = set_scl_gpio_value; + } else if (bri->recover_bus == i2c_generic_scl_recovery) { + /* Generic SCL recovery */ + if (!bri->set_scl || !bri->get_scl) { + err_str = "no {get|set}_scl() found"; + goto err; + } + } + + return; + err: + dev_err(&adap->dev, "Not using recovery: %s\n", err_str); + adap->bus_recovery_info = NULL; +} + static int i2c_device_probe(struct device *dev) { struct i2c_client *client = i2c_verify_client(dev); @@ -1610,41 +1651,8 @@ static int i2c_register_adapter(struct i2c_adapter *adap) "Failed to create compatibility class link\n"); #endif - /* bus recovery specific initialization */ - if (adap->bus_recovery_info) { - struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; - - if (!bri->recover_bus) { - dev_err(&adap->dev, "No recover_bus() found, not using recovery\n"); - adap->bus_recovery_info = NULL; - goto exit_recovery; - } - - /* Generic GPIO recovery */ - if (bri->recover_bus == i2c_generic_gpio_recovery) { - if (!gpio_is_valid(bri->scl_gpio)) { - dev_err(&adap->dev, "Invalid SCL gpio, not using recovery\n"); - adap->bus_recovery_info = NULL; - goto exit_recovery; - } - - if (gpio_is_valid(bri->sda_gpio)) - bri->get_sda = get_sda_gpio_value; - else - bri->get_sda = NULL; - - bri->get_scl = get_scl_gpio_value; - bri->set_scl = set_scl_gpio_value; - } else if (bri->recover_bus == i2c_generic_scl_recovery) { - /* Generic SCL recovery */ - if (!bri->set_scl || !bri->get_scl) { - dev_err(&adap->dev, "No {get|set}_scl() found, not using recovery\n"); - adap->bus_recovery_info = NULL; - } - } - } + i2c_init_recovery(adap); -exit_recovery: /* create pre-declared device nodes */ of_i2c_register_devices(adap); acpi_i2c_register_devices(adap); -- cgit v1.2.3-59-g8ed1b From 8ddfe4108e0a160f078adc96827e3809beb4d451 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 9 Jul 2016 13:35:00 +0900 Subject: i2c: improve error messages in i2c_register_adapter() Switch to WARN if no adapter name is given, otherwise we won't know who missed to do that. Add error message if device registration fails. Update error message for missing algo to match style of the others. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index ef6def72a654..8e07e3be4880 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1604,14 +1604,11 @@ static int i2c_register_adapter(struct i2c_adapter *adap) } /* Sanity checks */ - if (unlikely(adap->name[0] == '\0')) { - pr_err("i2c-core: Attempt to register an adapter with " - "no name!\n"); + if (WARN(!adap->name[0], "i2c adapter has no name")) goto out_list; - } - if (unlikely(!adap->algo)) { - pr_err("i2c-core: Attempt to register adapter '%s' with " - "no algo!\n", adap->name); + + if (!adap->algo) { + pr_err("i2c-core: adapter '%s': no algo supplied!\n", adap->name); goto out_list; } @@ -1634,8 +1631,11 @@ static int i2c_register_adapter(struct i2c_adapter *adap) adap->dev.bus = &i2c_bus_type; adap->dev.type = &i2c_adapter_type; res = device_register(&adap->dev); - if (res) + if (res) { + pr_err("i2c-core: adapter '%s': can't register device (%d)\n", + adap->name, res); goto out_list; + } dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); -- cgit v1.2.3-59-g8ed1b From 84d0b61773c7af077be71f74f0d7fea65af7f9b0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 9 Jul 2016 13:35:01 +0900 Subject: i2c: add error message when obtaining idr fails Fix some whitespace issues while here. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 8e07e3be4880..1a91b5173104 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1684,13 +1684,12 @@ out_list: */ static int __i2c_add_numbered_adapter(struct i2c_adapter *adap) { - int id; + int id; mutex_lock(&core_lock); - id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1, - GFP_KERNEL); + id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1, GFP_KERNEL); mutex_unlock(&core_lock); - if (id < 0) + if (WARN(id < 0, "couldn't get idr")) return id == -ENOSPC ? -EBUSY : id; return i2c_register_adapter(adap); @@ -1727,7 +1726,7 @@ int i2c_add_adapter(struct i2c_adapter *adapter) id = idr_alloc(&i2c_adapter_idr, adapter, __i2c_first_dynamic_bus_num, 0, GFP_KERNEL); mutex_unlock(&core_lock); - if (id < 0) + if (WARN(id < 0, "couldn't get idr")) return id; adapter->nr = id; -- cgit v1.2.3-59-g8ed1b From 399d62acc2ac5aa091c55810ae5190294b60e92f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 9 Jul 2016 13:35:02 +0900 Subject: i2c: print more info when of_i2c_notify fails Use dev_err instead of pr_err for more details. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 1a91b5173104..a2f69db4f4df 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -2103,8 +2103,8 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action, put_device(&adap->dev); if (IS_ERR(client)) { - pr_err("%s: failed to create for '%s'\n", - __func__, rd->dn->full_name); + dev_err(&adap->dev, "failed to create client for '%s'\n", + rd->dn->full_name); return notifier_from_errno(PTR_ERR(client)); } break; -- cgit v1.2.3-59-g8ed1b From be309c3cd3dcbebbd2b742e9a2a24482c92e01ff Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 9 Jul 2016 13:35:03 +0900 Subject: i2c: print more info when acpi_i2c_space_handler() fails Use a warning loglevel instead of info and switch to dev_* for device info. Also print which client was accessed. Signed-off-by: Wolfram Sang Acked-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index a2f69db4f4df..4b3d760b3f51 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -400,7 +400,8 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command, break; default: - pr_info("protocol(0x%02x) is not supported.\n", accessor_type); + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); ret = AE_BAD_PARAMETER; goto err; } -- cgit v1.2.3-59-g8ed1b From 44239a5afd7c568047fbaba8f32fb4b4464902b4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 9 Jul 2016 13:35:04 +0900 Subject: i2c: use pr_fmt in the core Now that we revisited all error messages, we can use pr_fmt for the remaining pr_* messages to ensure consistent output. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 4b3d760b3f51..b2b34a0a35a1 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -27,6 +27,8 @@ I2C slave support (c) 2014 by Wolfram Sang */ +#define pr_fmt(fmt) "i2c-core: " fmt + #include #include #include @@ -1609,7 +1611,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) goto out_list; if (!adap->algo) { - pr_err("i2c-core: adapter '%s': no algo supplied!\n", adap->name); + pr_err("adapter '%s': no algo supplied!\n", adap->name); goto out_list; } @@ -1633,8 +1635,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) adap->dev.type = &i2c_adapter_type; res = device_register(&adap->dev); if (res) { - pr_err("i2c-core: adapter '%s': can't register device (%d)\n", - adap->name, res); + pr_err("adapter '%s': can't register device (%d)\n", adap->name, res); goto out_list; } @@ -1825,8 +1826,7 @@ void i2c_del_adapter(struct i2c_adapter *adap) found = idr_find(&i2c_adapter_idr, adap->nr); mutex_unlock(&core_lock); if (found != adap) { - pr_debug("i2c-core: attempting to delete unregistered " - "adapter [%s]\n", adap->name); + pr_debug("attempting to delete unregistered adapter [%s]\n", adap->name); return; } @@ -1986,7 +1986,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) if (res) return res; - pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); + pr_debug("driver [%s] registered\n", driver->driver.name); INIT_LIST_HEAD(&driver->clients); /* Walk the adapters that are already present */ @@ -2013,7 +2013,7 @@ void i2c_del_driver(struct i2c_driver *driver) i2c_for_each_dev(driver, __process_removed_driver); driver_unregister(&driver->driver); - pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); + pr_debug("driver [%s] unregistered\n", driver->driver.name); } EXPORT_SYMBOL(i2c_del_driver); @@ -2722,7 +2722,7 @@ static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg) cpec = i2c_smbus_msg_pec(cpec, msg); if (rpec != cpec) { - pr_debug("i2c-core: Bad PEC 0x%02x vs. 0x%02x\n", + pr_debug("Bad PEC 0x%02x vs. 0x%02x\n", rpec, cpec); return -EBADMSG; } -- cgit v1.2.3-59-g8ed1b From a7003b65801e17a19617a509b2dbae3442ddd709 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 6 Jun 2016 14:26:21 +0300 Subject: i2c: core: Cleanup I2C ACPI namespace I2C ACPI enumeration was originally implemented in another module under drivers/acpi/ but was later moved into i2c-core with added support for I2C ACPI operation region. Rename these acpi_i2c_ prefixed functions, structures and defines in i2c-core to i2c_acpi_ in order to have more consistent name space. Signed-off-by: Jarkko Nikula Reviewed-by: Andy Shevchenko Acked-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 54 +++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index b2b34a0a35a1..abe41369eec1 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -88,7 +88,7 @@ void i2c_transfer_trace_unreg(void) } #if defined(CONFIG_ACPI) -struct acpi_i2c_handler_data { +struct i2c_acpi_handler_data { struct acpi_connection_info info; struct i2c_adapter *adapter; }; @@ -103,15 +103,15 @@ struct gsb_buffer { }; } __packed; -struct acpi_i2c_lookup { +struct i2c_acpi_lookup { struct i2c_board_info *info; acpi_handle adapter_handle; acpi_handle device_handle; }; -static int acpi_i2c_find_address(struct acpi_resource *ares, void *data) +static int i2c_acpi_find_address(struct acpi_resource *ares, void *data) { - struct acpi_i2c_lookup *lookup = data; + struct i2c_acpi_lookup *lookup = data; struct i2c_board_info *info = lookup->info; struct acpi_resource_i2c_serialbus *sb; acpi_handle adapter_handle; @@ -140,12 +140,12 @@ static int acpi_i2c_find_address(struct acpi_resource *ares, void *data) return 1; } -static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, +static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level, void *data, void **return_value) { struct i2c_adapter *adapter = data; struct list_head resource_list; - struct acpi_i2c_lookup lookup; + struct i2c_acpi_lookup lookup; struct resource_entry *entry; struct i2c_board_info info; struct acpi_device *adev; @@ -170,7 +170,7 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, */ INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, - acpi_i2c_find_address, &lookup); + i2c_acpi_find_address, &lookup); acpi_dev_free_resource_list(&resource_list); if (ret < 0 || !info.addr) @@ -202,17 +202,17 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, return AE_OK; } -#define ACPI_I2C_MAX_SCAN_DEPTH 32 +#define I2C_ACPI_MAX_SCAN_DEPTH 32 /** - * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter + * i2c_acpi_register_devices - enumerate I2C slave devices behind adapter * @adap: pointer to adapter * * Enumerate all I2C slave devices behind this adapter by walking the ACPI * namespace. When a device is found it will be added to the Linux device * model and bound to the corresponding ACPI handle. */ -static void acpi_i2c_register_devices(struct i2c_adapter *adap) +static void i2c_acpi_register_devices(struct i2c_adapter *adap) { acpi_status status; @@ -220,15 +220,15 @@ static void acpi_i2c_register_devices(struct i2c_adapter *adap) return; status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_I2C_MAX_SCAN_DEPTH, - acpi_i2c_add_device, NULL, + I2C_ACPI_MAX_SCAN_DEPTH, + i2c_acpi_add_device, NULL, adap, NULL); if (ACPI_FAILURE(status)) dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); } #else /* CONFIG_ACPI */ -static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { } +static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { } #endif /* CONFIG_ACPI */ #ifdef CONFIG_ACPI_I2C_OPREGION @@ -293,12 +293,12 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, } static acpi_status -acpi_i2c_space_handler(u32 function, acpi_physical_address command, +i2c_acpi_space_handler(u32 function, acpi_physical_address command, u32 bits, u64 *value64, void *handler_context, void *region_context) { struct gsb_buffer *gsb = (struct gsb_buffer *)value64; - struct acpi_i2c_handler_data *data = handler_context; + struct i2c_acpi_handler_data *data = handler_context; struct acpi_connection_info *info = &data->info; struct acpi_resource_i2c_serialbus *sb; struct i2c_adapter *adapter = data->adapter; @@ -417,10 +417,10 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command, } -static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) +static int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) { acpi_handle handle; - struct acpi_i2c_handler_data *data; + struct i2c_acpi_handler_data *data; acpi_status status; if (!adapter->dev.parent) @@ -431,7 +431,7 @@ static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) if (!handle) return -ENODEV; - data = kzalloc(sizeof(struct acpi_i2c_handler_data), + data = kzalloc(sizeof(struct i2c_acpi_handler_data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -445,7 +445,7 @@ static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) status = acpi_install_address_space_handler(handle, ACPI_ADR_SPACE_GSBUS, - &acpi_i2c_space_handler, + &i2c_acpi_space_handler, NULL, data); if (ACPI_FAILURE(status)) { @@ -459,10 +459,10 @@ static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) return 0; } -static void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) +static void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) { acpi_handle handle; - struct acpi_i2c_handler_data *data; + struct i2c_acpi_handler_data *data; acpi_status status; if (!adapter->dev.parent) @@ -475,7 +475,7 @@ static void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GSBUS, - &acpi_i2c_space_handler); + &i2c_acpi_space_handler); status = acpi_bus_get_private_data(handle, (void **)&data); if (ACPI_SUCCESS(status)) @@ -484,10 +484,10 @@ static void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) acpi_bus_detach_private_data(handle); } #else /* CONFIG_ACPI_I2C_OPREGION */ -static inline void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) +static inline void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) { } -static inline int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) +static inline int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) { return 0; } #endif /* CONFIG_ACPI_I2C_OPREGION */ @@ -1657,8 +1657,8 @@ static int i2c_register_adapter(struct i2c_adapter *adap) /* create pre-declared device nodes */ of_i2c_register_devices(adap); - acpi_i2c_register_devices(adap); - acpi_i2c_install_space_handler(adap); + i2c_acpi_register_devices(adap); + i2c_acpi_install_space_handler(adap); if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); @@ -1830,7 +1830,7 @@ void i2c_del_adapter(struct i2c_adapter *adap) return; } - acpi_i2c_remove_space_handler(adap); + i2c_acpi_remove_space_handler(adap); /* Tell drivers about this removal */ mutex_lock(&core_lock); bus_for_each_drv(&i2c_bus_type, NULL, adap, -- cgit v1.2.3-59-g8ed1b From 55d38d060e999ca1a3ea6eb132105a0301e4cd04 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 6 Jun 2016 14:26:22 +0300 Subject: i2c: core: Add function for finding the bus speed from ACPI ACPI 5 specification doesn't have property for the I2C bus speed but I2cSerialBus resource descriptors which define each controller-slave connection define the maximum speed supported by that connection. Thus finding the maximum safe speed for the bus is to walk all I2cSerialBus resources that are associated to I2C controller and use the speed of slowest connection. Add function i2c_acpi_find_bus_speed() to the i2c-core that adapter drivers can call prior registering itself to core. This implies two-step walk through the I2cSerialBus resources: call to i2c_acpi_find_bus_speed() does the first scan and finds the safe bus speed that adapter drivers can set up. Adapter driver registration does the second scan when i2c-core creates the I2C slaves by calling the i2c_acpi_register_devices(). In that way the bus speed is set in case slave device probe gets called during registration and does communication. Implement this by reusing the existing ACPI I2C walk routines in the i2c-core. Extend them so that slowest connection speed is saved during the walk and I2C slaves are registered only when calling through the i2c_acpi_register_devices() with the i2c_adapter pointer. Signed-off-by: Jarkko Nikula Reviewed-by: Andy Shevchenko Acked-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 74 ++++++++++++++++++++++++++++++++++++++++---------- include/linux/i2c.h | 9 ++++++ 2 files changed, 68 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index abe41369eec1..347494a8750e 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -105,11 +105,13 @@ struct gsb_buffer { struct i2c_acpi_lookup { struct i2c_board_info *info; + struct i2c_adapter *adapter; /* set only when registering slaves */ acpi_handle adapter_handle; acpi_handle device_handle; + u32 min_speed; }; -static int i2c_acpi_find_address(struct acpi_resource *ares, void *data) +static int i2c_acpi_find_resource(struct acpi_resource *ares, void *data) { struct i2c_acpi_lookup *lookup = data; struct i2c_board_info *info = lookup->info; @@ -135,17 +137,20 @@ static int i2c_acpi_find_address(struct acpi_resource *ares, void *data) info->addr = sb->slave_address; if (sb->access_mode == ACPI_I2C_10BIT_MODE) info->flags |= I2C_CLIENT_TEN; + /* Save speed of the slowest device */ + if (sb->connection_speed < lookup->min_speed) + lookup->min_speed = sb->connection_speed; } return 1; } -static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level, - void *data, void **return_value) +static acpi_status i2c_acpi_slave_lookup(acpi_handle handle, u32 level, + void *data, void **return_value) { - struct i2c_adapter *adapter = data; + struct i2c_acpi_lookup *lookup = data; + struct i2c_adapter *adapter = lookup->adapter; struct list_head resource_list; - struct i2c_acpi_lookup lookup; struct resource_entry *entry; struct i2c_board_info info; struct acpi_device *adev; @@ -159,10 +164,8 @@ static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level, memset(&info, 0, sizeof(info)); info.fwnode = acpi_fwnode_handle(adev); - memset(&lookup, 0, sizeof(lookup)); - lookup.adapter_handle = ACPI_HANDLE(&adapter->dev); - lookup.device_handle = handle; - lookup.info = &info; + lookup->device_handle = handle; + lookup->info = &info; /* * Look up for I2cSerialBus resource with ResourceSource that @@ -170,10 +173,10 @@ static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level, */ INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, - i2c_acpi_find_address, &lookup); + i2c_acpi_find_resource, lookup); acpi_dev_free_resource_list(&resource_list); - if (ret < 0 || !info.addr) + if (ret < 0 || !info.addr || !lookup->adapter) return AE_OK; /* Then fill IRQ number if any */ @@ -204,6 +207,14 @@ static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level, #define I2C_ACPI_MAX_SCAN_DEPTH 32 +static acpi_status i2c_acpi_walk(struct i2c_acpi_lookup *lookup) +{ + return acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + I2C_ACPI_MAX_SCAN_DEPTH, + i2c_acpi_slave_lookup, NULL, + lookup, NULL); +} + /** * i2c_acpi_register_devices - enumerate I2C slave devices behind adapter * @adap: pointer to adapter @@ -214,19 +225,52 @@ static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level, */ static void i2c_acpi_register_devices(struct i2c_adapter *adap) { + struct i2c_acpi_lookup lookup; acpi_status status; if (!has_acpi_companion(&adap->dev)) return; - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - I2C_ACPI_MAX_SCAN_DEPTH, - i2c_acpi_add_device, NULL, - adap, NULL); + memset(&lookup, 0, sizeof(lookup)); + lookup.adapter = adap; + lookup.adapter_handle = ACPI_HANDLE(&adap->dev); + + status = i2c_acpi_walk(&lookup); if (ACPI_FAILURE(status)) dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); } +/** + * i2c_acpi_find_bus_speed - find I2C bus speed from ACPI + * @dev: The device owning the bus + * + * Find the I2C bus speed by walking the ACPI namespace for all I2C slaves + * devices connected to this bus and use the speed of slowest device. + * + * Returns the speed in Hz or zero + */ +u32 i2c_acpi_find_bus_speed(struct device *dev) +{ + struct i2c_acpi_lookup lookup; + acpi_status status; + + if (!has_acpi_companion(dev)) + return 0; + + memset(&lookup, 0, sizeof(lookup)); + lookup.adapter_handle = ACPI_HANDLE(dev); + lookup.min_speed = UINT_MAX; + + status = i2c_acpi_walk(&lookup); + if (ACPI_FAILURE(status)) { + dev_warn(dev, "unable to find I2C bus speed from ACPI\n"); + return 0; + } + + return lookup.min_speed != UINT_MAX ? lookup.min_speed : 0; +} +EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed); + #else /* CONFIG_ACPI */ static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { } #endif /* CONFIG_ACPI */ diff --git a/include/linux/i2c.h b/include/linux/i2c.h index fffdc270ca18..5cde08719fb6 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -766,4 +766,13 @@ static inline struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node } #endif /* CONFIG_OF */ +#if IS_ENABLED(CONFIG_ACPI) +u32 i2c_acpi_find_bus_speed(struct device *dev); +#else +static inline u32 i2c_acpi_find_bus_speed(struct device *dev) +{ + return 0; +} +#endif /* CONFIG_ACPI */ + #endif /* _LINUX_I2C_H */ -- cgit v1.2.3-59-g8ed1b From bcf358aa57742db3bf0d66df8418fc99975a4361 Mon Sep 17 00:00:00 2001 From: Jaedon Shin Date: Fri, 15 Jul 2016 12:45:08 +0900 Subject: i2c: brcmstb: Make the driver buildable on BMIPS_GENERIC The BCM7xxx ARM and MIPS based SoCs share a similar I2C hardware block. Signed-off-by: Jaedon Shin Acked-by: Florian Fainelli Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 2f0fd11b8057..5c3993b26129 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -398,7 +398,7 @@ config I2C_BCM_KONA config I2C_BRCMSTB tristate "BRCM Settop I2C controller" - depends on ARCH_BRCMSTB || COMPILE_TEST + depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST default y help If you say yes to this option, support will be included for the -- cgit v1.2.3-59-g8ed1b From 94a0b0b92ed53cb74115b2c41c34aa0bf314d1aa Mon Sep 17 00:00:00 2001 From: Jaedon Shin Date: Fri, 15 Jul 2016 12:45:09 +0900 Subject: i2c: brcmstb: Remove superfluous size check The driver transfer to a message with NOACK always in any size. If client (eg. EDID segment point message) needs NOACK condition, it can use I2C_M_IGNORE_NAK flag. Signed-off-by: Jaedon Shin Acked-by: Kamal Dasu Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-brcmstb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c index 6a8cfc1344b2..3f5a4d71d3bf 100644 --- a/drivers/i2c/busses/i2c-brcmstb.c +++ b/drivers/i2c/busses/i2c-brcmstb.c @@ -343,10 +343,9 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev, struct bsc_regs *pi2creg = dev->bsc_regmap; int no_ack = pmsg->flags & I2C_M_IGNORE_NAK; int data_regsz = brcmstb_i2c_get_data_regsz(dev); - int xfersz = brcmstb_i2c_get_xfersz(dev); /* see if the transaction needs to check NACK conditions */ - if (no_ack || len <= xfersz) { + if (no_ack) { cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD_NOACK : CMD_WR_NOACK; pi2creg->ctlhi_reg |= BSC_CTLHI_REG_IGNORE_ACK_MASK; -- cgit v1.2.3-59-g8ed1b From 2b84a4dd4be0fd6d6fecdb14040cbbc38a3b525a Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 9 May 2016 18:14:30 +0530 Subject: i2c: qup: Cleared the error bits in ISR 1. Current QCOM I2C driver hangs when sending data to address 0x03-0x07 in some scenarios. The QUP controller generates invalid write in this case, since these addresses are reserved for different bus formats. 2. Also, the error handling is done by I2C QUP ISR in the case of DMA mode. The state need to be RESET in case of any error for clearing the available data in FIFO, which otherwise leaves the BAM DMA controller in hang state. This patch fixes the above two issues by clearing the error bits from I2C and QUP status in ISR in case of I2C error, QUP error and resets the QUP state to clear the FIFO data. Signed-off-by: Abhishek Sahu Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 69849a95d479..686f262e34f7 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -213,14 +213,16 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev) bus_err &= I2C_STATUS_ERROR_MASK; qup_err &= QUP_STATUS_ERROR_FLAGS; - if (qup_err) { - /* Clear Error interrupt */ + /* Clear the error bits in QUP_ERROR_FLAGS */ + if (qup_err) writel(qup_err, qup->base + QUP_ERROR_FLAGS); - goto done; - } - if (bus_err) { - /* Clear Error interrupt */ + /* Clear the error bits in QUP_I2C_STATUS */ + if (bus_err) + writel(bus_err, qup->base + QUP_I2C_STATUS); + + /* Reset the QUP State in case of error */ + if (qup_err || bus_err) { writel(QUP_RESET_STATE, qup->base + QUP_STATE); goto done; } -- cgit v1.2.3-59-g8ed1b From 5c135e151aee5f7e7f2ffb336cdb3e4e041caef4 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 9 May 2016 18:14:31 +0530 Subject: i2c: qup: Fixed the DMA segments length 1. The current QCOM I2C driver code is failing for transfer length greater than 255. This is happening due to improper segments length as the I2C DMA segments can be maximum of 256 bytes. 2. The transfer length tlen was being initialized with 0 for 256 bytes, which is being passed for DMA mappings resulting in improper DMA mapping length. This patch fixes the above said problems by initializing the block count with the values calculated in qup_i2c_set_blk_data and calculating the remaining length for last DMA segment. Also, the block data length need to be decremented after each transfer. Additionally, this patch corrects the tlen assignment for DMA mapping. Signed-off-by: Abhishek Sahu Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 686f262e34f7..29139bbe8f85 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -659,23 +659,24 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, u8 *tags; while (idx < num) { - blocks = (msg->len + limit) / limit; - rem = msg->len % limit; tx_len = 0, len = 0, i = 0; qup->is_last = (idx == (num - 1)); qup_i2c_set_blk_data(qup, msg); + blocks = qup->blk.count; + rem = msg->len - (blocks - 1) * limit; + if (msg->flags & I2C_M_RD) { rx_nents += (blocks * 2) + 1; tx_nents += 1; while (qup->blk.pos < blocks) { - /* length set to '0' implies 256 bytes */ - tlen = (i == (blocks - 1)) ? rem : 0; + tlen = (i == (blocks - 1)) ? rem : limit; tags = &qup->start_tag.start[off + len]; len += qup_i2c_set_tags(tags, qup, msg, 1); + qup->blk.data_len -= tlen; /* scratch buf to read the start and len tags */ ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++], @@ -712,9 +713,10 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, tx_nents += (blocks * 2); while (qup->blk.pos < blocks) { - tlen = (i == (blocks - 1)) ? rem : 0; + tlen = (i == (blocks - 1)) ? rem : limit; tags = &qup->start_tag.start[off + tx_len]; len = qup_i2c_set_tags(tags, qup, msg, 1); + qup->blk.data_len -= tlen; ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], tags, len, -- cgit v1.2.3-59-g8ed1b From b0b9f7bf9d1b76bdc05f3ba4955f42ccb9fd461d Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 6 Jun 2016 10:48:43 +0200 Subject: eeprom: at24: improve the device_id table readability As part of the preparation for introducing support for more chips, improve the readability of the device table by separating columns with tabs. Signed-off-by: Bartosz Golaszewski Signed-off-by: Wolfram Sang --- drivers/misc/eeprom/at24.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 9ceb63b62be5..411600de4a1b 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -111,23 +111,23 @@ MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)"); static const struct i2c_device_id at24_ids[] = { /* needs 8 addresses as A0-A2 are ignored */ - { "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) }, + { "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) }, /* old variants can't be handled with this generic entry! */ - { "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) }, - { "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) }, + { "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) }, + { "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) }, /* spd is a 24c02 in memory DIMMs */ - { "spd", AT24_DEVICE_MAGIC(2048 / 8, - AT24_FLAG_READONLY | AT24_FLAG_IRUGO) }, - { "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) }, + { "spd", AT24_DEVICE_MAGIC(2048 / 8, + AT24_FLAG_READONLY | AT24_FLAG_IRUGO) }, + { "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) }, /* 24rf08 quirk is handled at i2c-core */ - { "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) }, - { "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) }, - { "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) }, - { "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) }, - { "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) }, - { "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) }, - { "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) }, - { "24c1024", AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) }, + { "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) }, + { "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) }, + { "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) }, + { "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) }, + { "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) }, + { "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) }, + { "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) }, + { "24c1024", AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) }, { "at24", 0 }, { /* END OF LIST */ } }; -- cgit v1.2.3-59-g8ed1b From d5bc0047986df1fe99805141650cc3d429499ecc Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 6 Jun 2016 10:48:44 +0200 Subject: eeprom: at24: move at24_read() below at24_eeprom_write() In preparation for splitting at24_eeprom_write() & at24_eeprom_read() into smaller, specialized routines move at24_read() below, so that it won't be intertwined with the low-level EEPROM accessors. Signed-off-by: Bartosz Golaszewski Signed-off-by: Wolfram Sang --- drivers/misc/eeprom/at24.c | 64 +++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 411600de4a1b..e12d76fcbce6 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -249,38 +249,6 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, return -ETIMEDOUT; } -static int at24_read(void *priv, unsigned int off, void *val, size_t count) -{ - struct at24_data *at24 = priv; - char *buf = val; - - if (unlikely(!count)) - return count; - - /* - * Read data from chip, protecting against concurrent updates - * from this host, but not from other I2C masters. - */ - mutex_lock(&at24->lock); - - while (count) { - int status; - - status = at24_eeprom_read(at24, buf, off, count); - if (status < 0) { - mutex_unlock(&at24->lock); - return status; - } - buf += status; - off += status; - count -= status; - } - - mutex_unlock(&at24->lock); - - return 0; -} - /* * Note that if the hardware write-protect pin is pulled high, the whole * chip is normally write protected. But there are plenty of product @@ -366,6 +334,38 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf, return -ETIMEDOUT; } +static int at24_read(void *priv, unsigned int off, void *val, size_t count) +{ + struct at24_data *at24 = priv; + char *buf = val; + + if (unlikely(!count)) + return count; + + /* + * Read data from chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&at24->lock); + + while (count) { + int status; + + status = at24_eeprom_read(at24, buf, off, count); + if (status < 0) { + mutex_unlock(&at24->lock); + return status; + } + buf += status; + off += status; + count -= status; + } + + mutex_unlock(&at24->lock); + + return 0; +} + static int at24_write(void *priv, unsigned int off, void *val, size_t count) { struct at24_data *at24 = priv; -- cgit v1.2.3-59-g8ed1b From 2da78ac3ba577e0e4c9f13cbfce51db5a74f7ba3 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 6 Jun 2016 10:48:45 +0200 Subject: eeprom: at24: coding style fixes Align the arguments in broken lines with the arguments list's opening brackets and make checkpatch.pl happy by converting 'unsigned' into 'unsigned int'. Signed-off-by: Bartosz Golaszewski Signed-off-by: Wolfram Sang --- drivers/misc/eeprom/at24.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index e12d76fcbce6..564a20113377 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -147,7 +147,7 @@ MODULE_DEVICE_TABLE(acpi, at24_acpi_ids); * Assumes that sanity checks for offset happened at sysfs-layer. */ static struct i2c_client *at24_translate_offset(struct at24_data *at24, - unsigned *offset) + unsigned int *offset) { unsigned i; @@ -163,7 +163,7 @@ static struct i2c_client *at24_translate_offset(struct at24_data *at24, } static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, - unsigned offset, size_t count) + unsigned int offset, size_t count) { struct i2c_msg msg[2]; u8 msgbuf[2]; @@ -258,7 +258,7 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, * writes at most one page. */ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf, - unsigned offset, size_t count) + unsigned int offset, size_t count) { struct i2c_client *client; struct i2c_msg msg; @@ -400,7 +400,7 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count) #ifdef CONFIG_OF static void at24_get_ofdata(struct i2c_client *client, - struct at24_platform_data *chip) + struct at24_platform_data *chip) { const __be32 *val; struct device_node *node = client->dev.of_node; @@ -415,7 +415,7 @@ static void at24_get_ofdata(struct i2c_client *client, } #else static void at24_get_ofdata(struct i2c_client *client, - struct at24_platform_data *chip) + struct at24_platform_data *chip) { } #endif /* CONFIG_OF */ -- cgit v1.2.3-59-g8ed1b From 318aa9c66b337924f96caffab689553e1875aadf Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 6 Jun 2016 10:48:46 +0200 Subject: eeprom: at24: call read/write functions via function pointers The first step in simplifying the read and write functions is to call them via function pointers stored in at24_data. When we eventually split the routines into smaller ones (depending on whether they use smbus or i2c operations) we'll simply assign them to said pointers instead of checking the flags at runtime every time we read/write. Signed-off-by: Bartosz Golaszewski Signed-off-by: Wolfram Sang --- drivers/misc/eeprom/at24.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 564a20113377..0621937e7b3a 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -58,6 +58,10 @@ struct at24_data { int use_smbus; int use_smbus_write; + ssize_t (*read_func)(struct at24_data *, char *, unsigned int, size_t); + ssize_t (*write_func)(struct at24_data *, + const char *, unsigned int, size_t); + /* * Lock protects against activities from other Linux tasks, * but not from changes by other I2C masters. @@ -351,7 +355,7 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count) while (count) { int status; - status = at24_eeprom_read(at24, buf, off, count); + status = at24->read_func(at24, buf, off, count); if (status < 0) { mutex_unlock(&at24->lock); return status; @@ -383,7 +387,7 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count) while (count) { int status; - status = at24_eeprom_write(at24, buf, off, count); + status = at24->write_func(at24, buf, off, count); if (status < 0) { mutex_unlock(&at24->lock); return status; @@ -518,6 +522,9 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) at24->chip = chip; at24->num_addresses = num_addresses; + at24->read_func = at24_eeprom_read; + at24->write_func = at24_eeprom_write; + writable = !(chip.flags & AT24_FLAG_READONLY); if (writable) { if (!use_smbus || use_smbus_write) { -- cgit v1.2.3-59-g8ed1b From 9344a81efb885cc0d5b29dd214df66e332aa0129 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 6 Jun 2016 10:48:47 +0200 Subject: eeprom: at24: hide the read/write loop behind a macro Before splitting the read/write routines into smaller, more specialized functions, unduplicate some code in advance. Use a 'for' loop instead of 'do while' when waiting for the previous write to complete and hide it behind a macro. Signed-off-by: Bartosz Golaszewski Signed-off-by: Wolfram Sang --- drivers/misc/eeprom/at24.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 0621937e7b3a..2efb572757cc 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -113,6 +113,22 @@ MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)"); ((1 << AT24_SIZE_FLAGS | (_flags)) \ << AT24_SIZE_BYTELEN | ilog2(_len)) +/* + * Both reads and writes fail if the previous write didn't complete yet. This + * macro loops a few times waiting at least long enough for one entire page + * write to work. + * + * It takes two parameters: a variable in which the future timeout in jiffies + * will be stored and a temporary variable holding the time of the last + * iteration of processing the request. Both should be unsigned integers + * holding at least 32 bits. + */ +#define loop_until_timeout(tout, op_time) \ + for (tout = jiffies + msecs_to_jiffies(write_timeout), \ + op_time = jiffies; \ + time_before(op_time, tout); \ + usleep_range(1000, 1500), op_time = jiffies) + static const struct i2c_device_id at24_ids[] = { /* needs 8 addresses as A0-A2 are ignored */ { "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) }, @@ -225,14 +241,7 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, msg[1].len = count; } - /* - * Reads fail if the previous write didn't complete yet. We may - * loop a few times until this one succeeds, waiting at least - * long enough for one entire page write to work. - */ - timeout = jiffies + msecs_to_jiffies(write_timeout); - do { - read_time = jiffies; + loop_until_timeout(timeout, read_time) { if (at24->use_smbus) { status = i2c_smbus_read_i2c_block_data_or_emulated(client, offset, count, buf); @@ -246,9 +255,7 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, if (status == count) return count; - - usleep_range(1000, 1500); - } while (time_before(read_time, timeout)); + } return -ETIMEDOUT; } @@ -299,14 +306,7 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf, msg.len = i + count; } - /* - * Writes fail if the previous one didn't complete yet. We may - * loop a few times until this one succeeds, waiting at least - * long enough for one entire page write to work. - */ - timeout = jiffies + msecs_to_jiffies(write_timeout); - do { - write_time = jiffies; + loop_until_timeout(timeout, write_time) { if (at24->use_smbus_write) { switch (at24->use_smbus_write) { case I2C_SMBUS_I2C_BLOCK_DATA: @@ -331,9 +331,7 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf, if (status == count) return count; - - usleep_range(1000, 1500); - } while (time_before(write_time, timeout)); + } return -ETIMEDOUT; } -- cgit v1.2.3-59-g8ed1b From 9afd6866bf88b6a652136c70197e48fe837dbc01 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 6 Jun 2016 10:48:48 +0200 Subject: eeprom: at24: split at24_eeprom_read() into specialized functions Split at24_eeprom_read() into two smaller functions - one for the i2c operations and one for the smbus extensions. Assign them in at24_probe() depending on the bus capabilities. Also: in order to avoid duplications move the comments related to offset calculations above the at24_translate_offset() routine. Signed-off-by: Bartosz Golaszewski Signed-off-by: Wolfram Sang --- drivers/misc/eeprom/at24.c | 125 +++++++++++++++++++++++++-------------------- 1 file changed, 71 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 2efb572757cc..e7db1377e210 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -165,6 +165,19 @@ MODULE_DEVICE_TABLE(acpi, at24_acpi_ids); * This routine supports chips which consume multiple I2C addresses. It * computes the addressing information to be used for a given r/w request. * Assumes that sanity checks for offset happened at sysfs-layer. + * + * Slave address and byte offset derive from the offset. Always + * set the byte address; on a multi-master board, another master + * may have changed the chip's "current" address pointer. + * + * REVISIT some multi-address chips don't rollover page reads to + * the next slave address, so we may need to truncate the count. + * Those chips might need another quirk flag. + * + * If the real hardware used four adjacent 24c02 chips and that + * were misconfigured as one 24c08, that would be a similar effect: + * one "eeprom" file not four, but larger reads would fail when + * they crossed certain pages. */ static struct i2c_client *at24_translate_offset(struct at24_data *at24, unsigned int *offset) @@ -182,74 +195,77 @@ static struct i2c_client *at24_translate_offset(struct at24_data *at24, return at24->client[i]; } -static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, - unsigned int offset, size_t count) +static ssize_t at24_eeprom_read_smbus(struct at24_data *at24, char *buf, + unsigned int offset, size_t count) { - struct i2c_msg msg[2]; - u8 msgbuf[2]; + unsigned long timeout, read_time; struct i2c_client *client; + int status; + + client = at24_translate_offset(at24, &offset); + + if (count > io_limit) + count = io_limit; + + /* Smaller eeproms can work given some SMBus extension calls */ + if (count > I2C_SMBUS_BLOCK_MAX) + count = I2C_SMBUS_BLOCK_MAX; + + loop_until_timeout(timeout, read_time) { + status = i2c_smbus_read_i2c_block_data_or_emulated(client, + offset, + count, buf); + + dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n", + count, offset, status, jiffies); + + if (status == count) + return count; + } + + return -ETIMEDOUT; +} + +static ssize_t at24_eeprom_read_i2c(struct at24_data *at24, char *buf, + unsigned int offset, size_t count) +{ unsigned long timeout, read_time; + struct i2c_client *client; + struct i2c_msg msg[2]; int status, i; + u8 msgbuf[2]; memset(msg, 0, sizeof(msg)); - - /* - * REVISIT some multi-address chips don't rollover page reads to - * the next slave address, so we may need to truncate the count. - * Those chips might need another quirk flag. - * - * If the real hardware used four adjacent 24c02 chips and that - * were misconfigured as one 24c08, that would be a similar effect: - * one "eeprom" file not four, but larger reads would fail when - * they crossed certain pages. - */ - - /* - * Slave address and byte offset derive from the offset. Always - * set the byte address; on a multi-master board, another master - * may have changed the chip's "current" address pointer. - */ client = at24_translate_offset(at24, &offset); if (count > io_limit) count = io_limit; - if (at24->use_smbus) { - /* Smaller eeproms can work given some SMBus extension calls */ - if (count > I2C_SMBUS_BLOCK_MAX) - count = I2C_SMBUS_BLOCK_MAX; - } else { - /* - * When we have a better choice than SMBus calls, use a - * combined I2C message. Write address; then read up to - * io_limit data bytes. Note that read page rollover helps us - * here (unlike writes). msgbuf is u8 and will cast to our - * needs. - */ - i = 0; - if (at24->chip.flags & AT24_FLAG_ADDR16) - msgbuf[i++] = offset >> 8; - msgbuf[i++] = offset; + /* + * When we have a better choice than SMBus calls, use a combined I2C + * message. Write address; then read up to io_limit data bytes. Note + * that read page rollover helps us here (unlike writes). msgbuf is + * u8 and will cast to our needs. + */ + i = 0; + if (at24->chip.flags & AT24_FLAG_ADDR16) + msgbuf[i++] = offset >> 8; + msgbuf[i++] = offset; - msg[0].addr = client->addr; - msg[0].buf = msgbuf; - msg[0].len = i; + msg[0].addr = client->addr; + msg[0].buf = msgbuf; + msg[0].len = i; - msg[1].addr = client->addr; - msg[1].flags = I2C_M_RD; - msg[1].buf = buf; - msg[1].len = count; - } + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].buf = buf; + msg[1].len = count; loop_until_timeout(timeout, read_time) { - if (at24->use_smbus) { - status = i2c_smbus_read_i2c_block_data_or_emulated(client, offset, - count, buf); - } else { - status = i2c_transfer(client->adapter, msg, 2); - if (status == 2) - status = count; - } + status = i2c_transfer(client->adapter, msg, 2); + if (status == 2) + status = count; + dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n", count, offset, status, jiffies); @@ -520,7 +536,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) at24->chip = chip; at24->num_addresses = num_addresses; - at24->read_func = at24_eeprom_read; + at24->read_func = at24->use_smbus ? at24_eeprom_read_smbus + : at24_eeprom_read_i2c; at24->write_func = at24_eeprom_write; writable = !(chip.flags & AT24_FLAG_READONLY); -- cgit v1.2.3-59-g8ed1b From cd0c861542fc81bd3087ff1e8af0f87e2a8794c3 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 6 Jun 2016 10:48:49 +0200 Subject: eeprom: at24: split at24_eeprom_write() into specialized functions Split at24_eeprom_write() into three smaller functions - one for the i2c operations and two for the smbus extensions (separate routines for block and byte transfers). Assign them in at24_probe() depending on the bus capabilities. Also: in order to avoid duplications move code adjusting the count argument into a separate function and use it for i2c and smbus block writes (no need for a roll-over for byte writes as we're always writing one byte). Signed-off-by: Bartosz Golaszewski Signed-off-by: Wolfram Sang --- drivers/misc/eeprom/at24.c | 134 ++++++++++++++++++++++++++++++--------------- 1 file changed, 91 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index e7db1377e210..6acf35af271c 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -281,21 +281,15 @@ static ssize_t at24_eeprom_read_i2c(struct at24_data *at24, char *buf, * chip is normally write protected. But there are plenty of product * variants here, including OTP fuses and partial chip protect. * - * We only use page mode writes; the alternative is sloooow. This routine - * writes at most one page. + * We only use page mode writes; the alternative is sloooow. These routines + * write at most one page. */ -static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf, - unsigned int offset, size_t count) + +static size_t at24_adjust_write_count(struct at24_data *at24, + unsigned int offset, size_t count) { - struct i2c_client *client; - struct i2c_msg msg; - ssize_t status = 0; - unsigned long timeout, write_time; unsigned next_page; - /* Get corresponding I2C address and adjust offset */ - client = at24_translate_offset(at24, &offset); - /* write_max is at most a page */ if (count > at24->write_max) count = at24->write_max; @@ -305,43 +299,90 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf, if (offset + count > next_page) count = next_page - offset; - /* If we'll use I2C calls for I/O, set up the message */ - if (!at24->use_smbus) { - int i = 0; + return count; +} + +static ssize_t at24_eeprom_write_smbus_block(struct at24_data *at24, + const char *buf, + unsigned int offset, size_t count) +{ + unsigned long timeout, write_time; + struct i2c_client *client; + ssize_t status = 0; + + client = at24_translate_offset(at24, &offset); + count = at24_adjust_write_count(at24, offset, count); - msg.addr = client->addr; - msg.flags = 0; + loop_until_timeout(timeout, write_time) { + status = i2c_smbus_write_i2c_block_data(client, + offset, count, buf); + if (status == 0) + status = count; - /* msg.buf is u8 and casts will mask the values */ - msg.buf = at24->writebuf; - if (at24->chip.flags & AT24_FLAG_ADDR16) - msg.buf[i++] = offset >> 8; + dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n", + count, offset, status, jiffies); - msg.buf[i++] = offset; - memcpy(&msg.buf[i], buf, count); - msg.len = i + count; + if (status == count) + return count; } + return -ETIMEDOUT; +} + +static ssize_t at24_eeprom_write_smbus_byte(struct at24_data *at24, + const char *buf, + unsigned int offset, size_t count) +{ + unsigned long timeout, write_time; + struct i2c_client *client; + ssize_t status = 0; + + client = at24_translate_offset(at24, &offset); + loop_until_timeout(timeout, write_time) { - if (at24->use_smbus_write) { - switch (at24->use_smbus_write) { - case I2C_SMBUS_I2C_BLOCK_DATA: - status = i2c_smbus_write_i2c_block_data(client, - offset, count, buf); - break; - case I2C_SMBUS_BYTE_DATA: - status = i2c_smbus_write_byte_data(client, - offset, buf[0]); - break; - } - - if (status == 0) - status = count; - } else { - status = i2c_transfer(client->adapter, &msg, 1); - if (status == 1) - status = count; - } + status = i2c_smbus_write_byte_data(client, offset, buf[0]); + if (status == 0) + status = count; + + dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n", + count, offset, status, jiffies); + + if (status == count) + return count; + } + + return -ETIMEDOUT; +} + +static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf, + unsigned int offset, size_t count) +{ + unsigned long timeout, write_time; + struct i2c_client *client; + struct i2c_msg msg; + ssize_t status = 0; + int i = 0; + + client = at24_translate_offset(at24, &offset); + count = at24_adjust_write_count(at24, offset, count); + + msg.addr = client->addr; + msg.flags = 0; + + /* msg.buf is u8 and casts will mask the values */ + msg.buf = at24->writebuf; + if (at24->chip.flags & AT24_FLAG_ADDR16) + msg.buf[i++] = offset >> 8; + + msg.buf[i++] = offset; + memcpy(&msg.buf[i], buf, count); + msg.len = i + count; + + loop_until_timeout(timeout, write_time) { + status = i2c_transfer(client->adapter, &msg, 1); + if (status == 1) + status = count; + dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n", count, offset, status, jiffies); @@ -538,7 +579,14 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) at24->read_func = at24->use_smbus ? at24_eeprom_read_smbus : at24_eeprom_read_i2c; - at24->write_func = at24_eeprom_write; + if (at24->use_smbus) { + if (at24->use_smbus_write == I2C_SMBUS_I2C_BLOCK_DATA) + at24->write_func = at24_eeprom_write_smbus_block; + else + at24->write_func = at24_eeprom_write_smbus_byte; + } else { + at24->write_func = at24_eeprom_write_i2c; + } writable = !(chip.flags & AT24_FLAG_READONLY); if (writable) { -- cgit v1.2.3-59-g8ed1b From 818d0220d857cc92cb37600758c5b47c3df3782b Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 6 Jun 2016 10:48:51 +0200 Subject: eeprom: at24: support reading the serial number for 24csxx The chips from the at24cs family have two memory areas - a regular read-write block and a read-only area containing the serial number. The latter is visible on a different slave address (the address of the rw memory block + 0x08). In order to access both blocks the user needs to instantiate a regular at24c device for the rw block address and a corresponding at24cs device on the serial number block address. Add a function that allows to access the serial number and assign it to at24->read_func if the chip allows serial number read operations and the driver was passed the relevant flag for this device. Signed-off-by: Bartosz Golaszewski Signed-off-by: Wolfram Sang --- drivers/misc/eeprom/at24.c | 80 +++++++++++++++++++++++++++++++++++++- include/linux/platform_data/at24.h | 1 + 2 files changed, 79 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 6acf35af271c..3b27ff14876c 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -134,16 +134,34 @@ static const struct i2c_device_id at24_ids[] = { { "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) }, /* old variants can't be handled with this generic entry! */ { "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) }, + { "24cs01", AT24_DEVICE_MAGIC(16, + AT24_FLAG_SERIAL | AT24_FLAG_READONLY) }, { "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) }, + { "24cs02", AT24_DEVICE_MAGIC(16, + AT24_FLAG_SERIAL | AT24_FLAG_READONLY) }, /* spd is a 24c02 in memory DIMMs */ { "spd", AT24_DEVICE_MAGIC(2048 / 8, AT24_FLAG_READONLY | AT24_FLAG_IRUGO) }, { "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) }, + { "24cs04", AT24_DEVICE_MAGIC(16, + AT24_FLAG_SERIAL | AT24_FLAG_READONLY) }, /* 24rf08 quirk is handled at i2c-core */ { "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) }, + { "24cs08", AT24_DEVICE_MAGIC(16, + AT24_FLAG_SERIAL | AT24_FLAG_READONLY) }, { "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) }, + { "24cs16", AT24_DEVICE_MAGIC(16, + AT24_FLAG_SERIAL | AT24_FLAG_READONLY) }, { "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) }, + { "24cs32", AT24_DEVICE_MAGIC(16, + AT24_FLAG_ADDR16 | + AT24_FLAG_SERIAL | + AT24_FLAG_READONLY) }, { "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) }, + { "24cs64", AT24_DEVICE_MAGIC(16, + AT24_FLAG_ADDR16 | + AT24_FLAG_SERIAL | + AT24_FLAG_READONLY) }, { "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) }, { "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) }, { "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) }, @@ -276,6 +294,59 @@ static ssize_t at24_eeprom_read_i2c(struct at24_data *at24, char *buf, return -ETIMEDOUT; } +static ssize_t at24_eeprom_read_serial(struct at24_data *at24, char *buf, + unsigned int offset, size_t count) +{ + unsigned long timeout, read_time; + struct i2c_client *client; + struct i2c_msg msg[2]; + u8 addrbuf[2]; + int status; + + client = at24_translate_offset(at24, &offset); + + memset(msg, 0, sizeof(msg)); + msg[0].addr = client->addr; + msg[0].buf = addrbuf; + + /* + * The address pointer of the device is shared between the regular + * EEPROM array and the serial number block. The dummy write (part of + * the sequential read protocol) ensures the address pointer is reset + * to the desired position. + */ + if (at24->chip.flags & AT24_FLAG_ADDR16) { + /* + * For 16 bit address pointers, the word address must contain + * a '10' sequence in bits 11 and 10 regardless of the + * intended position of the address pointer. + */ + addrbuf[0] = 0x08; + addrbuf[1] = offset; + msg[0].len = 2; + } else { + /* + * Otherwise the word address must begin with a '10' sequence, + * regardless of the intended address. + */ + addrbuf[0] = 0x80 + offset; + msg[0].len = 1; + } + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].buf = buf; + msg[1].len = count; + + loop_until_timeout(timeout, read_time) { + status = i2c_transfer(client->adapter, msg, 2); + if (status == 2) + return count; + } + + return -ETIMEDOUT; +} + /* * Note that if the hardware write-protect pin is pulled high, the whole * chip is normally write protected. But there are plenty of product @@ -577,8 +648,13 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) at24->chip = chip; at24->num_addresses = num_addresses; - at24->read_func = at24->use_smbus ? at24_eeprom_read_smbus - : at24_eeprom_read_i2c; + if (chip.flags & AT24_FLAG_SERIAL) { + at24->read_func = at24_eeprom_read_serial; + } else { + at24->read_func = at24->use_smbus ? at24_eeprom_read_smbus + : at24_eeprom_read_i2c; + } + if (at24->use_smbus) { if (at24->use_smbus_write == I2C_SMBUS_I2C_BLOCK_DATA) at24->write_func = at24_eeprom_write_smbus_block; diff --git a/include/linux/platform_data/at24.h b/include/linux/platform_data/at24.h index fcfdfe3c0e9c..d59587473aed 100644 --- a/include/linux/platform_data/at24.h +++ b/include/linux/platform_data/at24.h @@ -48,6 +48,7 @@ struct at24_platform_data { #define AT24_FLAG_READONLY BIT(6) /* sysfs-entry will be read-only */ #define AT24_FLAG_IRUGO BIT(5) /* sysfs-entry will be world-readable */ #define AT24_FLAG_TAKE8ADDR BIT(4) /* take always 8 addresses (24c00) */ +#define AT24_FLAG_SERIAL BIT(3) /* factory-programmed serial number */ void (*setup)(struct nvmem_device *nvmem, void *context); void *context; -- cgit v1.2.3-59-g8ed1b From 0b813658c11532be90cbf5f579a8ba45a8cc9dbf Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 6 Jun 2016 10:48:54 +0200 Subject: eeprom: at24: add support for at24mac series Add a new read function to the at24 driver allowing to retrieve the factory-programmed mac address embedded in chips from the at24mac family. These chips can be instantiated similarily to the at24cs family, except that there's no way of having access to both the serial number and the mac address at the same time - the user must instantiate either an at24cs or at24mac device as both special memory areas are accessible on the same slave address. Signed-off-by: Bartosz Golaszewski Signed-off-by: Wolfram Sang --- drivers/misc/eeprom/at24.c | 42 ++++++++++++++++++++++++++++++++++++++ include/linux/platform_data/at24.h | 1 + 2 files changed, 43 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 3b27ff14876c..04e91e331fc5 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -139,6 +139,10 @@ static const struct i2c_device_id at24_ids[] = { { "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) }, { "24cs02", AT24_DEVICE_MAGIC(16, AT24_FLAG_SERIAL | AT24_FLAG_READONLY) }, + { "24mac402", AT24_DEVICE_MAGIC(48 / 8, + AT24_FLAG_MAC | AT24_FLAG_READONLY) }, + { "24mac602", AT24_DEVICE_MAGIC(64 / 8, + AT24_FLAG_MAC | AT24_FLAG_READONLY) }, /* spd is a 24c02 in memory DIMMs */ { "spd", AT24_DEVICE_MAGIC(2048 / 8, AT24_FLAG_READONLY | AT24_FLAG_IRUGO) }, @@ -347,6 +351,36 @@ static ssize_t at24_eeprom_read_serial(struct at24_data *at24, char *buf, return -ETIMEDOUT; } +static ssize_t at24_eeprom_read_mac(struct at24_data *at24, char *buf, + unsigned int offset, size_t count) +{ + unsigned long timeout, read_time; + struct i2c_client *client; + struct i2c_msg msg[2]; + u8 addrbuf[2]; + int status; + + client = at24_translate_offset(at24, &offset); + + memset(msg, 0, sizeof(msg)); + msg[0].addr = client->addr; + msg[0].buf = addrbuf; + addrbuf[0] = 0x90 + offset; + msg[0].len = 1; + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].buf = buf; + msg[1].len = count; + + loop_until_timeout(timeout, read_time) { + status = i2c_transfer(client->adapter, msg, 2); + if (status == 2) + return count; + } + + return -ETIMEDOUT; +} + /* * Note that if the hardware write-protect pin is pulled high, the whole * chip is normally write protected. But there are plenty of product @@ -648,8 +682,16 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) at24->chip = chip; at24->num_addresses = num_addresses; + if ((chip.flags & AT24_FLAG_SERIAL) && (chip.flags & AT24_FLAG_MAC)) { + dev_err(&client->dev, + "invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC."); + return -EINVAL; + } + if (chip.flags & AT24_FLAG_SERIAL) { at24->read_func = at24_eeprom_read_serial; + } else if (chip.flags & AT24_FLAG_MAC) { + at24->read_func = at24_eeprom_read_mac; } else { at24->read_func = at24->use_smbus ? at24_eeprom_read_smbus : at24_eeprom_read_i2c; diff --git a/include/linux/platform_data/at24.h b/include/linux/platform_data/at24.h index d59587473aed..271a4e25af67 100644 --- a/include/linux/platform_data/at24.h +++ b/include/linux/platform_data/at24.h @@ -49,6 +49,7 @@ struct at24_platform_data { #define AT24_FLAG_IRUGO BIT(5) /* sysfs-entry will be world-readable */ #define AT24_FLAG_TAKE8ADDR BIT(4) /* take always 8 addresses (24c00) */ #define AT24_FLAG_SERIAL BIT(3) /* factory-programmed serial number */ +#define AT24_FLAG_MAC BIT(2) /* factory-programmed mac address */ void (*setup)(struct nvmem_device *nvmem, void *context); void *context; -- cgit v1.2.3-59-g8ed1b From 24da3cc0e25f48e12656226e5ed313573a3b443f Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Sun, 17 Jul 2016 20:40:06 +0200 Subject: eeprom: at24: tweak the loop_until_timeout() macro loop_until_timeout() replaced a do {} while loop in the at24 driver with a for loop which, under certain circumstances (such as heavy load or low value of the write_timeout argument), can lead to the code in the loop never being executed. Make sure that at least one iteration of the code enclosed within loop_until_timeout() is always executed. Suggested-by: Wolfram Sang Signed-off-by: Bartosz Golaszewski Signed-off-by: Wolfram Sang --- drivers/misc/eeprom/at24.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 04e91e331fc5..3cdf8e1ca0ad 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -116,7 +116,8 @@ MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)"); /* * Both reads and writes fail if the previous write didn't complete yet. This * macro loops a few times waiting at least long enough for one entire page - * write to work. + * write to work while making sure that at least one iteration is run before + * checking the break condition. * * It takes two parameters: a variable in which the future timeout in jiffies * will be stored and a temporary variable holding the time of the last @@ -124,9 +125,8 @@ MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)"); * holding at least 32 bits. */ #define loop_until_timeout(tout, op_time) \ - for (tout = jiffies + msecs_to_jiffies(write_timeout), \ - op_time = jiffies; \ - time_before(op_time, tout); \ + for (tout = jiffies + msecs_to_jiffies(write_timeout), op_time = 0; \ + op_time ? time_before(op_time, tout) : true; \ usleep_range(1000, 1500), op_time = jiffies) static const struct i2c_device_id at24_ids[] = { -- cgit v1.2.3-59-g8ed1b From 1847bbd709d0f736223cb4762033225cdfafbe5f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 16 Jul 2016 15:45:23 +0200 Subject: i2c: i2c-smbus: fix i2c_handle_smbus_host_notify documentation The parameter description is from a previous implementation, update it to describe the actual implementation. Signed-off-by: Jean Delvare Reviewed-by: Benjamin Tissoires Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-smbus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index f574995b41c1..b0d2679c60d1 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -302,8 +302,8 @@ EXPORT_SYMBOL_GPL(i2c_setup_smbus_host_notify); * i2c_handle_smbus_host_notify - Forward a Host Notify event to the correct * I2C client. * @host_notify: the struct host_notify attached to the relevant adapter - * @data: the Host Notify data which contains the payload and address of the - * client + * @addr: the I2C address of the notifying device + * @data: the payload of the notification * Context: can't sleep * * Helper function to be called from an I2C bus driver's interrupt -- cgit v1.2.3-59-g8ed1b From d380a20486b84895223d17a31d811a1195f6c50d Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 18 Jul 2016 12:39:43 +0200 Subject: i2c: Update the description of I2C_SMBUS We support the SMBus Host Notify protocol now. Signed-off-by: Jean Delvare Reviewed-by: Benjamin Tissoires Signed-off-by: Wolfram Sang --- drivers/i2c/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 78fbee463628..d223650a97e4 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -88,8 +88,8 @@ config I2C_SMBUS tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO help Say Y here if you want support for SMBus extensions to the I2C - specification. At the moment, the only supported extension is - the SMBus alert protocol. + specification. At the moment, two extensions are supported: + the SMBus Alert protocol and the SMBus Host Notify protocol. This support is also available as a module. If so, the module will be called i2c-smbus. -- cgit v1.2.3-59-g8ed1b From 38d0fc4662474c6219166505d0a68b45a583fcfb Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 19 Jul 2016 05:54:56 +0200 Subject: Revert "i2c: core: Add function for finding the bus speed from ACPI" This reverts commit 55d38d060e999ca1a3ea6eb132105a0301e4cd04. There were too heavy merge conflicts and the driver code making use of this was not ready yet anyhow. So, we wait one cycle. Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 74 ++++++++++---------------------------------------- include/linux/i2c.h | 9 ------ 2 files changed, 15 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 347494a8750e..abe41369eec1 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -105,13 +105,11 @@ struct gsb_buffer { struct i2c_acpi_lookup { struct i2c_board_info *info; - struct i2c_adapter *adapter; /* set only when registering slaves */ acpi_handle adapter_handle; acpi_handle device_handle; - u32 min_speed; }; -static int i2c_acpi_find_resource(struct acpi_resource *ares, void *data) +static int i2c_acpi_find_address(struct acpi_resource *ares, void *data) { struct i2c_acpi_lookup *lookup = data; struct i2c_board_info *info = lookup->info; @@ -137,20 +135,17 @@ static int i2c_acpi_find_resource(struct acpi_resource *ares, void *data) info->addr = sb->slave_address; if (sb->access_mode == ACPI_I2C_10BIT_MODE) info->flags |= I2C_CLIENT_TEN; - /* Save speed of the slowest device */ - if (sb->connection_speed < lookup->min_speed) - lookup->min_speed = sb->connection_speed; } return 1; } -static acpi_status i2c_acpi_slave_lookup(acpi_handle handle, u32 level, - void *data, void **return_value) +static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level, + void *data, void **return_value) { - struct i2c_acpi_lookup *lookup = data; - struct i2c_adapter *adapter = lookup->adapter; + struct i2c_adapter *adapter = data; struct list_head resource_list; + struct i2c_acpi_lookup lookup; struct resource_entry *entry; struct i2c_board_info info; struct acpi_device *adev; @@ -164,8 +159,10 @@ static acpi_status i2c_acpi_slave_lookup(acpi_handle handle, u32 level, memset(&info, 0, sizeof(info)); info.fwnode = acpi_fwnode_handle(adev); - lookup->device_handle = handle; - lookup->info = &info; + memset(&lookup, 0, sizeof(lookup)); + lookup.adapter_handle = ACPI_HANDLE(&adapter->dev); + lookup.device_handle = handle; + lookup.info = &info; /* * Look up for I2cSerialBus resource with ResourceSource that @@ -173,10 +170,10 @@ static acpi_status i2c_acpi_slave_lookup(acpi_handle handle, u32 level, */ INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, - i2c_acpi_find_resource, lookup); + i2c_acpi_find_address, &lookup); acpi_dev_free_resource_list(&resource_list); - if (ret < 0 || !info.addr || !lookup->adapter) + if (ret < 0 || !info.addr) return AE_OK; /* Then fill IRQ number if any */ @@ -207,14 +204,6 @@ static acpi_status i2c_acpi_slave_lookup(acpi_handle handle, u32 level, #define I2C_ACPI_MAX_SCAN_DEPTH 32 -static acpi_status i2c_acpi_walk(struct i2c_acpi_lookup *lookup) -{ - return acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - I2C_ACPI_MAX_SCAN_DEPTH, - i2c_acpi_slave_lookup, NULL, - lookup, NULL); -} - /** * i2c_acpi_register_devices - enumerate I2C slave devices behind adapter * @adap: pointer to adapter @@ -225,52 +214,19 @@ static acpi_status i2c_acpi_walk(struct i2c_acpi_lookup *lookup) */ static void i2c_acpi_register_devices(struct i2c_adapter *adap) { - struct i2c_acpi_lookup lookup; acpi_status status; if (!has_acpi_companion(&adap->dev)) return; - memset(&lookup, 0, sizeof(lookup)); - lookup.adapter = adap; - lookup.adapter_handle = ACPI_HANDLE(&adap->dev); - - status = i2c_acpi_walk(&lookup); + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + I2C_ACPI_MAX_SCAN_DEPTH, + i2c_acpi_add_device, NULL, + adap, NULL); if (ACPI_FAILURE(status)) dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); } -/** - * i2c_acpi_find_bus_speed - find I2C bus speed from ACPI - * @dev: The device owning the bus - * - * Find the I2C bus speed by walking the ACPI namespace for all I2C slaves - * devices connected to this bus and use the speed of slowest device. - * - * Returns the speed in Hz or zero - */ -u32 i2c_acpi_find_bus_speed(struct device *dev) -{ - struct i2c_acpi_lookup lookup; - acpi_status status; - - if (!has_acpi_companion(dev)) - return 0; - - memset(&lookup, 0, sizeof(lookup)); - lookup.adapter_handle = ACPI_HANDLE(dev); - lookup.min_speed = UINT_MAX; - - status = i2c_acpi_walk(&lookup); - if (ACPI_FAILURE(status)) { - dev_warn(dev, "unable to find I2C bus speed from ACPI\n"); - return 0; - } - - return lookup.min_speed != UINT_MAX ? lookup.min_speed : 0; -} -EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed); - #else /* CONFIG_ACPI */ static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { } #endif /* CONFIG_ACPI */ diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 5cde08719fb6..fffdc270ca18 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -766,13 +766,4 @@ static inline struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node } #endif /* CONFIG_OF */ -#if IS_ENABLED(CONFIG_ACPI) -u32 i2c_acpi_find_bus_speed(struct device *dev); -#else -static inline u32 i2c_acpi_find_bus_speed(struct device *dev) -{ - return 0; -} -#endif /* CONFIG_ACPI */ - #endif /* _LINUX_I2C_H */ -- cgit v1.2.3-59-g8ed1b From 5b40f121ced215544531dc00201ea4e8f68671c1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 19 Jul 2016 05:56:09 +0200 Subject: Revert "i2c: core: Cleanup I2C ACPI namespace" This reverts commit a7003b65801e17a19617a509b2dbae3442ddd709.There were too heavy merge conflicts and the driver code making use of this was not ready yet anyhow. So, we wait one cycle. Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 54 +++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index abe41369eec1..b2b34a0a35a1 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -88,7 +88,7 @@ void i2c_transfer_trace_unreg(void) } #if defined(CONFIG_ACPI) -struct i2c_acpi_handler_data { +struct acpi_i2c_handler_data { struct acpi_connection_info info; struct i2c_adapter *adapter; }; @@ -103,15 +103,15 @@ struct gsb_buffer { }; } __packed; -struct i2c_acpi_lookup { +struct acpi_i2c_lookup { struct i2c_board_info *info; acpi_handle adapter_handle; acpi_handle device_handle; }; -static int i2c_acpi_find_address(struct acpi_resource *ares, void *data) +static int acpi_i2c_find_address(struct acpi_resource *ares, void *data) { - struct i2c_acpi_lookup *lookup = data; + struct acpi_i2c_lookup *lookup = data; struct i2c_board_info *info = lookup->info; struct acpi_resource_i2c_serialbus *sb; acpi_handle adapter_handle; @@ -140,12 +140,12 @@ static int i2c_acpi_find_address(struct acpi_resource *ares, void *data) return 1; } -static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level, +static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, void *data, void **return_value) { struct i2c_adapter *adapter = data; struct list_head resource_list; - struct i2c_acpi_lookup lookup; + struct acpi_i2c_lookup lookup; struct resource_entry *entry; struct i2c_board_info info; struct acpi_device *adev; @@ -170,7 +170,7 @@ static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level, */ INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, - i2c_acpi_find_address, &lookup); + acpi_i2c_find_address, &lookup); acpi_dev_free_resource_list(&resource_list); if (ret < 0 || !info.addr) @@ -202,17 +202,17 @@ static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level, return AE_OK; } -#define I2C_ACPI_MAX_SCAN_DEPTH 32 +#define ACPI_I2C_MAX_SCAN_DEPTH 32 /** - * i2c_acpi_register_devices - enumerate I2C slave devices behind adapter + * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter * @adap: pointer to adapter * * Enumerate all I2C slave devices behind this adapter by walking the ACPI * namespace. When a device is found it will be added to the Linux device * model and bound to the corresponding ACPI handle. */ -static void i2c_acpi_register_devices(struct i2c_adapter *adap) +static void acpi_i2c_register_devices(struct i2c_adapter *adap) { acpi_status status; @@ -220,15 +220,15 @@ static void i2c_acpi_register_devices(struct i2c_adapter *adap) return; status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - I2C_ACPI_MAX_SCAN_DEPTH, - i2c_acpi_add_device, NULL, + ACPI_I2C_MAX_SCAN_DEPTH, + acpi_i2c_add_device, NULL, adap, NULL); if (ACPI_FAILURE(status)) dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); } #else /* CONFIG_ACPI */ -static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { } +static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { } #endif /* CONFIG_ACPI */ #ifdef CONFIG_ACPI_I2C_OPREGION @@ -293,12 +293,12 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, } static acpi_status -i2c_acpi_space_handler(u32 function, acpi_physical_address command, +acpi_i2c_space_handler(u32 function, acpi_physical_address command, u32 bits, u64 *value64, void *handler_context, void *region_context) { struct gsb_buffer *gsb = (struct gsb_buffer *)value64; - struct i2c_acpi_handler_data *data = handler_context; + struct acpi_i2c_handler_data *data = handler_context; struct acpi_connection_info *info = &data->info; struct acpi_resource_i2c_serialbus *sb; struct i2c_adapter *adapter = data->adapter; @@ -417,10 +417,10 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command, } -static int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) +static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) { acpi_handle handle; - struct i2c_acpi_handler_data *data; + struct acpi_i2c_handler_data *data; acpi_status status; if (!adapter->dev.parent) @@ -431,7 +431,7 @@ static int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) if (!handle) return -ENODEV; - data = kzalloc(sizeof(struct i2c_acpi_handler_data), + data = kzalloc(sizeof(struct acpi_i2c_handler_data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -445,7 +445,7 @@ static int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) status = acpi_install_address_space_handler(handle, ACPI_ADR_SPACE_GSBUS, - &i2c_acpi_space_handler, + &acpi_i2c_space_handler, NULL, data); if (ACPI_FAILURE(status)) { @@ -459,10 +459,10 @@ static int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) return 0; } -static void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) +static void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) { acpi_handle handle; - struct i2c_acpi_handler_data *data; + struct acpi_i2c_handler_data *data; acpi_status status; if (!adapter->dev.parent) @@ -475,7 +475,7 @@ static void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GSBUS, - &i2c_acpi_space_handler); + &acpi_i2c_space_handler); status = acpi_bus_get_private_data(handle, (void **)&data); if (ACPI_SUCCESS(status)) @@ -484,10 +484,10 @@ static void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) acpi_bus_detach_private_data(handle); } #else /* CONFIG_ACPI_I2C_OPREGION */ -static inline void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) +static inline void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) { } -static inline int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) +static inline int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) { return 0; } #endif /* CONFIG_ACPI_I2C_OPREGION */ @@ -1657,8 +1657,8 @@ static int i2c_register_adapter(struct i2c_adapter *adap) /* create pre-declared device nodes */ of_i2c_register_devices(adap); - i2c_acpi_register_devices(adap); - i2c_acpi_install_space_handler(adap); + acpi_i2c_register_devices(adap); + acpi_i2c_install_space_handler(adap); if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); @@ -1830,7 +1830,7 @@ void i2c_del_adapter(struct i2c_adapter *adap) return; } - i2c_acpi_remove_space_handler(adap); + acpi_i2c_remove_space_handler(adap); /* Tell drivers about this removal */ mutex_lock(&core_lock); bus_for_each_drv(&i2c_bus_type, NULL, adap, -- cgit v1.2.3-59-g8ed1b From 7dd91d52a813f99a95d20f539b777e9e6198b931 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 16 Jul 2016 02:36:38 +0300 Subject: i2c: efm32: fix a failure path in efm32_i2c_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is the only failure path in efm32_i2c_probe(), where clk_disable_unprepare() is missed. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Acked-by: Uwe Kleine-König Signed-off-by: Wolfram Sang Fixes: 1b5b23718b84 ("i2c: efm32: new bus driver") Cc: stable@kernel.org --- drivers/i2c/busses/i2c-efm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-efm32.c b/drivers/i2c/busses/i2c-efm32.c index 8eff62738877..e253598d764c 100644 --- a/drivers/i2c/busses/i2c-efm32.c +++ b/drivers/i2c/busses/i2c-efm32.c @@ -433,7 +433,7 @@ static int efm32_i2c_probe(struct platform_device *pdev) ret = request_irq(ddata->irq, efm32_i2c_irq, 0, DRIVER_NAME, ddata); if (ret < 0) { dev_err(&pdev->dev, "failed to request irq (%d)\n", ret); - return ret; + goto err_disable_clk; } ret = i2c_add_adapter(&ddata->adapter); -- cgit v1.2.3-59-g8ed1b From 85946abc961957df08c58acf838810f08c2a4594 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 1 Jun 2016 23:43:33 +0200 Subject: i2c: bcm2835: Don't complain on -EPROBE_DEFER from getting our clock Fixes dmesg spam when we just need to wait a moment for the clock driver to probe. Signed-off-by: Eric Anholt Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm2835.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index 818b051d25e6..d4f3239b5686 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -253,7 +253,8 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) i2c_dev->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(i2c_dev->clk)) { - dev_err(&pdev->dev, "Could not get clock\n"); + if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Could not get clock\n"); return PTR_ERR(i2c_dev->clk); } -- cgit v1.2.3-59-g8ed1b From 175c7080f2747b96e4b5352e4c38ddf9a0eacfdb Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 21 Jul 2016 12:11:01 -0400 Subject: i2c: i801: use IS_ENABLED() instead of checking for built-in or module The IS_ENABLED() macro checks if a Kconfig symbol has been enabled either built-in or as a module, use that macro instead of open coding the same. Using the macro makes the code more readable by helping abstract away some of the Kconfig built-in and module enable details. Signed-off-by: Javier Martinez Canillas Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 68cec6128ac0..5ef9b733d153 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -98,8 +98,7 @@ #include #include -#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \ - defined CONFIG_DMI +#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI #include #include #endif @@ -255,8 +254,7 @@ struct i801_priv { int len; u8 *data; -#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \ - defined CONFIG_DMI +#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI const struct i801_mux_config *mux_drvdata; struct platform_device *mux_pdev; #endif @@ -1133,8 +1131,7 @@ static void __init input_apanel_init(void) {} static void i801_probe_optional_slaves(struct i801_priv *priv) {} #endif /* CONFIG_X86 && CONFIG_DMI */ -#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \ - defined CONFIG_DMI +#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI static struct i801_mux_config i801_mux_config_asus_z8_d12 = { .gpio_chip = "gpio_ich", .values = { 0x02, 0x03 }, -- cgit v1.2.3-59-g8ed1b