aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/iosf_mbi.h39
-rw-r--r--arch/x86/platform/intel/iosf_mbi.c217
-rw-r--r--drivers/acpi/Kconfig2
-rw-r--r--drivers/acpi/pmic/intel_pmic_xpower.c21
-rw-r--r--drivers/i2c/busses/i2c-designware-baytrail.c139
-rw-r--r--drivers/i2c/busses/i2c-designware-common.c4
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h9
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c2
8 files changed, 250 insertions, 183 deletions
diff --git a/arch/x86/include/asm/iosf_mbi.h b/arch/x86/include/asm/iosf_mbi.h
index 3de0489deade..5270ff39b9af 100644
--- a/arch/x86/include/asm/iosf_mbi.h
+++ b/arch/x86/include/asm/iosf_mbi.h
@@ -105,8 +105,10 @@ int iosf_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask);
105 * the PMIC bus while another driver is also accessing the PMIC bus various bad 105 * the PMIC bus while another driver is also accessing the PMIC bus various bad
106 * things happen. 106 * things happen.
107 * 107 *
108 * To avoid these problems this function must be called before accessing the 108 * Call this function before sending requests to the P-Unit which may make it
109 * P-Unit or the PMIC, be it through iosf_mbi* functions or through other means. 109 * access the PMIC, be it through iosf_mbi* functions or through other means.
110 * This function will block all kernel access to the PMIC I2C bus, so that the
111 * P-Unit can safely access the PMIC over the shared I2C bus.
110 * 112 *
111 * Note on these systems the i2c-bus driver will request a sempahore from the 113 * Note on these systems the i2c-bus driver will request a sempahore from the
112 * P-Unit for exclusive access to the PMIC bus when i2c drivers are accessing 114 * P-Unit for exclusive access to the PMIC bus when i2c drivers are accessing
@@ -123,6 +125,31 @@ void iosf_mbi_punit_acquire(void);
123void iosf_mbi_punit_release(void); 125void iosf_mbi_punit_release(void);
124 126
125/** 127/**
128 * iosf_mbi_block_punit_i2c_access() - Block P-Unit accesses to the PMIC bus
129 *
130 * Call this function to block P-Unit access to the PMIC I2C bus, so that the
131 * kernel can safely access the PMIC over the shared I2C bus.
132 *
133 * This function acquires the P-Unit bus semaphore and notifies
134 * pmic_bus_access_notifier listeners that they may no longer access the
135 * P-Unit in a way which may cause it to access the shared I2C bus.
136 *
137 * Note this function may be called multiple times and the bus will not
138 * be released until iosf_mbi_unblock_punit_i2c_access() has been called the
139 * same amount of times.
140 *
141 * Return: Nonzero on error
142 */
143int iosf_mbi_block_punit_i2c_access(void);
144
145/*
146 * iosf_mbi_unblock_punit_i2c_access() - Release PMIC I2C bus block
147 *
148 * Release i2c access block gotten through iosf_mbi_block_punit_i2c_access().
149 */
150void iosf_mbi_unblock_punit_i2c_access(void);
151
152/**
126 * iosf_mbi_register_pmic_bus_access_notifier - Register PMIC bus notifier 153 * iosf_mbi_register_pmic_bus_access_notifier - Register PMIC bus notifier
127 * 154 *
128 * This function can be used by drivers which may need to acquire P-Unit 155 * This function can be used by drivers which may need to acquire P-Unit
@@ -159,14 +186,6 @@ int iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(
159 struct notifier_block *nb); 186 struct notifier_block *nb);
160 187
161/** 188/**
162 * iosf_mbi_call_pmic_bus_access_notifier_chain - Call PMIC bus notifier chain
163 *
164 * @val: action to pass into listener's notifier_call function
165 * @v: data pointer to pass into listener's notifier_call function
166 */
167int iosf_mbi_call_pmic_bus_access_notifier_chain(unsigned long val, void *v);
168
169/**
170 * iosf_mbi_assert_punit_acquired - Assert that the P-Unit has been acquired. 189 * iosf_mbi_assert_punit_acquired - Assert that the P-Unit has been acquired.
171 */ 190 */
172void iosf_mbi_assert_punit_acquired(void); 191void iosf_mbi_assert_punit_acquired(void);
diff --git a/arch/x86/platform/intel/iosf_mbi.c b/arch/x86/platform/intel/iosf_mbi.c
index 6f37a2137a79..2e569d10f2d0 100644
--- a/arch/x86/platform/intel/iosf_mbi.c
+++ b/arch/x86/platform/intel/iosf_mbi.c
@@ -18,24 +18,26 @@
18 * enumerate the device using PCI. 18 * enumerate the device using PCI.
19 */ 19 */
20 20
21#include <linux/delay.h>
21#include <linux/module.h> 22#include <linux/module.h>
22#include <linux/init.h> 23#include <linux/init.h>
23#include <linux/spinlock.h> 24#include <linux/spinlock.h>
24#include <linux/pci.h> 25#include <linux/pci.h>
25#include <linux/debugfs.h> 26#include <linux/debugfs.h>
26#include <linux/capability.h> 27#include <linux/capability.h>
28#include <linux/pm_qos.h>
27 29
28#include <asm/iosf_mbi.h> 30#include <asm/iosf_mbi.h>
29 31
30#define PCI_DEVICE_ID_BAYTRAIL 0x0F00 32#define PCI_DEVICE_ID_INTEL_BAYTRAIL 0x0F00
31#define PCI_DEVICE_ID_BRASWELL 0x2280 33#define PCI_DEVICE_ID_INTEL_BRASWELL 0x2280
32#define PCI_DEVICE_ID_QUARK_X1000 0x0958 34#define PCI_DEVICE_ID_INTEL_QUARK_X1000 0x0958
33#define PCI_DEVICE_ID_TANGIER 0x1170 35#define PCI_DEVICE_ID_INTEL_TANGIER 0x1170
34 36
35static struct pci_dev *mbi_pdev; 37static struct pci_dev *mbi_pdev;
36static DEFINE_SPINLOCK(iosf_mbi_lock); 38static DEFINE_SPINLOCK(iosf_mbi_lock);
37static DEFINE_MUTEX(iosf_mbi_punit_mutex); 39
38static BLOCKING_NOTIFIER_HEAD(iosf_mbi_pmic_bus_access_notifier); 40/**************** Generic iosf_mbi access helpers ****************/
39 41
40static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset) 42static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset)
41{ 43{
@@ -192,6 +194,30 @@ bool iosf_mbi_available(void)
192} 194}
193EXPORT_SYMBOL(iosf_mbi_available); 195EXPORT_SYMBOL(iosf_mbi_available);
194 196
197/*
198 **************** P-Unit/kernel shared I2C bus arbritration ****************
199 *
200 * Some Bay Trail and Cherry Trail devices have the P-Unit and us (the kernel)
201 * share a single I2C bus to the PMIC. Below are helpers to arbitrate the
202 * accesses between the kernel and the P-Unit.
203 *
204 * See arch/x86/include/asm/iosf_mbi.h for kernel-doc text for each function.
205 */
206
207#define SEMAPHORE_TIMEOUT 500
208#define PUNIT_SEMAPHORE_BYT 0x7
209#define PUNIT_SEMAPHORE_CHT 0x10e
210#define PUNIT_SEMAPHORE_BIT BIT(0)
211#define PUNIT_SEMAPHORE_ACQUIRE BIT(1)
212
213static DEFINE_MUTEX(iosf_mbi_punit_mutex);
214static DEFINE_MUTEX(iosf_mbi_block_punit_i2c_access_count_mutex);
215static BLOCKING_NOTIFIER_HEAD(iosf_mbi_pmic_bus_access_notifier);
216static u32 iosf_mbi_block_punit_i2c_access_count;
217static u32 iosf_mbi_sem_address;
218static unsigned long iosf_mbi_sem_acquired;
219static struct pm_qos_request iosf_mbi_pm_qos;
220
195void iosf_mbi_punit_acquire(void) 221void iosf_mbi_punit_acquire(void)
196{ 222{
197 mutex_lock(&iosf_mbi_punit_mutex); 223 mutex_lock(&iosf_mbi_punit_mutex);
@@ -204,6 +230,159 @@ void iosf_mbi_punit_release(void)
204} 230}
205EXPORT_SYMBOL(iosf_mbi_punit_release); 231EXPORT_SYMBOL(iosf_mbi_punit_release);
206 232
233static int iosf_mbi_get_sem(u32 *sem)
234{
235 int ret;
236
237 ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
238 iosf_mbi_sem_address, sem);
239 if (ret) {
240 dev_err(&mbi_pdev->dev, "Error P-Unit semaphore read failed\n");
241 return ret;
242 }
243
244 *sem &= PUNIT_SEMAPHORE_BIT;
245 return 0;
246}
247
248static void iosf_mbi_reset_semaphore(void)
249{
250 if (iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ,
251 iosf_mbi_sem_address, 0, PUNIT_SEMAPHORE_BIT))
252 dev_err(&mbi_pdev->dev, "Error P-Unit semaphore reset failed\n");
253
254 pm_qos_update_request(&iosf_mbi_pm_qos, PM_QOS_DEFAULT_VALUE);
255
256 blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier,
257 MBI_PMIC_BUS_ACCESS_END, NULL);
258}
259
260/*
261 * This function blocks P-Unit accesses to the PMIC I2C bus, so that kernel
262 * I2C code, such as e.g. a fuel-gauge driver, can access it safely.
263 *
264 * This function may be called by I2C controller code while an I2C driver has
265 * already blocked P-Unit accesses because it wants them blocked over multiple
266 * i2c-transfers, for e.g. read-modify-write of an I2C client register.
267 *
268 * The P-Unit accesses already being blocked is tracked through the
269 * iosf_mbi_block_punit_i2c_access_count variable which is protected by the
270 * iosf_mbi_block_punit_i2c_access_count_mutex this mutex is hold for the
271 * entire duration of the function.
272 *
273 * If access is not blocked yet, this function takes the following steps:
274 *
275 * 1) Some code sends request to the P-Unit which make it access the PMIC
276 * I2C bus. Testing has shown that the P-Unit does not check its internal
277 * PMIC bus semaphore for these requests. Callers of these requests call
278 * iosf_mbi_punit_acquire()/_release() around their P-Unit accesses, these
279 * functions lock/unlock the iosf_mbi_punit_mutex.
280 * As the first step we lock the iosf_mbi_punit_mutex, to wait for any in
281 * flight requests to finish and to block any new requests.
282 *
283 * 2) Some code makes such P-Unit requests from atomic contexts where it
284 * cannot call iosf_mbi_punit_acquire() as that may sleep.
285 * As the second step we call a notifier chain which allows any code
286 * needing P-Unit resources from atomic context to acquire them before
287 * we take control over the PMIC I2C bus.
288 *
289 * 3) When CPU cores enter C6 or C7 the P-Unit needs to talk to the PMIC
290 * if this happens while the kernel itself is accessing the PMIC I2C bus
291 * the SoC hangs.
292 * As the third step we call pm_qos_update_request() to disallow the CPU
293 * to enter C6 or C7.
294 *
295 * 4) The P-Unit has a PMIC bus semaphore which we can request to stop
296 * autonomous P-Unit tasks from accessing the PMIC I2C bus while we hold it.
297 * As the fourth and final step we request this semaphore and wait for our
298 * request to be acknowledged.
299 */
300int iosf_mbi_block_punit_i2c_access(void)
301{
302 unsigned long start, end;
303 int ret = 0;
304 u32 sem;
305
306 if (WARN_ON(!mbi_pdev || !iosf_mbi_sem_address))
307 return -ENXIO;
308
309 mutex_lock(&iosf_mbi_block_punit_i2c_access_count_mutex);
310
311 if (iosf_mbi_block_punit_i2c_access_count > 0)
312 goto success;
313
314 mutex_lock(&iosf_mbi_punit_mutex);
315 blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier,
316 MBI_PMIC_BUS_ACCESS_BEGIN, NULL);
317
318 /*
319 * Disallow the CPU to enter C6 or C7 state, entering these states
320 * requires the P-Unit to talk to the PMIC and if this happens while
321 * we're holding the semaphore, the SoC hangs.
322 */
323 pm_qos_update_request(&iosf_mbi_pm_qos, 0);
324
325 /* host driver writes to side band semaphore register */
326 ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
327 iosf_mbi_sem_address, PUNIT_SEMAPHORE_ACQUIRE);
328 if (ret) {
329 dev_err(&mbi_pdev->dev, "Error P-Unit semaphore request failed\n");
330 goto error;
331 }
332
333 /* host driver waits for bit 0 to be set in semaphore register */
334 start = jiffies;
335 end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
336 do {
337 ret = iosf_mbi_get_sem(&sem);
338 if (!ret && sem) {
339 iosf_mbi_sem_acquired = jiffies;
340 dev_dbg(&mbi_pdev->dev, "P-Unit semaphore acquired after %ums\n",
341 jiffies_to_msecs(jiffies - start));
342 /*
343 * Success, keep iosf_mbi_punit_mutex locked till
344 * iosf_mbi_unblock_punit_i2c_access() gets called.
345 */
346 goto success;
347 }
348
349 usleep_range(1000, 2000);
350 } while (time_before(jiffies, end));
351
352 ret = -ETIMEDOUT;
353 dev_err(&mbi_pdev->dev, "Error P-Unit semaphore timed out, resetting\n");
354error:
355 iosf_mbi_reset_semaphore();
356 mutex_unlock(&iosf_mbi_punit_mutex);
357
358 if (!iosf_mbi_get_sem(&sem))
359 dev_err(&mbi_pdev->dev, "P-Unit semaphore: %d\n", sem);
360success:
361 if (!WARN_ON(ret))
362 iosf_mbi_block_punit_i2c_access_count++;
363
364 mutex_unlock(&iosf_mbi_block_punit_i2c_access_count_mutex);
365
366 return ret;
367}
368EXPORT_SYMBOL(iosf_mbi_block_punit_i2c_access);
369
370void iosf_mbi_unblock_punit_i2c_access(void)
371{
372 mutex_lock(&iosf_mbi_block_punit_i2c_access_count_mutex);
373
374 iosf_mbi_block_punit_i2c_access_count--;
375 if (iosf_mbi_block_punit_i2c_access_count == 0) {
376 iosf_mbi_reset_semaphore();
377 mutex_unlock(&iosf_mbi_punit_mutex);
378 dev_dbg(&mbi_pdev->dev, "punit semaphore held for %ums\n",
379 jiffies_to_msecs(jiffies - iosf_mbi_sem_acquired));
380 }
381
382 mutex_unlock(&iosf_mbi_block_punit_i2c_access_count_mutex);
383}
384EXPORT_SYMBOL(iosf_mbi_unblock_punit_i2c_access);
385
207int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb) 386int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb)
208{ 387{
209 int ret; 388 int ret;
@@ -241,19 +420,14 @@ int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb)
241} 420}
242EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier); 421EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier);
243 422
244int iosf_mbi_call_pmic_bus_access_notifier_chain(unsigned long val, void *v)
245{
246 return blocking_notifier_call_chain(
247 &iosf_mbi_pmic_bus_access_notifier, val, v);
248}
249EXPORT_SYMBOL(iosf_mbi_call_pmic_bus_access_notifier_chain);
250
251void iosf_mbi_assert_punit_acquired(void) 423void iosf_mbi_assert_punit_acquired(void)
252{ 424{
253 WARN_ON(!mutex_is_locked(&iosf_mbi_punit_mutex)); 425 WARN_ON(!mutex_is_locked(&iosf_mbi_punit_mutex));
254} 426}
255EXPORT_SYMBOL(iosf_mbi_assert_punit_acquired); 427EXPORT_SYMBOL(iosf_mbi_assert_punit_acquired);
256 428
429/**************** iosf_mbi debug code ****************/
430
257#ifdef CONFIG_IOSF_MBI_DEBUG 431#ifdef CONFIG_IOSF_MBI_DEBUG
258static u32 dbg_mdr; 432static u32 dbg_mdr;
259static u32 dbg_mcr; 433static u32 dbg_mcr;
@@ -338,7 +512,7 @@ static inline void iosf_debugfs_remove(void) { }
338#endif /* CONFIG_IOSF_MBI_DEBUG */ 512#endif /* CONFIG_IOSF_MBI_DEBUG */
339 513
340static int iosf_mbi_probe(struct pci_dev *pdev, 514static int iosf_mbi_probe(struct pci_dev *pdev,
341 const struct pci_device_id *unused) 515 const struct pci_device_id *dev_id)
342{ 516{
343 int ret; 517 int ret;
344 518
@@ -349,14 +523,16 @@ static int iosf_mbi_probe(struct pci_dev *pdev,
349 } 523 }
350 524
351 mbi_pdev = pci_dev_get(pdev); 525 mbi_pdev = pci_dev_get(pdev);
526 iosf_mbi_sem_address = dev_id->driver_data;
527
352 return 0; 528 return 0;
353} 529}
354 530
355static const struct pci_device_id iosf_mbi_pci_ids[] = { 531static const struct pci_device_id iosf_mbi_pci_ids[] = {
356 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_BAYTRAIL) }, 532 { PCI_DEVICE_DATA(INTEL, BAYTRAIL, PUNIT_SEMAPHORE_BYT) },
357 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_BRASWELL) }, 533 { PCI_DEVICE_DATA(INTEL, BRASWELL, PUNIT_SEMAPHORE_CHT) },
358 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_QUARK_X1000) }, 534 { PCI_DEVICE_DATA(INTEL, QUARK_X1000, 0) },
359 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_TANGIER) }, 535 { PCI_DEVICE_DATA(INTEL, TANGIER, 0) },
360 { 0, }, 536 { 0, },
361}; 537};
362MODULE_DEVICE_TABLE(pci, iosf_mbi_pci_ids); 538MODULE_DEVICE_TABLE(pci, iosf_mbi_pci_ids);
@@ -371,6 +547,9 @@ static int __init iosf_mbi_init(void)
371{ 547{
372 iosf_debugfs_init(); 548 iosf_debugfs_init();
373 549
550 pm_qos_add_request(&iosf_mbi_pm_qos, PM_QOS_CPU_DMA_LATENCY,
551 PM_QOS_DEFAULT_VALUE);
552
374 return pci_register_driver(&iosf_mbi_pci_driver); 553 return pci_register_driver(&iosf_mbi_pci_driver);
375} 554}
376 555
@@ -381,6 +560,8 @@ static void __exit iosf_mbi_exit(void)
381 pci_unregister_driver(&iosf_mbi_pci_driver); 560 pci_unregister_driver(&iosf_mbi_pci_driver);
382 pci_dev_put(mbi_pdev); 561 pci_dev_put(mbi_pdev);
383 mbi_pdev = NULL; 562 mbi_pdev = NULL;
563
564 pm_qos_remove_request(&iosf_mbi_pm_qos);
384} 565}
385 566
386module_init(iosf_mbi_init); 567module_init(iosf_mbi_init);
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 365e6c1a729e..8f3a444c6ea9 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -512,7 +512,7 @@ config CRC_PMIC_OPREGION
512 512
513config XPOWER_PMIC_OPREGION 513config XPOWER_PMIC_OPREGION
514 bool "ACPI operation region support for XPower AXP288 PMIC" 514 bool "ACPI operation region support for XPower AXP288 PMIC"
515 depends on MFD_AXP20X_I2C 515 depends on MFD_AXP20X_I2C && IOSF_MBI
516 help 516 help
517 This config adds ACPI operation region support for XPower AXP288 PMIC. 517 This config adds ACPI operation region support for XPower AXP288 PMIC.
518 518
diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c
index aadc86db804c..2579675b7082 100644
--- a/drivers/acpi/pmic/intel_pmic_xpower.c
+++ b/drivers/acpi/pmic/intel_pmic_xpower.c
@@ -8,8 +8,9 @@
8#include <linux/acpi.h> 8#include <linux/acpi.h>
9#include <linux/init.h> 9#include <linux/init.h>
10#include <linux/mfd/axp20x.h> 10#include <linux/mfd/axp20x.h>
11#include <linux/platform_device.h>
12#include <linux/regmap.h> 11#include <linux/regmap.h>
12#include <linux/platform_device.h>
13#include <asm/iosf_mbi.h>
13#include "intel_pmic.h" 14#include "intel_pmic.h"
14 15
15#define XPOWER_GPADC_LOW 0x5b 16#define XPOWER_GPADC_LOW 0x5b
@@ -172,15 +173,21 @@ static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg,
172static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg, 173static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg,
173 int bit, bool on) 174 int bit, bool on)
174{ 175{
175 int data; 176 int data, ret;
176 177
177 /* GPIO1 LDO regulator needs special handling */ 178 /* GPIO1 LDO regulator needs special handling */
178 if (reg == XPOWER_GPI1_CTRL) 179 if (reg == XPOWER_GPI1_CTRL)
179 return regmap_update_bits(regmap, reg, GPI1_LDO_MASK, 180 return regmap_update_bits(regmap, reg, GPI1_LDO_MASK,
180 on ? GPI1_LDO_ON : GPI1_LDO_OFF); 181 on ? GPI1_LDO_ON : GPI1_LDO_OFF);
181 182
182 if (regmap_read(regmap, reg, &data)) 183 ret = iosf_mbi_block_punit_i2c_access();
183 return -EIO; 184 if (ret)
185 return ret;
186
187 if (regmap_read(regmap, reg, &data)) {
188 ret = -EIO;
189 goto out;
190 }
184 191
185 if (on) 192 if (on)
186 data |= BIT(bit); 193 data |= BIT(bit);
@@ -188,9 +195,11 @@ static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg,
188 data &= ~BIT(bit); 195 data &= ~BIT(bit);
189 196
190 if (regmap_write(regmap, reg, data)) 197 if (regmap_write(regmap, reg, data))
191 return -EIO; 198 ret = -EIO;
199out:
200 iosf_mbi_unblock_punit_i2c_access();
192 201
193 return 0; 202 return ret;
194} 203}
195 204
196/** 205/**
diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c
index 9ca1feaba98f..33da07d64494 100644
--- a/drivers/i2c/busses/i2c-designware-baytrail.c
+++ b/drivers/i2c/busses/i2c-designware-baytrail.c
@@ -3,141 +3,15 @@
3 * Intel BayTrail PMIC I2C bus semaphore implementaion 3 * Intel BayTrail PMIC I2C bus semaphore implementaion
4 * Copyright (c) 2014, Intel Corporation. 4 * Copyright (c) 2014, Intel Corporation.
5 */ 5 */
6#include <linux/delay.h>
7#include <linux/device.h> 6#include <linux/device.h>
8#include <linux/acpi.h> 7#include <linux/acpi.h>
9#include <linux/i2c.h> 8#include <linux/i2c.h>
10#include <linux/interrupt.h> 9#include <linux/interrupt.h>
11#include <linux/pm_qos.h>
12 10
13#include <asm/iosf_mbi.h> 11#include <asm/iosf_mbi.h>
14 12
15#include "i2c-designware-core.h" 13#include "i2c-designware-core.h"
16 14
17#define SEMAPHORE_TIMEOUT 500
18#define PUNIT_SEMAPHORE 0x7
19#define PUNIT_SEMAPHORE_CHT 0x10e
20#define PUNIT_SEMAPHORE_BIT BIT(0)
21#define PUNIT_SEMAPHORE_ACQUIRE BIT(1)
22
23static unsigned long acquired;
24
25static u32 get_sem_addr(struct dw_i2c_dev *dev)
26{
27 if (dev->flags & MODEL_CHERRYTRAIL)
28 return PUNIT_SEMAPHORE_CHT;
29 else
30 return PUNIT_SEMAPHORE;
31}
32
33static int get_sem(struct dw_i2c_dev *dev, u32 *sem)
34{
35 u32 addr = get_sem_addr(dev);
36 u32 data;
37 int ret;
38
39 ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, addr, &data);
40 if (ret) {
41 dev_err(dev->dev, "iosf failed to read punit semaphore\n");
42 return ret;
43 }
44
45 *sem = data & PUNIT_SEMAPHORE_BIT;
46
47 return 0;
48}
49
50static void reset_semaphore(struct dw_i2c_dev *dev)
51{
52 if (iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, get_sem_addr(dev),
53 0, PUNIT_SEMAPHORE_BIT))
54 dev_err(dev->dev, "iosf failed to reset punit semaphore during write\n");
55
56 pm_qos_update_request(&dev->pm_qos, PM_QOS_DEFAULT_VALUE);
57
58 iosf_mbi_call_pmic_bus_access_notifier_chain(MBI_PMIC_BUS_ACCESS_END,
59 NULL);
60 iosf_mbi_punit_release();
61}
62
63static int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
64{
65 u32 addr;
66 u32 sem = PUNIT_SEMAPHORE_ACQUIRE;
67 int ret;
68 unsigned long start, end;
69
70 might_sleep();
71
72 if (!dev || !dev->dev)
73 return -ENODEV;
74
75 if (!dev->release_lock)
76 return 0;
77
78 iosf_mbi_punit_acquire();
79 iosf_mbi_call_pmic_bus_access_notifier_chain(MBI_PMIC_BUS_ACCESS_BEGIN,
80 NULL);
81
82 /*
83 * Disallow the CPU to enter C6 or C7 state, entering these states
84 * requires the punit to talk to the pmic and if this happens while
85 * we're holding the semaphore, the SoC hangs.
86 */
87 pm_qos_update_request(&dev->pm_qos, 0);
88
89 addr = get_sem_addr(dev);
90
91 /* host driver writes to side band semaphore register */
92 ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, addr, sem);
93 if (ret) {
94 dev_err(dev->dev, "iosf punit semaphore request failed\n");
95 goto out;
96 }
97
98 /* host driver waits for bit 0 to be set in semaphore register */
99 start = jiffies;
100 end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
101 do {
102 ret = get_sem(dev, &sem);
103 if (!ret && sem) {
104 acquired = jiffies;
105 dev_dbg(dev->dev, "punit semaphore acquired after %ums\n",
106 jiffies_to_msecs(jiffies - start));
107 return 0;
108 }
109
110 usleep_range(1000, 2000);
111 } while (time_before(jiffies, end));
112
113 dev_err(dev->dev, "punit semaphore timed out, resetting\n");
114out:
115 reset_semaphore(dev);
116
117 ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, addr, &sem);
118 if (ret)
119 dev_err(dev->dev, "iosf failed to read punit semaphore\n");
120 else
121 dev_err(dev->dev, "PUNIT SEM: %d\n", sem);
122
123 WARN_ON(1);
124
125 return -ETIMEDOUT;
126}
127
128static void baytrail_i2c_release(struct dw_i2c_dev *dev)
129{
130 if (!dev || !dev->dev)
131 return;
132
133 if (!dev->acquire_lock)
134 return;
135
136 reset_semaphore(dev);
137 dev_dbg(dev->dev, "punit semaphore held for %ums\n",
138 jiffies_to_msecs(jiffies - acquired));
139}
140
141int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) 15int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
142{ 16{
143 acpi_status status; 17 acpi_status status;
@@ -162,18 +36,9 @@ int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
162 return -EPROBE_DEFER; 36 return -EPROBE_DEFER;
163 37
164 dev_info(dev->dev, "I2C bus managed by PUNIT\n"); 38 dev_info(dev->dev, "I2C bus managed by PUNIT\n");
165 dev->acquire_lock = baytrail_i2c_acquire; 39 dev->acquire_lock = iosf_mbi_block_punit_i2c_access;
166 dev->release_lock = baytrail_i2c_release; 40 dev->release_lock = iosf_mbi_unblock_punit_i2c_access;
167 dev->shared_with_punit = true; 41 dev->shared_with_punit = true;
168 42
169 pm_qos_add_request(&dev->pm_qos, PM_QOS_CPU_DMA_LATENCY,
170 PM_QOS_DEFAULT_VALUE);
171
172 return 0; 43 return 0;
173} 44}
174
175void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev)
176{
177 if (dev->acquire_lock)
178 pm_qos_remove_request(&dev->pm_qos);
179}
diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
index 36271cd75342..a4730111d290 100644
--- a/drivers/i2c/busses/i2c-designware-common.c
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -269,7 +269,7 @@ int i2c_dw_acquire_lock(struct dw_i2c_dev *dev)
269 if (!dev->acquire_lock) 269 if (!dev->acquire_lock)
270 return 0; 270 return 0;
271 271
272 ret = dev->acquire_lock(dev); 272 ret = dev->acquire_lock();
273 if (!ret) 273 if (!ret)
274 return 0; 274 return 0;
275 275
@@ -281,7 +281,7 @@ int i2c_dw_acquire_lock(struct dw_i2c_dev *dev)
281void i2c_dw_release_lock(struct dw_i2c_dev *dev) 281void i2c_dw_release_lock(struct dw_i2c_dev *dev)
282{ 282{
283 if (dev->release_lock) 283 if (dev->release_lock)
284 dev->release_lock(dev); 284 dev->release_lock();
285} 285}
286 286
287/* 287/*
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 9ec8394f4787..b4a0b2b99a78 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -10,7 +10,6 @@
10 */ 10 */
11 11
12#include <linux/i2c.h> 12#include <linux/i2c.h>
13#include <linux/pm_qos.h>
14 13
15#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \ 14#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \
16 I2C_FUNC_SMBUS_BYTE | \ 15 I2C_FUNC_SMBUS_BYTE | \
@@ -209,7 +208,6 @@
209 * @fp_lcnt: fast plus LCNT value 208 * @fp_lcnt: fast plus LCNT value
210 * @hs_hcnt: high speed HCNT value 209 * @hs_hcnt: high speed HCNT value
211 * @hs_lcnt: high speed LCNT value 210 * @hs_lcnt: high speed LCNT value
212 * @pm_qos: pm_qos_request used while holding a hardware lock on the bus
213 * @acquire_lock: function to acquire a hardware lock on the bus 211 * @acquire_lock: function to acquire a hardware lock on the bus
214 * @release_lock: function to release a hardware lock on the bus 212 * @release_lock: function to release a hardware lock on the bus
215 * @shared_with_punit: true if this bus is shared with the SoCs PUNIT 213 * @shared_with_punit: true if this bus is shared with the SoCs PUNIT
@@ -263,9 +261,8 @@ struct dw_i2c_dev {
263 u16 fp_lcnt; 261 u16 fp_lcnt;
264 u16 hs_hcnt; 262 u16 hs_hcnt;
265 u16 hs_lcnt; 263 u16 hs_lcnt;
266 struct pm_qos_request pm_qos; 264 int (*acquire_lock)(void);
267 int (*acquire_lock)(struct dw_i2c_dev *dev); 265 void (*release_lock)(void);
268 void (*release_lock)(struct dw_i2c_dev *dev);
269 bool shared_with_punit; 266 bool shared_with_punit;
270 void (*disable)(struct dw_i2c_dev *dev); 267 void (*disable)(struct dw_i2c_dev *dev);
271 void (*disable_int)(struct dw_i2c_dev *dev); 268 void (*disable_int)(struct dw_i2c_dev *dev);
@@ -322,8 +319,6 @@ static inline int i2c_dw_probe_slave(struct dw_i2c_dev *dev) { return -EINVAL; }
322 319
323#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL) 320#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
324extern int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev); 321extern int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev);
325extern void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev);
326#else 322#else
327static inline int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) { return 0; } 323static inline int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) { return 0; }
328static inline void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) {}
329#endif 324#endif
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 997bbb3d925f..9eaac3be1f63 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -418,8 +418,6 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
418 if (!IS_ERR_OR_NULL(dev->rst)) 418 if (!IS_ERR_OR_NULL(dev->rst))
419 reset_control_assert(dev->rst); 419 reset_control_assert(dev->rst);
420 420
421 i2c_dw_remove_lock_support(dev);
422
423 return 0; 421 return 0;
424} 422}
425 423