aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-omap.c
diff options
context:
space:
mode:
authorTarun Kanti DebBarma <tarun.kanti@ti.com>2011-11-23 16:14:29 -0500
committerTarun Kanti DebBarma <tarun.kanti@ti.com>2012-02-06 06:10:48 -0500
commit2dc983c565e03f6f6f96c5fe7449b65d86af4dee (patch)
tree10603d101152685569c0dca7107ba733c9b6d133 /drivers/gpio/gpio-omap.c
parent065cd795d2721f8d2d1f2967ee6ed0aec07a4202 (diff)
gpio/omap: cleanup prepare_for_idle and resume_after_idle
Since *_prepare_for_idle() and *_resume_after_idle() are called with interrupts disabled they should be kept as simple as possible. So, moving most of the stuff to *_runtime_suspend/resume() callbacks. To avoid invalid context restore happening in *_runtime_resume() callback as a result of *_get_sync() call in *_gpio_probe(), update bank->context_loss_count. This would make context restore condition check false in the callback and skip restore until further initialization take place. The workaround_enabled static variable is now a member of struct gpio_bank. Unlike most GPIO registers the OE has 0xffffffff as the default value. To make sure invalid context is not restored, updating the OE context with default value. Signed-off-by: Tarun Kanti DebBarma <tarun.kanti@ti.com> Signed-off-by: Charulatha V <charu@ti.com> Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Reviewed-by: Kevin Hilman <khilman@ti.com> Signed-off-by: Kevin Hilman <khilman@ti.com>
Diffstat (limited to 'drivers/gpio/gpio-omap.c')
-rw-r--r--drivers/gpio/gpio-omap.c245
1 files changed, 147 insertions, 98 deletions
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index e9a30fa8715b..d483cc9f0c63 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -29,6 +29,8 @@
29#include <asm/gpio.h> 29#include <asm/gpio.h>
30#include <asm/mach/irq.h> 30#include <asm/mach/irq.h>
31 31
32#define OFF_MODE 1
33
32static LIST_HEAD(omap_gpio_list); 34static LIST_HEAD(omap_gpio_list);
33 35
34struct gpio_regs { 36struct gpio_regs {
@@ -73,6 +75,8 @@ struct gpio_bank {
73 u32 width; 75 u32 width;
74 int context_loss_count; 76 int context_loss_count;
75 u16 id; 77 u16 id;
78 int power_mode;
79 bool workaround_enabled;
76 80
77 void (*set_dataout)(struct gpio_bank *bank, int gpio, int enable); 81 void (*set_dataout)(struct gpio_bank *bank, int gpio, int enable);
78 int (*get_context_loss_count)(struct device *dev); 82 int (*get_context_loss_count)(struct device *dev);
@@ -905,6 +909,8 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
905 if (bank->regs->debounce_en) 909 if (bank->regs->debounce_en)
906 _gpio_rmw(base, bank->regs->debounce_en, 0, 1); 910 _gpio_rmw(base, bank->regs->debounce_en, 0, 1);
907 911
912 /* Save OE default value (0xffffffff) in the context */
913 bank->context.oe = __raw_readl(bank->base + bank->regs->direction);
908 /* Initialize interface clk ungated, module enabled */ 914 /* Initialize interface clk ungated, module enabled */
909 if (bank->regs->ctrl) 915 if (bank->regs->ctrl)
910 _gpio_rmw(base, bank->regs->ctrl, 0, 1); 916 _gpio_rmw(base, bank->regs->ctrl, 0, 1);
@@ -1127,141 +1133,179 @@ static int omap_gpio_resume(struct device *dev)
1127} 1133}
1128#endif /* CONFIG_PM_SLEEP */ 1134#endif /* CONFIG_PM_SLEEP */
1129 1135
1136#if defined(CONFIG_PM_RUNTIME)
1130static void omap_gpio_save_context(struct gpio_bank *bank); 1137static void omap_gpio_save_context(struct gpio_bank *bank);
1131static void omap_gpio_restore_context(struct gpio_bank *bank); 1138static void omap_gpio_restore_context(struct gpio_bank *bank);
1132 1139
1133void omap2_gpio_prepare_for_idle(int off_mode) 1140static int omap_gpio_runtime_suspend(struct device *dev)
1134{ 1141{
1135 struct gpio_bank *bank; 1142 struct platform_device *pdev = to_platform_device(dev);
1136 1143 struct gpio_bank *bank = platform_get_drvdata(pdev);
1137 list_for_each_entry(bank, &omap_gpio_list, node) { 1144 u32 l1 = 0, l2 = 0;
1138 u32 l1 = 0, l2 = 0; 1145 unsigned long flags;
1139 int j;
1140
1141 if (!bank->loses_context)
1142 continue;
1143
1144 for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
1145 clk_disable(bank->dbck);
1146 1146
1147 if (!off_mode) 1147 spin_lock_irqsave(&bank->lock, flags);
1148 continue; 1148 if (bank->power_mode != OFF_MODE) {
1149 bank->power_mode = 0;
1150 goto save_gpio_context;
1151 }
1152 /*
1153 * If going to OFF, remove triggering for all
1154 * non-wakeup GPIOs. Otherwise spurious IRQs will be
1155 * generated. See OMAP2420 Errata item 1.101.
1156 */
1157 if (!(bank->enabled_non_wakeup_gpios))
1158 goto save_gpio_context;
1149 1159
1150 /* If going to OFF, remove triggering for all 1160 bank->saved_datain = __raw_readl(bank->base +
1151 * non-wakeup GPIOs. Otherwise spurious IRQs will be 1161 bank->regs->datain);
1152 * generated. See OMAP2420 Errata item 1.101. */ 1162 l1 = __raw_readl(bank->base + bank->regs->fallingdetect);
1153 if (!(bank->enabled_non_wakeup_gpios)) 1163 l2 = __raw_readl(bank->base + bank->regs->risingdetect);
1154 goto save_gpio_context;
1155 1164
1156 bank->saved_datain = __raw_readl(bank->base + 1165 bank->saved_fallingdetect = l1;
1157 bank->regs->datain); 1166 bank->saved_risingdetect = l2;
1158 l1 = __raw_readl(bank->base + bank->regs->fallingdetect); 1167 l1 &= ~bank->enabled_non_wakeup_gpios;
1159 l2 = __raw_readl(bank->base + bank->regs->risingdetect); 1168 l2 &= ~bank->enabled_non_wakeup_gpios;
1160 1169
1161 bank->saved_fallingdetect = l1; 1170 __raw_writel(l1, bank->base + bank->regs->fallingdetect);
1162 bank->saved_risingdetect = l2; 1171 __raw_writel(l2, bank->base + bank->regs->risingdetect);
1163 l1 &= ~bank->enabled_non_wakeup_gpios;
1164 l2 &= ~bank->enabled_non_wakeup_gpios;
1165 1172
1166 __raw_writel(l1, bank->base + bank->regs->fallingdetect); 1173 bank->workaround_enabled = true;
1167 __raw_writel(l2, bank->base + bank->regs->risingdetect);
1168 1174
1169save_gpio_context: 1175save_gpio_context:
1170 1176 if (bank->get_context_loss_count)
1171 if (bank->get_context_loss_count) 1177 bank->context_loss_count =
1172 bank->context_loss_count =
1173 bank->get_context_loss_count(bank->dev); 1178 bank->get_context_loss_count(bank->dev);
1174 1179
1175 omap_gpio_save_context(bank); 1180 omap_gpio_save_context(bank);
1181 spin_unlock_irqrestore(&bank->lock, flags);
1176 1182
1177 if (!pm_runtime_suspended(bank->dev)) 1183 return 0;
1178 pm_runtime_put(bank->dev);
1179 }
1180} 1184}
1181 1185
1182void omap2_gpio_resume_after_idle(void) 1186static int omap_gpio_runtime_resume(struct device *dev)
1183{ 1187{
1184 struct gpio_bank *bank; 1188 struct platform_device *pdev = to_platform_device(dev);
1185 1189 struct gpio_bank *bank = platform_get_drvdata(pdev);
1186 list_for_each_entry(bank, &omap_gpio_list, node) { 1190 int context_lost_cnt_after;
1187 int context_lost_cnt_after; 1191 u32 l = 0, gen, gen0, gen1;
1188 u32 l = 0, gen, gen0, gen1; 1192 unsigned long flags;
1189 int j;
1190
1191 if (!bank->loses_context)
1192 continue;
1193
1194 for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
1195 clk_enable(bank->dbck);
1196 1193
1197 if (pm_runtime_suspended(bank->dev)) 1194 spin_lock_irqsave(&bank->lock, flags);
1198 pm_runtime_get_sync(bank->dev); 1195 if (!bank->enabled_non_wakeup_gpios || !bank->workaround_enabled) {
1196 spin_unlock_irqrestore(&bank->lock, flags);
1197 return 0;
1198 }
1199 1199
1200 if (bank->get_context_loss_count) { 1200 if (bank->get_context_loss_count) {
1201 context_lost_cnt_after = 1201 context_lost_cnt_after =
1202 bank->get_context_loss_count(bank->dev); 1202 bank->get_context_loss_count(bank->dev);
1203 if (context_lost_cnt_after != bank->context_loss_count 1203 if (context_lost_cnt_after != bank->context_loss_count ||
1204 || !context_lost_cnt_after) 1204 !context_lost_cnt_after) {
1205 omap_gpio_restore_context(bank); 1205 omap_gpio_restore_context(bank);
1206 } else {
1207 spin_unlock_irqrestore(&bank->lock, flags);
1208 return 0;
1206 } 1209 }
1210 }
1207 1211
1208 if (!(bank->enabled_non_wakeup_gpios)) 1212 __raw_writel(bank->saved_fallingdetect,
1209 continue; 1213 bank->base + bank->regs->fallingdetect);
1214 __raw_writel(bank->saved_risingdetect,
1215 bank->base + bank->regs->risingdetect);
1216 l = __raw_readl(bank->base + bank->regs->datain);
1210 1217
1211 __raw_writel(bank->saved_fallingdetect, 1218 /*
1212 bank->base + bank->regs->fallingdetect); 1219 * Check if any of the non-wakeup interrupt GPIOs have changed
1213 __raw_writel(bank->saved_risingdetect, 1220 * state. If so, generate an IRQ by software. This is
1214 bank->base + bank->regs->risingdetect); 1221 * horribly racy, but it's the best we can do to work around
1215 l = __raw_readl(bank->base + bank->regs->datain); 1222 * this silicon bug.
1223 */
1224 l ^= bank->saved_datain;
1225 l &= bank->enabled_non_wakeup_gpios;
1216 1226
1217 /* Check if any of the non-wakeup interrupt GPIOs have changed 1227 /*
1218 * state. If so, generate an IRQ by software. This is 1228 * No need to generate IRQs for the rising edge for gpio IRQs
1219 * horribly racy, but it's the best we can do to work around 1229 * configured with falling edge only; and vice versa.
1220 * this silicon bug. */ 1230 */
1221 l ^= bank->saved_datain; 1231 gen0 = l & bank->saved_fallingdetect;
1222 l &= bank->enabled_non_wakeup_gpios; 1232 gen0 &= bank->saved_datain;
1223 1233
1224 /* 1234 gen1 = l & bank->saved_risingdetect;
1225 * No need to generate IRQs for the rising edge for gpio IRQs 1235 gen1 &= ~(bank->saved_datain);
1226 * configured with falling edge only; and vice versa.
1227 */
1228 gen0 = l & bank->saved_fallingdetect;
1229 gen0 &= bank->saved_datain;
1230 1236
1231 gen1 = l & bank->saved_risingdetect; 1237 /* FIXME: Consider GPIO IRQs with level detections properly! */
1232 gen1 &= ~(bank->saved_datain); 1238 gen = l & (~(bank->saved_fallingdetect) & ~(bank->saved_risingdetect));
1239 /* Consider all GPIO IRQs needed to be updated */
1240 gen |= gen0 | gen1;
1233 1241
1234 /* FIXME: Consider GPIO IRQs with level detections properly! */ 1242 if (gen) {
1235 gen = l & (~(bank->saved_fallingdetect) & 1243 u32 old0, old1;
1236 ~(bank->saved_risingdetect));
1237 /* Consider all GPIO IRQs needed to be updated */
1238 gen |= gen0 | gen1;
1239 1244
1240 if (gen) { 1245 old0 = __raw_readl(bank->base + bank->regs->leveldetect0);
1241 u32 old0, old1; 1246 old1 = __raw_readl(bank->base + bank->regs->leveldetect1);
1242 1247
1243 old0 = __raw_readl(bank->base + 1248 if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
1249 __raw_writel(old0 | gen, bank->base +
1244 bank->regs->leveldetect0); 1250 bank->regs->leveldetect0);
1245 old1 = __raw_readl(bank->base + 1251 __raw_writel(old1 | gen, bank->base +
1246 bank->regs->leveldetect1); 1252 bank->regs->leveldetect1);
1253 }
1247 1254
1248 if (cpu_is_omap24xx() || cpu_is_omap34xx()) { 1255 if (cpu_is_omap44xx()) {
1249 old0 |= gen; 1256 __raw_writel(old0 | l, bank->base +
1250 old1 |= gen;
1251 }
1252
1253 if (cpu_is_omap44xx()) {
1254 old0 |= l;
1255 old1 |= l;
1256 }
1257 __raw_writel(old0, bank->base +
1258 bank->regs->leveldetect0); 1257 bank->regs->leveldetect0);
1259 __raw_writel(old1, bank->base + 1258 __raw_writel(old1 | l, bank->base +
1260 bank->regs->leveldetect1); 1259 bank->regs->leveldetect1);
1261 } 1260 }
1261 __raw_writel(old0, bank->base + bank->regs->leveldetect0);
1262 __raw_writel(old1, bank->base + bank->regs->leveldetect1);
1263 }
1264
1265 bank->workaround_enabled = false;
1266 spin_unlock_irqrestore(&bank->lock, flags);
1267
1268 return 0;
1269}
1270#endif /* CONFIG_PM_RUNTIME */
1271
1272void omap2_gpio_prepare_for_idle(int pwr_mode)
1273{
1274 struct gpio_bank *bank;
1275
1276 list_for_each_entry(bank, &omap_gpio_list, node) {
1277 int j;
1278
1279 if (!bank->mod_usage || !bank->loses_context)
1280 continue;
1281
1282 bank->power_mode = pwr_mode;
1283
1284 for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
1285 clk_disable(bank->dbck);
1286
1287 pm_runtime_put_sync_suspend(bank->dev);
1288 }
1289}
1290
1291void omap2_gpio_resume_after_idle(void)
1292{
1293 struct gpio_bank *bank;
1294
1295 list_for_each_entry(bank, &omap_gpio_list, node) {
1296 int j;
1297
1298 if (!bank->mod_usage || !bank->loses_context)
1299 continue;
1300
1301 for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
1302 clk_enable(bank->dbck);
1303
1304 pm_runtime_get_sync(bank->dev);
1262 } 1305 }
1263} 1306}
1264 1307
1308#if defined(CONFIG_PM_RUNTIME)
1265static void omap_gpio_save_context(struct gpio_bank *bank) 1309static void omap_gpio_save_context(struct gpio_bank *bank)
1266{ 1310{
1267 bank->context.irqenable1 = 1311 bank->context.irqenable1 =
@@ -1303,13 +1347,18 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
1303 bank->base + bank->regs->fallingdetect); 1347 bank->base + bank->regs->fallingdetect);
1304 __raw_writel(bank->context.dataout, bank->base + bank->regs->dataout); 1348 __raw_writel(bank->context.dataout, bank->base + bank->regs->dataout);
1305} 1349}
1350#endif /* CONFIG_PM_RUNTIME */
1306#else 1351#else
1307#define omap_gpio_suspend NULL 1352#define omap_gpio_suspend NULL
1308#define omap_gpio_resume NULL 1353#define omap_gpio_resume NULL
1354#define omap_gpio_runtime_suspend NULL
1355#define omap_gpio_runtime_resume NULL
1309#endif 1356#endif
1310 1357
1311static const struct dev_pm_ops gpio_pm_ops = { 1358static const struct dev_pm_ops gpio_pm_ops = {
1312 SET_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume) 1359 SET_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume)
1360 SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume,
1361 NULL)
1313}; 1362};
1314 1363
1315static struct platform_driver omap_gpio_driver = { 1364static struct platform_driver omap_gpio_driver = {