189b4012bSMark Brown /* 289b4012bSMark Brown * wm8350-core.c -- Device access for Wolfson WM8350 389b4012bSMark Brown * 489b4012bSMark Brown * Copyright 2007, 2008 Wolfson Microelectronics PLC. 589b4012bSMark Brown * 689b4012bSMark Brown * Author: Liam Girdwood, Mark Brown 789b4012bSMark Brown * 889b4012bSMark Brown * This program is free software; you can redistribute it and/or modify it 989b4012bSMark Brown * under the terms of the GNU General Public License as published by the 1089b4012bSMark Brown * Free Software Foundation; either version 2 of the License, or (at your 1189b4012bSMark Brown * option) any later version. 1289b4012bSMark Brown * 1389b4012bSMark Brown */ 1489b4012bSMark Brown 1589b4012bSMark Brown #include <linux/kernel.h> 1689b4012bSMark Brown #include <linux/module.h> 1789b4012bSMark Brown #include <linux/init.h> 18ebccec0fSMark Brown #include <linux/bug.h> 1989b4012bSMark Brown #include <linux/device.h> 2089b4012bSMark Brown #include <linux/delay.h> 2189b4012bSMark Brown #include <linux/interrupt.h> 22ebccec0fSMark Brown #include <linux/workqueue.h> 2389b4012bSMark Brown 2489b4012bSMark Brown #include <linux/mfd/wm8350/core.h> 2589b4012bSMark Brown #include <linux/mfd/wm8350/audio.h> 26ebccec0fSMark Brown #include <linux/mfd/wm8350/comparator.h> 2789b4012bSMark Brown #include <linux/mfd/wm8350/gpio.h> 2889b4012bSMark Brown #include <linux/mfd/wm8350/pmic.h> 29ebccec0fSMark Brown #include <linux/mfd/wm8350/rtc.h> 3089b4012bSMark Brown #include <linux/mfd/wm8350/supply.h> 31ebccec0fSMark Brown #include <linux/mfd/wm8350/wdt.h> 3289b4012bSMark Brown 3389b4012bSMark Brown #define WM8350_UNLOCK_KEY 0x0013 3489b4012bSMark Brown #define WM8350_LOCK_KEY 0x0000 3589b4012bSMark Brown 3689b4012bSMark Brown #define WM8350_CLOCK_CONTROL_1 0x28 3789b4012bSMark Brown #define WM8350_AIF_TEST 0x74 3889b4012bSMark Brown 3989b4012bSMark Brown /* debug */ 4089b4012bSMark Brown #define WM8350_BUS_DEBUG 0 4189b4012bSMark Brown #if WM8350_BUS_DEBUG 4289b4012bSMark Brown #define dump(regs, src) do { \ 4389b4012bSMark Brown int i_; \ 4489b4012bSMark Brown u16 *src_ = src; \ 4589b4012bSMark Brown printk(KERN_DEBUG); \ 4689b4012bSMark Brown for (i_ = 0; i_ < regs; i_++) \ 4789b4012bSMark Brown printk(" 0x%4.4x", *src_++); \ 4889b4012bSMark Brown printk("\n"); \ 4989b4012bSMark Brown } while (0); 5089b4012bSMark Brown #else 5189b4012bSMark Brown #define dump(bytes, src) 5289b4012bSMark Brown #endif 5389b4012bSMark Brown 5489b4012bSMark Brown #define WM8350_LOCK_DEBUG 0 5589b4012bSMark Brown #if WM8350_LOCK_DEBUG 5689b4012bSMark Brown #define ldbg(format, arg...) printk(format, ## arg) 5789b4012bSMark Brown #else 5889b4012bSMark Brown #define ldbg(format, arg...) 5989b4012bSMark Brown #endif 6089b4012bSMark Brown 6189b4012bSMark Brown /* 6289b4012bSMark Brown * WM8350 Device IO 6389b4012bSMark Brown */ 6489b4012bSMark Brown static DEFINE_MUTEX(io_mutex); 6589b4012bSMark Brown static DEFINE_MUTEX(reg_lock_mutex); 6689b4012bSMark Brown static DEFINE_MUTEX(auxadc_mutex); 6789b4012bSMark Brown 6889b4012bSMark Brown /* Perform a physical read from the device. 6989b4012bSMark Brown */ 7089b4012bSMark Brown static int wm8350_phys_read(struct wm8350 *wm8350, u8 reg, int num_regs, 7189b4012bSMark Brown u16 *dest) 7289b4012bSMark Brown { 7389b4012bSMark Brown int i, ret; 7489b4012bSMark Brown int bytes = num_regs * 2; 7589b4012bSMark Brown 7689b4012bSMark Brown dev_dbg(wm8350->dev, "volatile read\n"); 7789b4012bSMark Brown ret = wm8350->read_dev(wm8350, reg, bytes, (char *)dest); 7889b4012bSMark Brown 7989b4012bSMark Brown for (i = reg; i < reg + num_regs; i++) { 8089b4012bSMark Brown /* Cache is CPU endian */ 8189b4012bSMark Brown dest[i - reg] = be16_to_cpu(dest[i - reg]); 8289b4012bSMark Brown 8389b4012bSMark Brown /* Satisfy non-volatile bits from cache */ 8489b4012bSMark Brown dest[i - reg] &= wm8350_reg_io_map[i].vol; 8589b4012bSMark Brown dest[i - reg] |= wm8350->reg_cache[i]; 8689b4012bSMark Brown 8789b4012bSMark Brown /* Mask out non-readable bits */ 8889b4012bSMark Brown dest[i - reg] &= wm8350_reg_io_map[i].readable; 8989b4012bSMark Brown } 9089b4012bSMark Brown 9189b4012bSMark Brown dump(num_regs, dest); 9289b4012bSMark Brown 9389b4012bSMark Brown return ret; 9489b4012bSMark Brown } 9589b4012bSMark Brown 9689b4012bSMark Brown static int wm8350_read(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *dest) 9789b4012bSMark Brown { 9889b4012bSMark Brown int i; 9989b4012bSMark Brown int end = reg + num_regs; 10089b4012bSMark Brown int ret = 0; 10189b4012bSMark Brown int bytes = num_regs * 2; 10289b4012bSMark Brown 10389b4012bSMark Brown if (wm8350->read_dev == NULL) 10489b4012bSMark Brown return -ENODEV; 10589b4012bSMark Brown 10689b4012bSMark Brown if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) { 10789b4012bSMark Brown dev_err(wm8350->dev, "invalid reg %x\n", 10889b4012bSMark Brown reg + num_regs - 1); 10989b4012bSMark Brown return -EINVAL; 11089b4012bSMark Brown } 11189b4012bSMark Brown 11289b4012bSMark Brown dev_dbg(wm8350->dev, 11389b4012bSMark Brown "%s R%d(0x%2.2x) %d regs\n", __func__, reg, reg, num_regs); 11489b4012bSMark Brown 11589b4012bSMark Brown #if WM8350_BUS_DEBUG 11689b4012bSMark Brown /* we can _safely_ read any register, but warn if read not supported */ 11789b4012bSMark Brown for (i = reg; i < end; i++) { 11889b4012bSMark Brown if (!wm8350_reg_io_map[i].readable) 11989b4012bSMark Brown dev_warn(wm8350->dev, 12089b4012bSMark Brown "reg R%d is not readable\n", i); 12189b4012bSMark Brown } 12289b4012bSMark Brown #endif 12389b4012bSMark Brown 12489b4012bSMark Brown /* if any volatile registers are required, then read back all */ 12589b4012bSMark Brown for (i = reg; i < end; i++) 12689b4012bSMark Brown if (wm8350_reg_io_map[i].vol) 12789b4012bSMark Brown return wm8350_phys_read(wm8350, reg, num_regs, dest); 12889b4012bSMark Brown 12989b4012bSMark Brown /* no volatiles, then cache is good */ 13089b4012bSMark Brown dev_dbg(wm8350->dev, "cache read\n"); 13189b4012bSMark Brown memcpy(dest, &wm8350->reg_cache[reg], bytes); 13289b4012bSMark Brown dump(num_regs, dest); 13389b4012bSMark Brown return ret; 13489b4012bSMark Brown } 13589b4012bSMark Brown 13689b4012bSMark Brown static inline int is_reg_locked(struct wm8350 *wm8350, u8 reg) 13789b4012bSMark Brown { 13889b4012bSMark Brown if (reg == WM8350_SECURITY || 13989b4012bSMark Brown wm8350->reg_cache[WM8350_SECURITY] == WM8350_UNLOCK_KEY) 14089b4012bSMark Brown return 0; 14189b4012bSMark Brown 14289b4012bSMark Brown if ((reg == WM8350_GPIO_CONFIGURATION_I_O) || 14389b4012bSMark Brown (reg >= WM8350_GPIO_FUNCTION_SELECT_1 && 14489b4012bSMark Brown reg <= WM8350_GPIO_FUNCTION_SELECT_4) || 14589b4012bSMark Brown (reg >= WM8350_BATTERY_CHARGER_CONTROL_1 && 14689b4012bSMark Brown reg <= WM8350_BATTERY_CHARGER_CONTROL_3)) 14789b4012bSMark Brown return 1; 14889b4012bSMark Brown return 0; 14989b4012bSMark Brown } 15089b4012bSMark Brown 15189b4012bSMark Brown static int wm8350_write(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *src) 15289b4012bSMark Brown { 15389b4012bSMark Brown int i; 15489b4012bSMark Brown int end = reg + num_regs; 15589b4012bSMark Brown int bytes = num_regs * 2; 15689b4012bSMark Brown 15789b4012bSMark Brown if (wm8350->write_dev == NULL) 15889b4012bSMark Brown return -ENODEV; 15989b4012bSMark Brown 16089b4012bSMark Brown if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) { 16189b4012bSMark Brown dev_err(wm8350->dev, "invalid reg %x\n", 16289b4012bSMark Brown reg + num_regs - 1); 16389b4012bSMark Brown return -EINVAL; 16489b4012bSMark Brown } 16589b4012bSMark Brown 16689b4012bSMark Brown /* it's generally not a good idea to write to RO or locked registers */ 16789b4012bSMark Brown for (i = reg; i < end; i++) { 16889b4012bSMark Brown if (!wm8350_reg_io_map[i].writable) { 16989b4012bSMark Brown dev_err(wm8350->dev, 17089b4012bSMark Brown "attempted write to read only reg R%d\n", i); 17189b4012bSMark Brown return -EINVAL; 17289b4012bSMark Brown } 17389b4012bSMark Brown 17489b4012bSMark Brown if (is_reg_locked(wm8350, i)) { 17589b4012bSMark Brown dev_err(wm8350->dev, 17689b4012bSMark Brown "attempted write to locked reg R%d\n", i); 17789b4012bSMark Brown return -EINVAL; 17889b4012bSMark Brown } 17989b4012bSMark Brown 18089b4012bSMark Brown src[i - reg] &= wm8350_reg_io_map[i].writable; 18189b4012bSMark Brown 18289b4012bSMark Brown wm8350->reg_cache[i] = 18389b4012bSMark Brown (wm8350->reg_cache[i] & ~wm8350_reg_io_map[i].writable) 18489b4012bSMark Brown | src[i - reg]; 18589b4012bSMark Brown 18689b4012bSMark Brown src[i - reg] = cpu_to_be16(src[i - reg]); 18789b4012bSMark Brown } 18889b4012bSMark Brown 18989b4012bSMark Brown /* Actually write it out */ 19089b4012bSMark Brown return wm8350->write_dev(wm8350, reg, bytes, (char *)src); 19189b4012bSMark Brown } 19289b4012bSMark Brown 19389b4012bSMark Brown /* 19489b4012bSMark Brown * Safe read, modify, write methods 19589b4012bSMark Brown */ 19689b4012bSMark Brown int wm8350_clear_bits(struct wm8350 *wm8350, u16 reg, u16 mask) 19789b4012bSMark Brown { 19889b4012bSMark Brown u16 data; 19989b4012bSMark Brown int err; 20089b4012bSMark Brown 20189b4012bSMark Brown mutex_lock(&io_mutex); 20289b4012bSMark Brown err = wm8350_read(wm8350, reg, 1, &data); 20389b4012bSMark Brown if (err) { 20489b4012bSMark Brown dev_err(wm8350->dev, "read from reg R%d failed\n", reg); 20589b4012bSMark Brown goto out; 20689b4012bSMark Brown } 20789b4012bSMark Brown 20889b4012bSMark Brown data &= ~mask; 20989b4012bSMark Brown err = wm8350_write(wm8350, reg, 1, &data); 21089b4012bSMark Brown if (err) 21189b4012bSMark Brown dev_err(wm8350->dev, "write to reg R%d failed\n", reg); 21289b4012bSMark Brown out: 21389b4012bSMark Brown mutex_unlock(&io_mutex); 21489b4012bSMark Brown return err; 21589b4012bSMark Brown } 21689b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_clear_bits); 21789b4012bSMark Brown 21889b4012bSMark Brown int wm8350_set_bits(struct wm8350 *wm8350, u16 reg, u16 mask) 21989b4012bSMark Brown { 22089b4012bSMark Brown u16 data; 22189b4012bSMark Brown int err; 22289b4012bSMark Brown 22389b4012bSMark Brown mutex_lock(&io_mutex); 22489b4012bSMark Brown err = wm8350_read(wm8350, reg, 1, &data); 22589b4012bSMark Brown if (err) { 22689b4012bSMark Brown dev_err(wm8350->dev, "read from reg R%d failed\n", reg); 22789b4012bSMark Brown goto out; 22889b4012bSMark Brown } 22989b4012bSMark Brown 23089b4012bSMark Brown data |= mask; 23189b4012bSMark Brown err = wm8350_write(wm8350, reg, 1, &data); 23289b4012bSMark Brown if (err) 23389b4012bSMark Brown dev_err(wm8350->dev, "write to reg R%d failed\n", reg); 23489b4012bSMark Brown out: 23589b4012bSMark Brown mutex_unlock(&io_mutex); 23689b4012bSMark Brown return err; 23789b4012bSMark Brown } 23889b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_set_bits); 23989b4012bSMark Brown 24089b4012bSMark Brown u16 wm8350_reg_read(struct wm8350 *wm8350, int reg) 24189b4012bSMark Brown { 24289b4012bSMark Brown u16 data; 24389b4012bSMark Brown int err; 24489b4012bSMark Brown 24589b4012bSMark Brown mutex_lock(&io_mutex); 24689b4012bSMark Brown err = wm8350_read(wm8350, reg, 1, &data); 24789b4012bSMark Brown if (err) 24889b4012bSMark Brown dev_err(wm8350->dev, "read from reg R%d failed\n", reg); 24989b4012bSMark Brown 25089b4012bSMark Brown mutex_unlock(&io_mutex); 25189b4012bSMark Brown return data; 25289b4012bSMark Brown } 25389b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_reg_read); 25489b4012bSMark Brown 25589b4012bSMark Brown int wm8350_reg_write(struct wm8350 *wm8350, int reg, u16 val) 25689b4012bSMark Brown { 25789b4012bSMark Brown int ret; 25889b4012bSMark Brown u16 data = val; 25989b4012bSMark Brown 26089b4012bSMark Brown mutex_lock(&io_mutex); 26189b4012bSMark Brown ret = wm8350_write(wm8350, reg, 1, &data); 26289b4012bSMark Brown if (ret) 26389b4012bSMark Brown dev_err(wm8350->dev, "write to reg R%d failed\n", reg); 26489b4012bSMark Brown mutex_unlock(&io_mutex); 26589b4012bSMark Brown return ret; 26689b4012bSMark Brown } 26789b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_reg_write); 26889b4012bSMark Brown 26989b4012bSMark Brown int wm8350_block_read(struct wm8350 *wm8350, int start_reg, int regs, 27089b4012bSMark Brown u16 *dest) 27189b4012bSMark Brown { 27289b4012bSMark Brown int err = 0; 27389b4012bSMark Brown 27489b4012bSMark Brown mutex_lock(&io_mutex); 27589b4012bSMark Brown err = wm8350_read(wm8350, start_reg, regs, dest); 27689b4012bSMark Brown if (err) 27789b4012bSMark Brown dev_err(wm8350->dev, "block read starting from R%d failed\n", 27889b4012bSMark Brown start_reg); 27989b4012bSMark Brown mutex_unlock(&io_mutex); 28089b4012bSMark Brown return err; 28189b4012bSMark Brown } 28289b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_block_read); 28389b4012bSMark Brown 28489b4012bSMark Brown int wm8350_block_write(struct wm8350 *wm8350, int start_reg, int regs, 28589b4012bSMark Brown u16 *src) 28689b4012bSMark Brown { 28789b4012bSMark Brown int ret = 0; 28889b4012bSMark Brown 28989b4012bSMark Brown mutex_lock(&io_mutex); 29089b4012bSMark Brown ret = wm8350_write(wm8350, start_reg, regs, src); 29189b4012bSMark Brown if (ret) 29289b4012bSMark Brown dev_err(wm8350->dev, "block write starting at R%d failed\n", 29389b4012bSMark Brown start_reg); 29489b4012bSMark Brown mutex_unlock(&io_mutex); 29589b4012bSMark Brown return ret; 29689b4012bSMark Brown } 29789b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_block_write); 29889b4012bSMark Brown 29989b4012bSMark Brown int wm8350_reg_lock(struct wm8350 *wm8350) 30089b4012bSMark Brown { 30189b4012bSMark Brown u16 key = WM8350_LOCK_KEY; 30289b4012bSMark Brown int ret; 30389b4012bSMark Brown 30489b4012bSMark Brown ldbg(__func__); 30589b4012bSMark Brown mutex_lock(&io_mutex); 30689b4012bSMark Brown ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key); 30789b4012bSMark Brown if (ret) 30889b4012bSMark Brown dev_err(wm8350->dev, "lock failed\n"); 30989b4012bSMark Brown mutex_unlock(&io_mutex); 31089b4012bSMark Brown return ret; 31189b4012bSMark Brown } 31289b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_reg_lock); 31389b4012bSMark Brown 31489b4012bSMark Brown int wm8350_reg_unlock(struct wm8350 *wm8350) 31589b4012bSMark Brown { 31689b4012bSMark Brown u16 key = WM8350_UNLOCK_KEY; 31789b4012bSMark Brown int ret; 31889b4012bSMark Brown 31989b4012bSMark Brown ldbg(__func__); 32089b4012bSMark Brown mutex_lock(&io_mutex); 32189b4012bSMark Brown ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key); 32289b4012bSMark Brown if (ret) 32389b4012bSMark Brown dev_err(wm8350->dev, "unlock failed\n"); 32489b4012bSMark Brown mutex_unlock(&io_mutex); 32589b4012bSMark Brown return ret; 32689b4012bSMark Brown } 32789b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_reg_unlock); 32889b4012bSMark Brown 329ebccec0fSMark Brown static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq) 330ebccec0fSMark Brown { 331ebccec0fSMark Brown mutex_lock(&wm8350->irq_mutex); 332ebccec0fSMark Brown 333ebccec0fSMark Brown if (wm8350->irq[irq].handler) 334ebccec0fSMark Brown wm8350->irq[irq].handler(wm8350, irq, wm8350->irq[irq].data); 335ebccec0fSMark Brown else { 336ebccec0fSMark Brown dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n", 337ebccec0fSMark Brown irq); 338ebccec0fSMark Brown wm8350_mask_irq(wm8350, irq); 339ebccec0fSMark Brown } 340ebccec0fSMark Brown 341ebccec0fSMark Brown mutex_unlock(&wm8350->irq_mutex); 342ebccec0fSMark Brown } 343ebccec0fSMark Brown 344ebccec0fSMark Brown /* 345ebccec0fSMark Brown * wm8350_irq_worker actually handles the interrupts. Since all 346ebccec0fSMark Brown * interrupts are clear on read the IRQ line will be reasserted and 347ebccec0fSMark Brown * the physical IRQ will be handled again if another interrupt is 348ebccec0fSMark Brown * asserted while we run - in the normal course of events this is a 349ebccec0fSMark Brown * rare occurrence so we save I2C/SPI reads. 350ebccec0fSMark Brown */ 351ebccec0fSMark Brown static void wm8350_irq_worker(struct work_struct *work) 352ebccec0fSMark Brown { 353ebccec0fSMark Brown struct wm8350 *wm8350 = container_of(work, struct wm8350, irq_work); 354ebccec0fSMark Brown u16 level_one, status1, status2, comp; 355ebccec0fSMark Brown 356ebccec0fSMark Brown /* TODO: Use block reads to improve performance? */ 357ebccec0fSMark Brown level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS) 358ebccec0fSMark Brown & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK); 359ebccec0fSMark Brown status1 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_1) 360ebccec0fSMark Brown & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_1_MASK); 361ebccec0fSMark Brown status2 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_2) 362ebccec0fSMark Brown & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_2_MASK); 363ebccec0fSMark Brown comp = wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS) 364ebccec0fSMark Brown & ~wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK); 365ebccec0fSMark Brown 366ebccec0fSMark Brown /* over current */ 367ebccec0fSMark Brown if (level_one & WM8350_OC_INT) { 368ebccec0fSMark Brown u16 oc; 369ebccec0fSMark Brown 370ebccec0fSMark Brown oc = wm8350_reg_read(wm8350, WM8350_OVER_CURRENT_INT_STATUS); 371ebccec0fSMark Brown oc &= ~wm8350_reg_read(wm8350, 372ebccec0fSMark Brown WM8350_OVER_CURRENT_INT_STATUS_MASK); 373ebccec0fSMark Brown 374ebccec0fSMark Brown if (oc & WM8350_OC_LS_EINT) /* limit switch */ 375ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_OC_LS); 376ebccec0fSMark Brown } 377ebccec0fSMark Brown 378ebccec0fSMark Brown /* under voltage */ 379ebccec0fSMark Brown if (level_one & WM8350_UV_INT) { 380ebccec0fSMark Brown u16 uv; 381ebccec0fSMark Brown 382ebccec0fSMark Brown uv = wm8350_reg_read(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS); 383ebccec0fSMark Brown uv &= ~wm8350_reg_read(wm8350, 384ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK); 385ebccec0fSMark Brown 386ebccec0fSMark Brown if (uv & WM8350_UV_DC1_EINT) 387ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC1); 388ebccec0fSMark Brown if (uv & WM8350_UV_DC2_EINT) 389ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC2); 390ebccec0fSMark Brown if (uv & WM8350_UV_DC3_EINT) 391ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC3); 392ebccec0fSMark Brown if (uv & WM8350_UV_DC4_EINT) 393ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC4); 394ebccec0fSMark Brown if (uv & WM8350_UV_DC5_EINT) 395ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC5); 396ebccec0fSMark Brown if (uv & WM8350_UV_DC6_EINT) 397ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC6); 398ebccec0fSMark Brown if (uv & WM8350_UV_LDO1_EINT) 399ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO1); 400ebccec0fSMark Brown if (uv & WM8350_UV_LDO2_EINT) 401ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO2); 402ebccec0fSMark Brown if (uv & WM8350_UV_LDO3_EINT) 403ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO3); 404ebccec0fSMark Brown if (uv & WM8350_UV_LDO4_EINT) 405ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO4); 406ebccec0fSMark Brown } 407ebccec0fSMark Brown 408ebccec0fSMark Brown /* charger, RTC */ 409ebccec0fSMark Brown if (status1) { 410ebccec0fSMark Brown if (status1 & WM8350_CHG_BAT_HOT_EINT) 411ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 412ebccec0fSMark Brown WM8350_IRQ_CHG_BAT_HOT); 413ebccec0fSMark Brown if (status1 & WM8350_CHG_BAT_COLD_EINT) 414ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 415ebccec0fSMark Brown WM8350_IRQ_CHG_BAT_COLD); 416ebccec0fSMark Brown if (status1 & WM8350_CHG_BAT_FAIL_EINT) 417ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 418ebccec0fSMark Brown WM8350_IRQ_CHG_BAT_FAIL); 419ebccec0fSMark Brown if (status1 & WM8350_CHG_TO_EINT) 420ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_TO); 421ebccec0fSMark Brown if (status1 & WM8350_CHG_END_EINT) 422ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_END); 423ebccec0fSMark Brown if (status1 & WM8350_CHG_START_EINT) 424ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_START); 425ebccec0fSMark Brown if (status1 & WM8350_CHG_FAST_RDY_EINT) 426ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 427ebccec0fSMark Brown WM8350_IRQ_CHG_FAST_RDY); 428ebccec0fSMark Brown if (status1 & WM8350_CHG_VBATT_LT_3P9_EINT) 429ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 430ebccec0fSMark Brown WM8350_IRQ_CHG_VBATT_LT_3P9); 431ebccec0fSMark Brown if (status1 & WM8350_CHG_VBATT_LT_3P1_EINT) 432ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 433ebccec0fSMark Brown WM8350_IRQ_CHG_VBATT_LT_3P1); 434ebccec0fSMark Brown if (status1 & WM8350_CHG_VBATT_LT_2P85_EINT) 435ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 436ebccec0fSMark Brown WM8350_IRQ_CHG_VBATT_LT_2P85); 437ebccec0fSMark Brown if (status1 & WM8350_RTC_ALM_EINT) 438ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_ALM); 439ebccec0fSMark Brown if (status1 & WM8350_RTC_SEC_EINT) 440ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_SEC); 441ebccec0fSMark Brown if (status1 & WM8350_RTC_PER_EINT) 442ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_PER); 443ebccec0fSMark Brown } 444ebccec0fSMark Brown 445ebccec0fSMark Brown /* current sink, system, aux adc */ 446ebccec0fSMark Brown if (status2) { 447ebccec0fSMark Brown if (status2 & WM8350_CS1_EINT) 448ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS1); 449ebccec0fSMark Brown if (status2 & WM8350_CS2_EINT) 450ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS2); 451ebccec0fSMark Brown 452ebccec0fSMark Brown if (status2 & WM8350_SYS_HYST_COMP_FAIL_EINT) 453ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 454ebccec0fSMark Brown WM8350_IRQ_SYS_HYST_COMP_FAIL); 455ebccec0fSMark Brown if (status2 & WM8350_SYS_CHIP_GT115_EINT) 456ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 457ebccec0fSMark Brown WM8350_IRQ_SYS_CHIP_GT115); 458ebccec0fSMark Brown if (status2 & WM8350_SYS_CHIP_GT140_EINT) 459ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 460ebccec0fSMark Brown WM8350_IRQ_SYS_CHIP_GT140); 461ebccec0fSMark Brown if (status2 & WM8350_SYS_WDOG_TO_EINT) 462ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 463ebccec0fSMark Brown WM8350_IRQ_SYS_WDOG_TO); 464ebccec0fSMark Brown 465ebccec0fSMark Brown if (status2 & WM8350_AUXADC_DATARDY_EINT) 466ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 467ebccec0fSMark Brown WM8350_IRQ_AUXADC_DATARDY); 468ebccec0fSMark Brown if (status2 & WM8350_AUXADC_DCOMP4_EINT) 469ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 470ebccec0fSMark Brown WM8350_IRQ_AUXADC_DCOMP4); 471ebccec0fSMark Brown if (status2 & WM8350_AUXADC_DCOMP3_EINT) 472ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 473ebccec0fSMark Brown WM8350_IRQ_AUXADC_DCOMP3); 474ebccec0fSMark Brown if (status2 & WM8350_AUXADC_DCOMP2_EINT) 475ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 476ebccec0fSMark Brown WM8350_IRQ_AUXADC_DCOMP2); 477ebccec0fSMark Brown if (status2 & WM8350_AUXADC_DCOMP1_EINT) 478ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 479ebccec0fSMark Brown WM8350_IRQ_AUXADC_DCOMP1); 480ebccec0fSMark Brown 481ebccec0fSMark Brown if (status2 & WM8350_USB_LIMIT_EINT) 482ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_USB_LIMIT); 483ebccec0fSMark Brown } 484ebccec0fSMark Brown 485ebccec0fSMark Brown /* wake, codec, ext */ 486ebccec0fSMark Brown if (comp) { 487ebccec0fSMark Brown if (comp & WM8350_WKUP_OFF_STATE_EINT) 488ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 489ebccec0fSMark Brown WM8350_IRQ_WKUP_OFF_STATE); 490ebccec0fSMark Brown if (comp & WM8350_WKUP_HIB_STATE_EINT) 491ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 492ebccec0fSMark Brown WM8350_IRQ_WKUP_HIB_STATE); 493ebccec0fSMark Brown if (comp & WM8350_WKUP_CONV_FAULT_EINT) 494ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 495ebccec0fSMark Brown WM8350_IRQ_WKUP_CONV_FAULT); 496ebccec0fSMark Brown if (comp & WM8350_WKUP_WDOG_RST_EINT) 497ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 498ebccec0fSMark Brown WM8350_IRQ_WKUP_WDOG_RST); 499ebccec0fSMark Brown if (comp & WM8350_WKUP_GP_PWR_ON_EINT) 500ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 501ebccec0fSMark Brown WM8350_IRQ_WKUP_GP_PWR_ON); 502ebccec0fSMark Brown if (comp & WM8350_WKUP_ONKEY_EINT) 503ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_WKUP_ONKEY); 504ebccec0fSMark Brown if (comp & WM8350_WKUP_GP_WAKEUP_EINT) 505ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 506ebccec0fSMark Brown WM8350_IRQ_WKUP_GP_WAKEUP); 507ebccec0fSMark Brown 508ebccec0fSMark Brown if (comp & WM8350_CODEC_JCK_DET_L_EINT) 509ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 510ebccec0fSMark Brown WM8350_IRQ_CODEC_JCK_DET_L); 511ebccec0fSMark Brown if (comp & WM8350_CODEC_JCK_DET_R_EINT) 512ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 513ebccec0fSMark Brown WM8350_IRQ_CODEC_JCK_DET_R); 514ebccec0fSMark Brown if (comp & WM8350_CODEC_MICSCD_EINT) 515ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 516ebccec0fSMark Brown WM8350_IRQ_CODEC_MICSCD); 517ebccec0fSMark Brown if (comp & WM8350_CODEC_MICD_EINT) 518ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_CODEC_MICD); 519ebccec0fSMark Brown 520ebccec0fSMark Brown if (comp & WM8350_EXT_USB_FB_EINT) 521ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_USB_FB); 522ebccec0fSMark Brown if (comp & WM8350_EXT_WALL_FB_EINT) 523ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 524ebccec0fSMark Brown WM8350_IRQ_EXT_WALL_FB); 525ebccec0fSMark Brown if (comp & WM8350_EXT_BAT_FB_EINT) 526ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_BAT_FB); 527ebccec0fSMark Brown } 528ebccec0fSMark Brown 529ebccec0fSMark Brown if (level_one & WM8350_GP_INT) { 530ebccec0fSMark Brown int i; 531ebccec0fSMark Brown u16 gpio; 532ebccec0fSMark Brown 533ebccec0fSMark Brown gpio = wm8350_reg_read(wm8350, WM8350_GPIO_INT_STATUS); 534ebccec0fSMark Brown gpio &= ~wm8350_reg_read(wm8350, 535ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK); 536ebccec0fSMark Brown 537ebccec0fSMark Brown for (i = 0; i < 12; i++) { 538ebccec0fSMark Brown if (gpio & (1 << i)) 539ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 540ebccec0fSMark Brown WM8350_IRQ_GPIO(i)); 541ebccec0fSMark Brown } 542ebccec0fSMark Brown } 543ebccec0fSMark Brown 544ebccec0fSMark Brown enable_irq(wm8350->chip_irq); 545ebccec0fSMark Brown } 546ebccec0fSMark Brown 547ebccec0fSMark Brown static irqreturn_t wm8350_irq(int irq, void *data) 548ebccec0fSMark Brown { 549ebccec0fSMark Brown struct wm8350 *wm8350 = data; 550ebccec0fSMark Brown 551ebccec0fSMark Brown disable_irq_nosync(irq); 552ebccec0fSMark Brown schedule_work(&wm8350->irq_work); 553ebccec0fSMark Brown 554ebccec0fSMark Brown return IRQ_HANDLED; 555ebccec0fSMark Brown } 556ebccec0fSMark Brown 557ebccec0fSMark Brown int wm8350_register_irq(struct wm8350 *wm8350, int irq, 558ebccec0fSMark Brown void (*handler) (struct wm8350 *, int, void *), 559ebccec0fSMark Brown void *data) 560ebccec0fSMark Brown { 561ebccec0fSMark Brown if (irq < 0 || irq > WM8350_NUM_IRQ || !handler) 562ebccec0fSMark Brown return -EINVAL; 563ebccec0fSMark Brown 564ebccec0fSMark Brown if (wm8350->irq[irq].handler) 565ebccec0fSMark Brown return -EBUSY; 566ebccec0fSMark Brown 567ebccec0fSMark Brown mutex_lock(&wm8350->irq_mutex); 568ebccec0fSMark Brown wm8350->irq[irq].handler = handler; 569ebccec0fSMark Brown wm8350->irq[irq].data = data; 570ebccec0fSMark Brown mutex_unlock(&wm8350->irq_mutex); 571ebccec0fSMark Brown 572ebccec0fSMark Brown return 0; 573ebccec0fSMark Brown } 574ebccec0fSMark Brown EXPORT_SYMBOL_GPL(wm8350_register_irq); 575ebccec0fSMark Brown 576ebccec0fSMark Brown int wm8350_free_irq(struct wm8350 *wm8350, int irq) 577ebccec0fSMark Brown { 578ebccec0fSMark Brown if (irq < 0 || irq > WM8350_NUM_IRQ) 579ebccec0fSMark Brown return -EINVAL; 580ebccec0fSMark Brown 581ebccec0fSMark Brown mutex_lock(&wm8350->irq_mutex); 582ebccec0fSMark Brown wm8350->irq[irq].handler = NULL; 583ebccec0fSMark Brown mutex_unlock(&wm8350->irq_mutex); 584ebccec0fSMark Brown return 0; 585ebccec0fSMark Brown } 586ebccec0fSMark Brown EXPORT_SYMBOL_GPL(wm8350_free_irq); 587ebccec0fSMark Brown 588ebccec0fSMark Brown int wm8350_mask_irq(struct wm8350 *wm8350, int irq) 589ebccec0fSMark Brown { 590ebccec0fSMark Brown switch (irq) { 591ebccec0fSMark Brown case WM8350_IRQ_CHG_BAT_HOT: 592ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 593ebccec0fSMark Brown WM8350_IM_CHG_BAT_HOT_EINT); 594ebccec0fSMark Brown case WM8350_IRQ_CHG_BAT_COLD: 595ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 596ebccec0fSMark Brown WM8350_IM_CHG_BAT_COLD_EINT); 597ebccec0fSMark Brown case WM8350_IRQ_CHG_BAT_FAIL: 598ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 599ebccec0fSMark Brown WM8350_IM_CHG_BAT_FAIL_EINT); 600ebccec0fSMark Brown case WM8350_IRQ_CHG_TO: 601ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 602ebccec0fSMark Brown WM8350_IM_CHG_TO_EINT); 603ebccec0fSMark Brown case WM8350_IRQ_CHG_END: 604ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 605ebccec0fSMark Brown WM8350_IM_CHG_END_EINT); 606ebccec0fSMark Brown case WM8350_IRQ_CHG_START: 607ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 608ebccec0fSMark Brown WM8350_IM_CHG_START_EINT); 609ebccec0fSMark Brown case WM8350_IRQ_CHG_FAST_RDY: 610ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 611ebccec0fSMark Brown WM8350_IM_CHG_FAST_RDY_EINT); 612ebccec0fSMark Brown case WM8350_IRQ_RTC_PER: 613ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 614ebccec0fSMark Brown WM8350_IM_RTC_PER_EINT); 615ebccec0fSMark Brown case WM8350_IRQ_RTC_SEC: 616ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 617ebccec0fSMark Brown WM8350_IM_RTC_SEC_EINT); 618ebccec0fSMark Brown case WM8350_IRQ_RTC_ALM: 619ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 620ebccec0fSMark Brown WM8350_IM_RTC_ALM_EINT); 621ebccec0fSMark Brown case WM8350_IRQ_CHG_VBATT_LT_3P9: 622ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 623ebccec0fSMark Brown WM8350_IM_CHG_VBATT_LT_3P9_EINT); 624ebccec0fSMark Brown case WM8350_IRQ_CHG_VBATT_LT_3P1: 625ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 626ebccec0fSMark Brown WM8350_IM_CHG_VBATT_LT_3P1_EINT); 627ebccec0fSMark Brown case WM8350_IRQ_CHG_VBATT_LT_2P85: 628ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 629ebccec0fSMark Brown WM8350_IM_CHG_VBATT_LT_2P85_EINT); 630ebccec0fSMark Brown case WM8350_IRQ_CS1: 631ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 632ebccec0fSMark Brown WM8350_IM_CS1_EINT); 633ebccec0fSMark Brown case WM8350_IRQ_CS2: 634ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 635ebccec0fSMark Brown WM8350_IM_CS2_EINT); 636ebccec0fSMark Brown case WM8350_IRQ_USB_LIMIT: 637ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 638ebccec0fSMark Brown WM8350_IM_USB_LIMIT_EINT); 639ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DATARDY: 640ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 641ebccec0fSMark Brown WM8350_IM_AUXADC_DATARDY_EINT); 642ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DCOMP4: 643ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 644ebccec0fSMark Brown WM8350_IM_AUXADC_DCOMP4_EINT); 645ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DCOMP3: 646ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 647ebccec0fSMark Brown WM8350_IM_AUXADC_DCOMP3_EINT); 648ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DCOMP2: 649ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 650ebccec0fSMark Brown WM8350_IM_AUXADC_DCOMP2_EINT); 651ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DCOMP1: 652ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 653ebccec0fSMark Brown WM8350_IM_AUXADC_DCOMP1_EINT); 654ebccec0fSMark Brown case WM8350_IRQ_SYS_HYST_COMP_FAIL: 655ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 656ebccec0fSMark Brown WM8350_IM_SYS_HYST_COMP_FAIL_EINT); 657ebccec0fSMark Brown case WM8350_IRQ_SYS_CHIP_GT115: 658ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 659ebccec0fSMark Brown WM8350_IM_SYS_CHIP_GT115_EINT); 660ebccec0fSMark Brown case WM8350_IRQ_SYS_CHIP_GT140: 661ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 662ebccec0fSMark Brown WM8350_IM_SYS_CHIP_GT140_EINT); 663ebccec0fSMark Brown case WM8350_IRQ_SYS_WDOG_TO: 664ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 665ebccec0fSMark Brown WM8350_IM_SYS_WDOG_TO_EINT); 666ebccec0fSMark Brown case WM8350_IRQ_UV_LDO4: 667ebccec0fSMark Brown return wm8350_set_bits(wm8350, 668ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 669ebccec0fSMark Brown WM8350_IM_UV_LDO4_EINT); 670ebccec0fSMark Brown case WM8350_IRQ_UV_LDO3: 671ebccec0fSMark Brown return wm8350_set_bits(wm8350, 672ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 673ebccec0fSMark Brown WM8350_IM_UV_LDO3_EINT); 674ebccec0fSMark Brown case WM8350_IRQ_UV_LDO2: 675ebccec0fSMark Brown return wm8350_set_bits(wm8350, 676ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 677ebccec0fSMark Brown WM8350_IM_UV_LDO2_EINT); 678ebccec0fSMark Brown case WM8350_IRQ_UV_LDO1: 679ebccec0fSMark Brown return wm8350_set_bits(wm8350, 680ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 681ebccec0fSMark Brown WM8350_IM_UV_LDO1_EINT); 682ebccec0fSMark Brown case WM8350_IRQ_UV_DC6: 683ebccec0fSMark Brown return wm8350_set_bits(wm8350, 684ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 685ebccec0fSMark Brown WM8350_IM_UV_DC6_EINT); 686ebccec0fSMark Brown case WM8350_IRQ_UV_DC5: 687ebccec0fSMark Brown return wm8350_set_bits(wm8350, 688ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 689ebccec0fSMark Brown WM8350_IM_UV_DC5_EINT); 690ebccec0fSMark Brown case WM8350_IRQ_UV_DC4: 691ebccec0fSMark Brown return wm8350_set_bits(wm8350, 692ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 693ebccec0fSMark Brown WM8350_IM_UV_DC4_EINT); 694ebccec0fSMark Brown case WM8350_IRQ_UV_DC3: 695ebccec0fSMark Brown return wm8350_set_bits(wm8350, 696ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 697ebccec0fSMark Brown WM8350_IM_UV_DC3_EINT); 698ebccec0fSMark Brown case WM8350_IRQ_UV_DC2: 699ebccec0fSMark Brown return wm8350_set_bits(wm8350, 700ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 701ebccec0fSMark Brown WM8350_IM_UV_DC2_EINT); 702ebccec0fSMark Brown case WM8350_IRQ_UV_DC1: 703ebccec0fSMark Brown return wm8350_set_bits(wm8350, 704ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 705ebccec0fSMark Brown WM8350_IM_UV_DC1_EINT); 706ebccec0fSMark Brown case WM8350_IRQ_OC_LS: 707ebccec0fSMark Brown return wm8350_set_bits(wm8350, 708ebccec0fSMark Brown WM8350_OVER_CURRENT_INT_STATUS_MASK, 709ebccec0fSMark Brown WM8350_IM_OC_LS_EINT); 710ebccec0fSMark Brown case WM8350_IRQ_EXT_USB_FB: 711ebccec0fSMark Brown return wm8350_set_bits(wm8350, 712ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 713ebccec0fSMark Brown WM8350_IM_EXT_USB_FB_EINT); 714ebccec0fSMark Brown case WM8350_IRQ_EXT_WALL_FB: 715ebccec0fSMark Brown return wm8350_set_bits(wm8350, 716ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 717ebccec0fSMark Brown WM8350_IM_EXT_WALL_FB_EINT); 718ebccec0fSMark Brown case WM8350_IRQ_EXT_BAT_FB: 719ebccec0fSMark Brown return wm8350_set_bits(wm8350, 720ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 721ebccec0fSMark Brown WM8350_IM_EXT_BAT_FB_EINT); 722ebccec0fSMark Brown case WM8350_IRQ_CODEC_JCK_DET_L: 723ebccec0fSMark Brown return wm8350_set_bits(wm8350, 724ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 725ebccec0fSMark Brown WM8350_IM_CODEC_JCK_DET_L_EINT); 726ebccec0fSMark Brown case WM8350_IRQ_CODEC_JCK_DET_R: 727ebccec0fSMark Brown return wm8350_set_bits(wm8350, 728ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 729ebccec0fSMark Brown WM8350_IM_CODEC_JCK_DET_R_EINT); 730ebccec0fSMark Brown case WM8350_IRQ_CODEC_MICSCD: 731ebccec0fSMark Brown return wm8350_set_bits(wm8350, 732ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 733ebccec0fSMark Brown WM8350_IM_CODEC_MICSCD_EINT); 734ebccec0fSMark Brown case WM8350_IRQ_CODEC_MICD: 735ebccec0fSMark Brown return wm8350_set_bits(wm8350, 736ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 737ebccec0fSMark Brown WM8350_IM_CODEC_MICD_EINT); 738ebccec0fSMark Brown case WM8350_IRQ_WKUP_OFF_STATE: 739ebccec0fSMark Brown return wm8350_set_bits(wm8350, 740ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 741ebccec0fSMark Brown WM8350_IM_WKUP_OFF_STATE_EINT); 742ebccec0fSMark Brown case WM8350_IRQ_WKUP_HIB_STATE: 743ebccec0fSMark Brown return wm8350_set_bits(wm8350, 744ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 745ebccec0fSMark Brown WM8350_IM_WKUP_HIB_STATE_EINT); 746ebccec0fSMark Brown case WM8350_IRQ_WKUP_CONV_FAULT: 747ebccec0fSMark Brown return wm8350_set_bits(wm8350, 748ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 749ebccec0fSMark Brown WM8350_IM_WKUP_CONV_FAULT_EINT); 750ebccec0fSMark Brown case WM8350_IRQ_WKUP_WDOG_RST: 751ebccec0fSMark Brown return wm8350_set_bits(wm8350, 752ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 753ebccec0fSMark Brown WM8350_IM_WKUP_OFF_STATE_EINT); 754ebccec0fSMark Brown case WM8350_IRQ_WKUP_GP_PWR_ON: 755ebccec0fSMark Brown return wm8350_set_bits(wm8350, 756ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 757ebccec0fSMark Brown WM8350_IM_WKUP_GP_PWR_ON_EINT); 758ebccec0fSMark Brown case WM8350_IRQ_WKUP_ONKEY: 759ebccec0fSMark Brown return wm8350_set_bits(wm8350, 760ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 761ebccec0fSMark Brown WM8350_IM_WKUP_ONKEY_EINT); 762ebccec0fSMark Brown case WM8350_IRQ_WKUP_GP_WAKEUP: 763ebccec0fSMark Brown return wm8350_set_bits(wm8350, 764ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 765ebccec0fSMark Brown WM8350_IM_WKUP_GP_WAKEUP_EINT); 766ebccec0fSMark Brown case WM8350_IRQ_GPIO(0): 767ebccec0fSMark Brown return wm8350_set_bits(wm8350, 768ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 769ebccec0fSMark Brown WM8350_IM_GP0_EINT); 770ebccec0fSMark Brown case WM8350_IRQ_GPIO(1): 771ebccec0fSMark Brown return wm8350_set_bits(wm8350, 772ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 773ebccec0fSMark Brown WM8350_IM_GP1_EINT); 774ebccec0fSMark Brown case WM8350_IRQ_GPIO(2): 775ebccec0fSMark Brown return wm8350_set_bits(wm8350, 776ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 777ebccec0fSMark Brown WM8350_IM_GP2_EINT); 778ebccec0fSMark Brown case WM8350_IRQ_GPIO(3): 779ebccec0fSMark Brown return wm8350_set_bits(wm8350, 780ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 781ebccec0fSMark Brown WM8350_IM_GP3_EINT); 782ebccec0fSMark Brown case WM8350_IRQ_GPIO(4): 783ebccec0fSMark Brown return wm8350_set_bits(wm8350, 784ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 785ebccec0fSMark Brown WM8350_IM_GP4_EINT); 786ebccec0fSMark Brown case WM8350_IRQ_GPIO(5): 787ebccec0fSMark Brown return wm8350_set_bits(wm8350, 788ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 789ebccec0fSMark Brown WM8350_IM_GP5_EINT); 790ebccec0fSMark Brown case WM8350_IRQ_GPIO(6): 791ebccec0fSMark Brown return wm8350_set_bits(wm8350, 792ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 793ebccec0fSMark Brown WM8350_IM_GP6_EINT); 794ebccec0fSMark Brown case WM8350_IRQ_GPIO(7): 795ebccec0fSMark Brown return wm8350_set_bits(wm8350, 796ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 797ebccec0fSMark Brown WM8350_IM_GP7_EINT); 798ebccec0fSMark Brown case WM8350_IRQ_GPIO(8): 799ebccec0fSMark Brown return wm8350_set_bits(wm8350, 800ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 801ebccec0fSMark Brown WM8350_IM_GP8_EINT); 802ebccec0fSMark Brown case WM8350_IRQ_GPIO(9): 803ebccec0fSMark Brown return wm8350_set_bits(wm8350, 804ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 805ebccec0fSMark Brown WM8350_IM_GP9_EINT); 806ebccec0fSMark Brown case WM8350_IRQ_GPIO(10): 807ebccec0fSMark Brown return wm8350_set_bits(wm8350, 808ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 809ebccec0fSMark Brown WM8350_IM_GP10_EINT); 810ebccec0fSMark Brown case WM8350_IRQ_GPIO(11): 811ebccec0fSMark Brown return wm8350_set_bits(wm8350, 812ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 813ebccec0fSMark Brown WM8350_IM_GP11_EINT); 814ebccec0fSMark Brown case WM8350_IRQ_GPIO(12): 815ebccec0fSMark Brown return wm8350_set_bits(wm8350, 816ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 817ebccec0fSMark Brown WM8350_IM_GP12_EINT); 818ebccec0fSMark Brown default: 819ebccec0fSMark Brown dev_warn(wm8350->dev, "Attempting to mask unknown IRQ %d\n", 820ebccec0fSMark Brown irq); 821ebccec0fSMark Brown return -EINVAL; 822ebccec0fSMark Brown } 823ebccec0fSMark Brown return 0; 824ebccec0fSMark Brown } 825ebccec0fSMark Brown EXPORT_SYMBOL_GPL(wm8350_mask_irq); 826ebccec0fSMark Brown 827ebccec0fSMark Brown int wm8350_unmask_irq(struct wm8350 *wm8350, int irq) 828ebccec0fSMark Brown { 829ebccec0fSMark Brown switch (irq) { 830ebccec0fSMark Brown case WM8350_IRQ_CHG_BAT_HOT: 831ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 832ebccec0fSMark Brown WM8350_IM_CHG_BAT_HOT_EINT); 833ebccec0fSMark Brown case WM8350_IRQ_CHG_BAT_COLD: 834ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 835ebccec0fSMark Brown WM8350_IM_CHG_BAT_COLD_EINT); 836ebccec0fSMark Brown case WM8350_IRQ_CHG_BAT_FAIL: 837ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 838ebccec0fSMark Brown WM8350_IM_CHG_BAT_FAIL_EINT); 839ebccec0fSMark Brown case WM8350_IRQ_CHG_TO: 840ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 841ebccec0fSMark Brown WM8350_IM_CHG_TO_EINT); 842ebccec0fSMark Brown case WM8350_IRQ_CHG_END: 843ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 844ebccec0fSMark Brown WM8350_IM_CHG_END_EINT); 845ebccec0fSMark Brown case WM8350_IRQ_CHG_START: 846ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 847ebccec0fSMark Brown WM8350_IM_CHG_START_EINT); 848ebccec0fSMark Brown case WM8350_IRQ_CHG_FAST_RDY: 849ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 850ebccec0fSMark Brown WM8350_IM_CHG_FAST_RDY_EINT); 851ebccec0fSMark Brown case WM8350_IRQ_RTC_PER: 852ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 853ebccec0fSMark Brown WM8350_IM_RTC_PER_EINT); 854ebccec0fSMark Brown case WM8350_IRQ_RTC_SEC: 855ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 856ebccec0fSMark Brown WM8350_IM_RTC_SEC_EINT); 857ebccec0fSMark Brown case WM8350_IRQ_RTC_ALM: 858ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 859ebccec0fSMark Brown WM8350_IM_RTC_ALM_EINT); 860ebccec0fSMark Brown case WM8350_IRQ_CHG_VBATT_LT_3P9: 861ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 862ebccec0fSMark Brown WM8350_IM_CHG_VBATT_LT_3P9_EINT); 863ebccec0fSMark Brown case WM8350_IRQ_CHG_VBATT_LT_3P1: 864ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 865ebccec0fSMark Brown WM8350_IM_CHG_VBATT_LT_3P1_EINT); 866ebccec0fSMark Brown case WM8350_IRQ_CHG_VBATT_LT_2P85: 867ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 868ebccec0fSMark Brown WM8350_IM_CHG_VBATT_LT_2P85_EINT); 869ebccec0fSMark Brown case WM8350_IRQ_CS1: 870ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 871ebccec0fSMark Brown WM8350_IM_CS1_EINT); 872ebccec0fSMark Brown case WM8350_IRQ_CS2: 873ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 874ebccec0fSMark Brown WM8350_IM_CS2_EINT); 875ebccec0fSMark Brown case WM8350_IRQ_USB_LIMIT: 876ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 877ebccec0fSMark Brown WM8350_IM_USB_LIMIT_EINT); 878ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DATARDY: 879ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 880ebccec0fSMark Brown WM8350_IM_AUXADC_DATARDY_EINT); 881ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DCOMP4: 882ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 883ebccec0fSMark Brown WM8350_IM_AUXADC_DCOMP4_EINT); 884ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DCOMP3: 885ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 886ebccec0fSMark Brown WM8350_IM_AUXADC_DCOMP3_EINT); 887ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DCOMP2: 888ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 889ebccec0fSMark Brown WM8350_IM_AUXADC_DCOMP2_EINT); 890ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DCOMP1: 891ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 892ebccec0fSMark Brown WM8350_IM_AUXADC_DCOMP1_EINT); 893ebccec0fSMark Brown case WM8350_IRQ_SYS_HYST_COMP_FAIL: 894ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 895ebccec0fSMark Brown WM8350_IM_SYS_HYST_COMP_FAIL_EINT); 896ebccec0fSMark Brown case WM8350_IRQ_SYS_CHIP_GT115: 897ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 898ebccec0fSMark Brown WM8350_IM_SYS_CHIP_GT115_EINT); 899ebccec0fSMark Brown case WM8350_IRQ_SYS_CHIP_GT140: 900ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 901ebccec0fSMark Brown WM8350_IM_SYS_CHIP_GT140_EINT); 902ebccec0fSMark Brown case WM8350_IRQ_SYS_WDOG_TO: 903ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 904ebccec0fSMark Brown WM8350_IM_SYS_WDOG_TO_EINT); 905ebccec0fSMark Brown case WM8350_IRQ_UV_LDO4: 906ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 907ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 908ebccec0fSMark Brown WM8350_IM_UV_LDO4_EINT); 909ebccec0fSMark Brown case WM8350_IRQ_UV_LDO3: 910ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 911ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 912ebccec0fSMark Brown WM8350_IM_UV_LDO3_EINT); 913ebccec0fSMark Brown case WM8350_IRQ_UV_LDO2: 914ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 915ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 916ebccec0fSMark Brown WM8350_IM_UV_LDO2_EINT); 917ebccec0fSMark Brown case WM8350_IRQ_UV_LDO1: 918ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 919ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 920ebccec0fSMark Brown WM8350_IM_UV_LDO1_EINT); 921ebccec0fSMark Brown case WM8350_IRQ_UV_DC6: 922ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 923ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 924ebccec0fSMark Brown WM8350_IM_UV_DC6_EINT); 925ebccec0fSMark Brown case WM8350_IRQ_UV_DC5: 926ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 927ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 928ebccec0fSMark Brown WM8350_IM_UV_DC5_EINT); 929ebccec0fSMark Brown case WM8350_IRQ_UV_DC4: 930ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 931ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 932ebccec0fSMark Brown WM8350_IM_UV_DC4_EINT); 933ebccec0fSMark Brown case WM8350_IRQ_UV_DC3: 934ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 935ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 936ebccec0fSMark Brown WM8350_IM_UV_DC3_EINT); 937ebccec0fSMark Brown case WM8350_IRQ_UV_DC2: 938ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 939ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 940ebccec0fSMark Brown WM8350_IM_UV_DC2_EINT); 941ebccec0fSMark Brown case WM8350_IRQ_UV_DC1: 942ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 943ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 944ebccec0fSMark Brown WM8350_IM_UV_DC1_EINT); 945ebccec0fSMark Brown case WM8350_IRQ_OC_LS: 946ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 947ebccec0fSMark Brown WM8350_OVER_CURRENT_INT_STATUS_MASK, 948ebccec0fSMark Brown WM8350_IM_OC_LS_EINT); 949ebccec0fSMark Brown case WM8350_IRQ_EXT_USB_FB: 950ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 951ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 952ebccec0fSMark Brown WM8350_IM_EXT_USB_FB_EINT); 953ebccec0fSMark Brown case WM8350_IRQ_EXT_WALL_FB: 954ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 955ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 956ebccec0fSMark Brown WM8350_IM_EXT_WALL_FB_EINT); 957ebccec0fSMark Brown case WM8350_IRQ_EXT_BAT_FB: 958ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 959ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 960ebccec0fSMark Brown WM8350_IM_EXT_BAT_FB_EINT); 961ebccec0fSMark Brown case WM8350_IRQ_CODEC_JCK_DET_L: 962ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 963ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 964ebccec0fSMark Brown WM8350_IM_CODEC_JCK_DET_L_EINT); 965ebccec0fSMark Brown case WM8350_IRQ_CODEC_JCK_DET_R: 966ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 967ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 968ebccec0fSMark Brown WM8350_IM_CODEC_JCK_DET_R_EINT); 969ebccec0fSMark Brown case WM8350_IRQ_CODEC_MICSCD: 970ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 971ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 972ebccec0fSMark Brown WM8350_IM_CODEC_MICSCD_EINT); 973ebccec0fSMark Brown case WM8350_IRQ_CODEC_MICD: 974ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 975ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 976ebccec0fSMark Brown WM8350_IM_CODEC_MICD_EINT); 977ebccec0fSMark Brown case WM8350_IRQ_WKUP_OFF_STATE: 978ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 979ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 980ebccec0fSMark Brown WM8350_IM_WKUP_OFF_STATE_EINT); 981ebccec0fSMark Brown case WM8350_IRQ_WKUP_HIB_STATE: 982ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 983ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 984ebccec0fSMark Brown WM8350_IM_WKUP_HIB_STATE_EINT); 985ebccec0fSMark Brown case WM8350_IRQ_WKUP_CONV_FAULT: 986ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 987ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 988ebccec0fSMark Brown WM8350_IM_WKUP_CONV_FAULT_EINT); 989ebccec0fSMark Brown case WM8350_IRQ_WKUP_WDOG_RST: 990ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 991ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 992ebccec0fSMark Brown WM8350_IM_WKUP_OFF_STATE_EINT); 993ebccec0fSMark Brown case WM8350_IRQ_WKUP_GP_PWR_ON: 994ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 995ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 996ebccec0fSMark Brown WM8350_IM_WKUP_GP_PWR_ON_EINT); 997ebccec0fSMark Brown case WM8350_IRQ_WKUP_ONKEY: 998ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 999ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 1000ebccec0fSMark Brown WM8350_IM_WKUP_ONKEY_EINT); 1001ebccec0fSMark Brown case WM8350_IRQ_WKUP_GP_WAKEUP: 1002ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1003ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 1004ebccec0fSMark Brown WM8350_IM_WKUP_GP_WAKEUP_EINT); 1005ebccec0fSMark Brown case WM8350_IRQ_GPIO(0): 1006ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1007ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1008ebccec0fSMark Brown WM8350_IM_GP0_EINT); 1009ebccec0fSMark Brown case WM8350_IRQ_GPIO(1): 1010ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1011ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1012ebccec0fSMark Brown WM8350_IM_GP1_EINT); 1013ebccec0fSMark Brown case WM8350_IRQ_GPIO(2): 1014ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1015ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1016ebccec0fSMark Brown WM8350_IM_GP2_EINT); 1017ebccec0fSMark Brown case WM8350_IRQ_GPIO(3): 1018ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1019ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1020ebccec0fSMark Brown WM8350_IM_GP3_EINT); 1021ebccec0fSMark Brown case WM8350_IRQ_GPIO(4): 1022ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1023ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1024ebccec0fSMark Brown WM8350_IM_GP4_EINT); 1025ebccec0fSMark Brown case WM8350_IRQ_GPIO(5): 1026ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1027ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1028ebccec0fSMark Brown WM8350_IM_GP5_EINT); 1029ebccec0fSMark Brown case WM8350_IRQ_GPIO(6): 1030ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1031ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1032ebccec0fSMark Brown WM8350_IM_GP6_EINT); 1033ebccec0fSMark Brown case WM8350_IRQ_GPIO(7): 1034ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1035ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1036ebccec0fSMark Brown WM8350_IM_GP7_EINT); 1037ebccec0fSMark Brown case WM8350_IRQ_GPIO(8): 1038ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1039ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1040ebccec0fSMark Brown WM8350_IM_GP8_EINT); 1041ebccec0fSMark Brown case WM8350_IRQ_GPIO(9): 1042ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1043ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1044ebccec0fSMark Brown WM8350_IM_GP9_EINT); 1045ebccec0fSMark Brown case WM8350_IRQ_GPIO(10): 1046ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1047ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1048ebccec0fSMark Brown WM8350_IM_GP10_EINT); 1049ebccec0fSMark Brown case WM8350_IRQ_GPIO(11): 1050ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1051ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1052ebccec0fSMark Brown WM8350_IM_GP11_EINT); 1053ebccec0fSMark Brown case WM8350_IRQ_GPIO(12): 1054ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1055ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1056ebccec0fSMark Brown WM8350_IM_GP12_EINT); 1057ebccec0fSMark Brown default: 1058ebccec0fSMark Brown dev_warn(wm8350->dev, "Attempting to unmask unknown IRQ %d\n", 1059ebccec0fSMark Brown irq); 1060ebccec0fSMark Brown return -EINVAL; 1061ebccec0fSMark Brown } 1062ebccec0fSMark Brown return 0; 1063ebccec0fSMark Brown } 1064ebccec0fSMark Brown EXPORT_SYMBOL_GPL(wm8350_unmask_irq); 1065ebccec0fSMark Brown 106689b4012bSMark Brown /* 106789b4012bSMark Brown * Cache is always host endian. 106889b4012bSMark Brown */ 106989b4012bSMark Brown static int wm8350_create_cache(struct wm8350 *wm8350, int mode) 107089b4012bSMark Brown { 107189b4012bSMark Brown int i, ret = 0; 107289b4012bSMark Brown u16 value; 107389b4012bSMark Brown const u16 *reg_map; 107489b4012bSMark Brown 107589b4012bSMark Brown switch (mode) { 107689b4012bSMark Brown #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0 107789b4012bSMark Brown case 0: 107889b4012bSMark Brown reg_map = wm8350_mode0_defaults; 107989b4012bSMark Brown break; 108089b4012bSMark Brown #endif 108189b4012bSMark Brown #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1 108289b4012bSMark Brown case 1: 108389b4012bSMark Brown reg_map = wm8350_mode1_defaults; 108489b4012bSMark Brown break; 108589b4012bSMark Brown #endif 108689b4012bSMark Brown #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2 108789b4012bSMark Brown case 2: 108889b4012bSMark Brown reg_map = wm8350_mode2_defaults; 108989b4012bSMark Brown break; 109089b4012bSMark Brown #endif 109189b4012bSMark Brown #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3 109289b4012bSMark Brown case 3: 109389b4012bSMark Brown reg_map = wm8350_mode3_defaults; 109489b4012bSMark Brown break; 109589b4012bSMark Brown #endif 109689b4012bSMark Brown default: 109789b4012bSMark Brown dev_err(wm8350->dev, "Configuration mode %d not supported\n", 109889b4012bSMark Brown mode); 109989b4012bSMark Brown return -EINVAL; 110089b4012bSMark Brown } 110189b4012bSMark Brown 110289b4012bSMark Brown wm8350->reg_cache = 110389b4012bSMark Brown kzalloc(sizeof(u16) * (WM8350_MAX_REGISTER + 1), GFP_KERNEL); 110489b4012bSMark Brown if (wm8350->reg_cache == NULL) 110589b4012bSMark Brown return -ENOMEM; 110689b4012bSMark Brown 110789b4012bSMark Brown /* Read the initial cache state back from the device - this is 110889b4012bSMark Brown * a PMIC so the device many not be in a virgin state and we 110989b4012bSMark Brown * can't rely on the silicon values. 111089b4012bSMark Brown */ 111189b4012bSMark Brown for (i = 0; i < WM8350_MAX_REGISTER; i++) { 111289b4012bSMark Brown /* audio register range */ 111389b4012bSMark Brown if (wm8350_reg_io_map[i].readable && 111489b4012bSMark Brown (i < WM8350_CLOCK_CONTROL_1 || i > WM8350_AIF_TEST)) { 111589b4012bSMark Brown ret = wm8350->read_dev(wm8350, i, 2, (char *)&value); 111689b4012bSMark Brown if (ret < 0) { 111789b4012bSMark Brown dev_err(wm8350->dev, 111889b4012bSMark Brown "failed to read initial cache value\n"); 111989b4012bSMark Brown goto out; 112089b4012bSMark Brown } 112189b4012bSMark Brown value = be16_to_cpu(value); 112289b4012bSMark Brown value &= wm8350_reg_io_map[i].readable; 112389b4012bSMark Brown wm8350->reg_cache[i] = value; 112489b4012bSMark Brown } else 112589b4012bSMark Brown wm8350->reg_cache[i] = reg_map[i]; 112689b4012bSMark Brown } 112789b4012bSMark Brown 112889b4012bSMark Brown out: 112989b4012bSMark Brown return ret; 113089b4012bSMark Brown } 113189b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_create_cache); 113289b4012bSMark Brown 1133ebccec0fSMark Brown int wm8350_device_init(struct wm8350 *wm8350, int irq, 1134bcdd4efcSMark Brown struct wm8350_platform_data *pdata) 113589b4012bSMark Brown { 113689b4012bSMark Brown int ret = -EINVAL; 113789b4012bSMark Brown u16 id1, id2, mask, mode; 1138ebccec0fSMark Brown int i; 113989b4012bSMark Brown 114089b4012bSMark Brown /* get WM8350 revision and config mode */ 114189b4012bSMark Brown wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1); 114289b4012bSMark Brown wm8350->read_dev(wm8350, WM8350_ID, sizeof(id2), &id2); 114389b4012bSMark Brown 114489b4012bSMark Brown id1 = be16_to_cpu(id1); 114589b4012bSMark Brown id2 = be16_to_cpu(id2); 114689b4012bSMark Brown 1147ebccec0fSMark Brown if (id1 == 0x6143) { 114889b4012bSMark Brown switch ((id2 & WM8350_CHIP_REV_MASK) >> 12) { 114989b4012bSMark Brown case WM8350_REV_E: 115089b4012bSMark Brown dev_info(wm8350->dev, "Found Rev E device\n"); 115189b4012bSMark Brown wm8350->rev = WM8350_REV_E; 115289b4012bSMark Brown break; 115389b4012bSMark Brown case WM8350_REV_F: 115489b4012bSMark Brown dev_info(wm8350->dev, "Found Rev F device\n"); 115589b4012bSMark Brown wm8350->rev = WM8350_REV_F; 115689b4012bSMark Brown break; 115789b4012bSMark Brown case WM8350_REV_G: 115889b4012bSMark Brown dev_info(wm8350->dev, "Found Rev G device\n"); 115989b4012bSMark Brown wm8350->rev = WM8350_REV_G; 116089b4012bSMark Brown break; 116189b4012bSMark Brown default: 116289b4012bSMark Brown /* For safety we refuse to run on unknown hardware */ 116389b4012bSMark Brown dev_info(wm8350->dev, "Found unknown rev\n"); 116489b4012bSMark Brown ret = -ENODEV; 116589b4012bSMark Brown goto err; 116689b4012bSMark Brown } 116789b4012bSMark Brown } else { 116889b4012bSMark Brown dev_info(wm8350->dev, "Device with ID %x is not a WM8350\n", 116989b4012bSMark Brown id1); 117089b4012bSMark Brown ret = -ENODEV; 117189b4012bSMark Brown goto err; 117289b4012bSMark Brown } 117389b4012bSMark Brown 117489b4012bSMark Brown mode = id2 & WM8350_CONF_STS_MASK >> 10; 117589b4012bSMark Brown mask = id2 & WM8350_CUST_ID_MASK; 117689b4012bSMark Brown dev_info(wm8350->dev, "Config mode %d, ROM mask %d\n", mode, mask); 117789b4012bSMark Brown 117889b4012bSMark Brown ret = wm8350_create_cache(wm8350, mode); 117989b4012bSMark Brown if (ret < 0) { 118089b4012bSMark Brown printk(KERN_ERR "wm8350: failed to create register cache\n"); 118189b4012bSMark Brown return ret; 118289b4012bSMark Brown } 118389b4012bSMark Brown 1184bcdd4efcSMark Brown if (pdata->init) { 1185bcdd4efcSMark Brown ret = pdata->init(wm8350); 1186bcdd4efcSMark Brown if (ret != 0) { 1187bcdd4efcSMark Brown dev_err(wm8350->dev, "Platform init() failed: %d\n", 1188bcdd4efcSMark Brown ret); 1189bcdd4efcSMark Brown goto err; 1190bcdd4efcSMark Brown } 1191bcdd4efcSMark Brown } 1192bcdd4efcSMark Brown 1193ebccec0fSMark Brown mutex_init(&wm8350->irq_mutex); 1194ebccec0fSMark Brown INIT_WORK(&wm8350->irq_work, wm8350_irq_worker); 1195ebccec0fSMark Brown if (irq != NO_IRQ) { 1196ebccec0fSMark Brown ret = request_irq(irq, wm8350_irq, 0, 1197ebccec0fSMark Brown "wm8350", wm8350); 1198ebccec0fSMark Brown if (ret != 0) { 1199ebccec0fSMark Brown dev_err(wm8350->dev, "Failed to request IRQ: %d\n", 1200ebccec0fSMark Brown ret); 1201ebccec0fSMark Brown goto err; 1202ebccec0fSMark Brown } 1203ebccec0fSMark Brown } else { 1204ebccec0fSMark Brown dev_err(wm8350->dev, "No IRQ configured\n"); 1205ebccec0fSMark Brown goto err; 1206ebccec0fSMark Brown } 1207ebccec0fSMark Brown wm8350->chip_irq = irq; 1208ebccec0fSMark Brown 1209ebccec0fSMark Brown wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0x0); 1210ebccec0fSMark Brown 121189b4012bSMark Brown return 0; 121289b4012bSMark Brown 121389b4012bSMark Brown err: 121489b4012bSMark Brown kfree(wm8350->reg_cache); 121589b4012bSMark Brown return ret; 121689b4012bSMark Brown } 121789b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_device_init); 121889b4012bSMark Brown 121989b4012bSMark Brown void wm8350_device_exit(struct wm8350 *wm8350) 122089b4012bSMark Brown { 1221da09155aSMark Brown int i; 1222da09155aSMark Brown 1223da09155aSMark Brown for (i = 0; i < ARRAY_SIZE(wm8350->pmic.pdev); i++) 1224da09155aSMark Brown if (wm8350->pmic.pdev[i] != NULL) 1225da09155aSMark Brown platform_device_unregister(wm8350->pmic.pdev[i]); 1226da09155aSMark Brown 1227ebccec0fSMark Brown free_irq(wm8350->chip_irq, wm8350); 1228ebccec0fSMark Brown flush_work(&wm8350->irq_work); 122989b4012bSMark Brown kfree(wm8350->reg_cache); 123089b4012bSMark Brown } 123189b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_device_exit); 123289b4012bSMark Brown 1233ebccec0fSMark Brown MODULE_DESCRIPTION("WM8350 AudioPlus PMIC core driver"); 123489b4012bSMark Brown MODULE_LICENSE("GPL"); 1235