1 /* 2 * Intel BayTrail PMIC I2C bus semaphore implementaion 3 * Copyright (c) 2014, Intel Corporation. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms and conditions of the GNU General Public License, 7 * version 2, as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 */ 14 #include <linux/module.h> 15 #include <linux/delay.h> 16 #include <linux/device.h> 17 #include <linux/acpi.h> 18 #include <linux/i2c.h> 19 #include <linux/interrupt.h> 20 #include <asm/iosf_mbi.h> 21 #include "i2c-designware-core.h" 22 23 #define SEMAPHORE_TIMEOUT 100 24 #define PUNIT_SEMAPHORE 0x7 25 26 static unsigned long acquired; 27 28 static int get_sem(struct device *dev, u32 *sem) 29 { 30 u32 reg_val; 31 int ret; 32 33 ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, PUNIT_SEMAPHORE, 34 ®_val); 35 if (ret) { 36 dev_err(dev, "iosf failed to read punit semaphore\n"); 37 return ret; 38 } 39 40 *sem = reg_val & 0x1; 41 42 return 0; 43 } 44 45 static void reset_semaphore(struct device *dev) 46 { 47 u32 data; 48 49 if (iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, 50 PUNIT_SEMAPHORE, &data)) { 51 dev_err(dev, "iosf failed to reset punit semaphore during read\n"); 52 return; 53 } 54 55 data = data & 0xfffffffe; 56 if (iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, 57 PUNIT_SEMAPHORE, data)) 58 dev_err(dev, "iosf failed to reset punit semaphore during write\n"); 59 } 60 61 int baytrail_i2c_acquire(struct dw_i2c_dev *dev) 62 { 63 u32 sem = 0; 64 int ret; 65 unsigned long start, end; 66 67 if (!dev || !dev->dev) 68 return -ENODEV; 69 70 if (!dev->acquire_lock) 71 return 0; 72 73 /* host driver writes 0x2 to side band semaphore register */ 74 ret = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, 75 PUNIT_SEMAPHORE, 0x2); 76 if (ret) { 77 dev_err(dev->dev, "iosf punit semaphore request failed\n"); 78 return ret; 79 } 80 81 /* host driver waits for bit 0 to be set in semaphore register */ 82 start = jiffies; 83 end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT); 84 while (!time_after(jiffies, end)) { 85 ret = get_sem(dev->dev, &sem); 86 if (!ret && sem) { 87 acquired = jiffies; 88 dev_dbg(dev->dev, "punit semaphore acquired after %ums\n", 89 jiffies_to_msecs(jiffies - start)); 90 return 0; 91 } 92 93 usleep_range(1000, 2000); 94 } 95 96 dev_err(dev->dev, "punit semaphore timed out, resetting\n"); 97 reset_semaphore(dev->dev); 98 99 ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, 100 PUNIT_SEMAPHORE, &sem); 101 if (!ret) 102 dev_err(dev->dev, "iosf failed to read punit semaphore\n"); 103 else 104 dev_err(dev->dev, "PUNIT SEM: %d\n", sem); 105 106 WARN_ON(1); 107 108 return -ETIMEDOUT; 109 } 110 EXPORT_SYMBOL(baytrail_i2c_acquire); 111 112 void baytrail_i2c_release(struct dw_i2c_dev *dev) 113 { 114 if (!dev || !dev->dev) 115 return; 116 117 if (!dev->acquire_lock) 118 return; 119 120 reset_semaphore(dev->dev); 121 dev_dbg(dev->dev, "punit semaphore held for %ums\n", 122 jiffies_to_msecs(jiffies - acquired)); 123 } 124 EXPORT_SYMBOL(baytrail_i2c_release); 125 126 int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev) 127 { 128 acpi_status status; 129 unsigned long long shared_host = 0; 130 acpi_handle handle; 131 132 if (!dev || !dev->dev) 133 return 0; 134 135 handle = ACPI_HANDLE(dev->dev); 136 if (!handle) 137 return 0; 138 139 status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host); 140 141 if (ACPI_FAILURE(status)) 142 return 0; 143 144 if (shared_host) { 145 dev_info(dev->dev, "I2C bus managed by PUNIT\n"); 146 dev->acquire_lock = baytrail_i2c_acquire; 147 dev->release_lock = baytrail_i2c_release; 148 dev->pm_runtime_disabled = true; 149 } 150 151 if (!iosf_mbi_available()) 152 return -EPROBE_DEFER; 153 154 return 0; 155 } 156 EXPORT_SYMBOL(i2c_dw_eval_lock_support); 157 158 MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>"); 159 MODULE_DESCRIPTION("Baytrail I2C Semaphore driver"); 160 MODULE_LICENSE("GPL v2"); 161