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 6789b4012bSMark Brown /* Perform a physical read from the device. 6889b4012bSMark Brown */ 6989b4012bSMark Brown static int wm8350_phys_read(struct wm8350 *wm8350, u8 reg, int num_regs, 7089b4012bSMark Brown u16 *dest) 7189b4012bSMark Brown { 7289b4012bSMark Brown int i, ret; 7389b4012bSMark Brown int bytes = num_regs * 2; 7489b4012bSMark Brown 7589b4012bSMark Brown dev_dbg(wm8350->dev, "volatile read\n"); 7689b4012bSMark Brown ret = wm8350->read_dev(wm8350, reg, bytes, (char *)dest); 7789b4012bSMark Brown 7889b4012bSMark Brown for (i = reg; i < reg + num_regs; i++) { 7989b4012bSMark Brown /* Cache is CPU endian */ 8089b4012bSMark Brown dest[i - reg] = be16_to_cpu(dest[i - reg]); 8189b4012bSMark Brown 8289b4012bSMark Brown /* Satisfy non-volatile bits from cache */ 8389b4012bSMark Brown dest[i - reg] &= wm8350_reg_io_map[i].vol; 8489b4012bSMark Brown dest[i - reg] |= wm8350->reg_cache[i]; 8589b4012bSMark Brown 8689b4012bSMark Brown /* Mask out non-readable bits */ 8789b4012bSMark Brown dest[i - reg] &= wm8350_reg_io_map[i].readable; 8889b4012bSMark Brown } 8989b4012bSMark Brown 9089b4012bSMark Brown dump(num_regs, dest); 9189b4012bSMark Brown 9289b4012bSMark Brown return ret; 9389b4012bSMark Brown } 9489b4012bSMark Brown 9589b4012bSMark Brown static int wm8350_read(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *dest) 9689b4012bSMark Brown { 9789b4012bSMark Brown int i; 9889b4012bSMark Brown int end = reg + num_regs; 9989b4012bSMark Brown int ret = 0; 10089b4012bSMark Brown int bytes = num_regs * 2; 10189b4012bSMark Brown 10289b4012bSMark Brown if (wm8350->read_dev == NULL) 10389b4012bSMark Brown return -ENODEV; 10489b4012bSMark Brown 10589b4012bSMark Brown if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) { 10689b4012bSMark Brown dev_err(wm8350->dev, "invalid reg %x\n", 10789b4012bSMark Brown reg + num_regs - 1); 10889b4012bSMark Brown return -EINVAL; 10989b4012bSMark Brown } 11089b4012bSMark Brown 11189b4012bSMark Brown dev_dbg(wm8350->dev, 11289b4012bSMark Brown "%s R%d(0x%2.2x) %d regs\n", __func__, reg, reg, num_regs); 11389b4012bSMark Brown 11489b4012bSMark Brown #if WM8350_BUS_DEBUG 11589b4012bSMark Brown /* we can _safely_ read any register, but warn if read not supported */ 11689b4012bSMark Brown for (i = reg; i < end; i++) { 11789b4012bSMark Brown if (!wm8350_reg_io_map[i].readable) 11889b4012bSMark Brown dev_warn(wm8350->dev, 11989b4012bSMark Brown "reg R%d is not readable\n", i); 12089b4012bSMark Brown } 12189b4012bSMark Brown #endif 12289b4012bSMark Brown 12389b4012bSMark Brown /* if any volatile registers are required, then read back all */ 12489b4012bSMark Brown for (i = reg; i < end; i++) 12589b4012bSMark Brown if (wm8350_reg_io_map[i].vol) 12689b4012bSMark Brown return wm8350_phys_read(wm8350, reg, num_regs, dest); 12789b4012bSMark Brown 12889b4012bSMark Brown /* no volatiles, then cache is good */ 12989b4012bSMark Brown dev_dbg(wm8350->dev, "cache read\n"); 13089b4012bSMark Brown memcpy(dest, &wm8350->reg_cache[reg], bytes); 13189b4012bSMark Brown dump(num_regs, dest); 13289b4012bSMark Brown return ret; 13389b4012bSMark Brown } 13489b4012bSMark Brown 13589b4012bSMark Brown static inline int is_reg_locked(struct wm8350 *wm8350, u8 reg) 13689b4012bSMark Brown { 13789b4012bSMark Brown if (reg == WM8350_SECURITY || 13889b4012bSMark Brown wm8350->reg_cache[WM8350_SECURITY] == WM8350_UNLOCK_KEY) 13989b4012bSMark Brown return 0; 14089b4012bSMark Brown 14189b4012bSMark Brown if ((reg == WM8350_GPIO_CONFIGURATION_I_O) || 14289b4012bSMark Brown (reg >= WM8350_GPIO_FUNCTION_SELECT_1 && 14389b4012bSMark Brown reg <= WM8350_GPIO_FUNCTION_SELECT_4) || 14489b4012bSMark Brown (reg >= WM8350_BATTERY_CHARGER_CONTROL_1 && 14589b4012bSMark Brown reg <= WM8350_BATTERY_CHARGER_CONTROL_3)) 14689b4012bSMark Brown return 1; 14789b4012bSMark Brown return 0; 14889b4012bSMark Brown } 14989b4012bSMark Brown 15089b4012bSMark Brown static int wm8350_write(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *src) 15189b4012bSMark Brown { 15289b4012bSMark Brown int i; 15389b4012bSMark Brown int end = reg + num_regs; 15489b4012bSMark Brown int bytes = num_regs * 2; 15589b4012bSMark Brown 15689b4012bSMark Brown if (wm8350->write_dev == NULL) 15789b4012bSMark Brown return -ENODEV; 15889b4012bSMark Brown 15989b4012bSMark Brown if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) { 16089b4012bSMark Brown dev_err(wm8350->dev, "invalid reg %x\n", 16189b4012bSMark Brown reg + num_regs - 1); 16289b4012bSMark Brown return -EINVAL; 16389b4012bSMark Brown } 16489b4012bSMark Brown 16589b4012bSMark Brown /* it's generally not a good idea to write to RO or locked registers */ 16689b4012bSMark Brown for (i = reg; i < end; i++) { 16789b4012bSMark Brown if (!wm8350_reg_io_map[i].writable) { 16889b4012bSMark Brown dev_err(wm8350->dev, 16989b4012bSMark Brown "attempted write to read only reg R%d\n", i); 17089b4012bSMark Brown return -EINVAL; 17189b4012bSMark Brown } 17289b4012bSMark Brown 17389b4012bSMark Brown if (is_reg_locked(wm8350, i)) { 17489b4012bSMark Brown dev_err(wm8350->dev, 17589b4012bSMark Brown "attempted write to locked reg R%d\n", i); 17689b4012bSMark Brown return -EINVAL; 17789b4012bSMark Brown } 17889b4012bSMark Brown 17989b4012bSMark Brown src[i - reg] &= wm8350_reg_io_map[i].writable; 18089b4012bSMark Brown 18189b4012bSMark Brown wm8350->reg_cache[i] = 18289b4012bSMark Brown (wm8350->reg_cache[i] & ~wm8350_reg_io_map[i].writable) 18389b4012bSMark Brown | src[i - reg]; 18489b4012bSMark Brown 185e76f7558SMark Brown /* Don't store volatile bits */ 186e76f7558SMark Brown wm8350->reg_cache[i] &= ~wm8350_reg_io_map[i].vol; 187e76f7558SMark Brown 18889b4012bSMark Brown src[i - reg] = cpu_to_be16(src[i - reg]); 18989b4012bSMark Brown } 19089b4012bSMark Brown 19189b4012bSMark Brown /* Actually write it out */ 19289b4012bSMark Brown return wm8350->write_dev(wm8350, reg, bytes, (char *)src); 19389b4012bSMark Brown } 19489b4012bSMark Brown 19589b4012bSMark Brown /* 19689b4012bSMark Brown * Safe read, modify, write methods 19789b4012bSMark Brown */ 19889b4012bSMark Brown int wm8350_clear_bits(struct wm8350 *wm8350, u16 reg, u16 mask) 19989b4012bSMark Brown { 20089b4012bSMark Brown u16 data; 20189b4012bSMark Brown int err; 20289b4012bSMark Brown 20389b4012bSMark Brown mutex_lock(&io_mutex); 20489b4012bSMark Brown err = wm8350_read(wm8350, reg, 1, &data); 20589b4012bSMark Brown if (err) { 20689b4012bSMark Brown dev_err(wm8350->dev, "read from reg R%d failed\n", reg); 20789b4012bSMark Brown goto out; 20889b4012bSMark Brown } 20989b4012bSMark Brown 21089b4012bSMark Brown data &= ~mask; 21189b4012bSMark Brown err = wm8350_write(wm8350, reg, 1, &data); 21289b4012bSMark Brown if (err) 21389b4012bSMark Brown dev_err(wm8350->dev, "write to reg R%d failed\n", reg); 21489b4012bSMark Brown out: 21589b4012bSMark Brown mutex_unlock(&io_mutex); 21689b4012bSMark Brown return err; 21789b4012bSMark Brown } 21889b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_clear_bits); 21989b4012bSMark Brown 22089b4012bSMark Brown int wm8350_set_bits(struct wm8350 *wm8350, u16 reg, u16 mask) 22189b4012bSMark Brown { 22289b4012bSMark Brown u16 data; 22389b4012bSMark Brown int err; 22489b4012bSMark Brown 22589b4012bSMark Brown mutex_lock(&io_mutex); 22689b4012bSMark Brown err = wm8350_read(wm8350, reg, 1, &data); 22789b4012bSMark Brown if (err) { 22889b4012bSMark Brown dev_err(wm8350->dev, "read from reg R%d failed\n", reg); 22989b4012bSMark Brown goto out; 23089b4012bSMark Brown } 23189b4012bSMark Brown 23289b4012bSMark Brown data |= mask; 23389b4012bSMark Brown err = wm8350_write(wm8350, reg, 1, &data); 23489b4012bSMark Brown if (err) 23589b4012bSMark Brown dev_err(wm8350->dev, "write to reg R%d failed\n", reg); 23689b4012bSMark Brown out: 23789b4012bSMark Brown mutex_unlock(&io_mutex); 23889b4012bSMark Brown return err; 23989b4012bSMark Brown } 24089b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_set_bits); 24189b4012bSMark Brown 24289b4012bSMark Brown u16 wm8350_reg_read(struct wm8350 *wm8350, int reg) 24389b4012bSMark Brown { 24489b4012bSMark Brown u16 data; 24589b4012bSMark Brown int err; 24689b4012bSMark Brown 24789b4012bSMark Brown mutex_lock(&io_mutex); 24889b4012bSMark Brown err = wm8350_read(wm8350, reg, 1, &data); 24989b4012bSMark Brown if (err) 25089b4012bSMark Brown dev_err(wm8350->dev, "read from reg R%d failed\n", reg); 25189b4012bSMark Brown 25289b4012bSMark Brown mutex_unlock(&io_mutex); 25389b4012bSMark Brown return data; 25489b4012bSMark Brown } 25589b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_reg_read); 25689b4012bSMark Brown 25789b4012bSMark Brown int wm8350_reg_write(struct wm8350 *wm8350, int reg, u16 val) 25889b4012bSMark Brown { 25989b4012bSMark Brown int ret; 26089b4012bSMark Brown u16 data = val; 26189b4012bSMark Brown 26289b4012bSMark Brown mutex_lock(&io_mutex); 26389b4012bSMark Brown ret = wm8350_write(wm8350, reg, 1, &data); 26489b4012bSMark Brown if (ret) 26589b4012bSMark Brown dev_err(wm8350->dev, "write to reg R%d failed\n", reg); 26689b4012bSMark Brown mutex_unlock(&io_mutex); 26789b4012bSMark Brown return ret; 26889b4012bSMark Brown } 26989b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_reg_write); 27089b4012bSMark Brown 27189b4012bSMark Brown int wm8350_block_read(struct wm8350 *wm8350, int start_reg, int regs, 27289b4012bSMark Brown u16 *dest) 27389b4012bSMark Brown { 27489b4012bSMark Brown int err = 0; 27589b4012bSMark Brown 27689b4012bSMark Brown mutex_lock(&io_mutex); 27789b4012bSMark Brown err = wm8350_read(wm8350, start_reg, regs, dest); 27889b4012bSMark Brown if (err) 27989b4012bSMark Brown dev_err(wm8350->dev, "block read starting from R%d failed\n", 28089b4012bSMark Brown start_reg); 28189b4012bSMark Brown mutex_unlock(&io_mutex); 28289b4012bSMark Brown return err; 28389b4012bSMark Brown } 28489b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_block_read); 28589b4012bSMark Brown 28689b4012bSMark Brown int wm8350_block_write(struct wm8350 *wm8350, int start_reg, int regs, 28789b4012bSMark Brown u16 *src) 28889b4012bSMark Brown { 28989b4012bSMark Brown int ret = 0; 29089b4012bSMark Brown 29189b4012bSMark Brown mutex_lock(&io_mutex); 29289b4012bSMark Brown ret = wm8350_write(wm8350, start_reg, regs, src); 29389b4012bSMark Brown if (ret) 29489b4012bSMark Brown dev_err(wm8350->dev, "block write starting at R%d failed\n", 29589b4012bSMark Brown start_reg); 29689b4012bSMark Brown mutex_unlock(&io_mutex); 29789b4012bSMark Brown return ret; 29889b4012bSMark Brown } 29989b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_block_write); 30089b4012bSMark Brown 301858e6744SMark Brown /** 302858e6744SMark Brown * wm8350_reg_lock() 303858e6744SMark Brown * 304858e6744SMark Brown * The WM8350 has a hardware lock which can be used to prevent writes to 305858e6744SMark Brown * some registers (generally those which can cause particularly serious 306858e6744SMark Brown * problems if misused). This function enables that lock. 307858e6744SMark Brown */ 30889b4012bSMark Brown int wm8350_reg_lock(struct wm8350 *wm8350) 30989b4012bSMark Brown { 31089b4012bSMark Brown u16 key = WM8350_LOCK_KEY; 31189b4012bSMark Brown int ret; 31289b4012bSMark Brown 31389b4012bSMark Brown ldbg(__func__); 31489b4012bSMark Brown mutex_lock(&io_mutex); 31589b4012bSMark Brown ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key); 31689b4012bSMark Brown if (ret) 31789b4012bSMark Brown dev_err(wm8350->dev, "lock failed\n"); 31889b4012bSMark Brown mutex_unlock(&io_mutex); 31989b4012bSMark Brown return ret; 32089b4012bSMark Brown } 32189b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_reg_lock); 32289b4012bSMark Brown 323858e6744SMark Brown /** 324858e6744SMark Brown * wm8350_reg_unlock() 325858e6744SMark Brown * 326858e6744SMark Brown * The WM8350 has a hardware lock which can be used to prevent writes to 327858e6744SMark Brown * some registers (generally those which can cause particularly serious 328858e6744SMark Brown * problems if misused). This function disables that lock so updates 329858e6744SMark Brown * can be performed. For maximum safety this should be done only when 330858e6744SMark Brown * required. 331858e6744SMark Brown */ 33289b4012bSMark Brown int wm8350_reg_unlock(struct wm8350 *wm8350) 33389b4012bSMark Brown { 33489b4012bSMark Brown u16 key = WM8350_UNLOCK_KEY; 33589b4012bSMark Brown int ret; 33689b4012bSMark Brown 33789b4012bSMark Brown ldbg(__func__); 33889b4012bSMark Brown mutex_lock(&io_mutex); 33989b4012bSMark Brown ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key); 34089b4012bSMark Brown if (ret) 34189b4012bSMark Brown dev_err(wm8350->dev, "unlock failed\n"); 34289b4012bSMark Brown mutex_unlock(&io_mutex); 34389b4012bSMark Brown return ret; 34489b4012bSMark Brown } 34589b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_reg_unlock); 34689b4012bSMark Brown 347ebccec0fSMark Brown static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq) 348ebccec0fSMark Brown { 349ebccec0fSMark Brown mutex_lock(&wm8350->irq_mutex); 350ebccec0fSMark Brown 351ebccec0fSMark Brown if (wm8350->irq[irq].handler) 352ebccec0fSMark Brown wm8350->irq[irq].handler(wm8350, irq, wm8350->irq[irq].data); 353ebccec0fSMark Brown else { 354ebccec0fSMark Brown dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n", 355ebccec0fSMark Brown irq); 356ebccec0fSMark Brown wm8350_mask_irq(wm8350, irq); 357ebccec0fSMark Brown } 358ebccec0fSMark Brown 359ebccec0fSMark Brown mutex_unlock(&wm8350->irq_mutex); 360ebccec0fSMark Brown } 361ebccec0fSMark Brown 362ebccec0fSMark Brown /* 363ebccec0fSMark Brown * wm8350_irq_worker actually handles the interrupts. Since all 364ebccec0fSMark Brown * interrupts are clear on read the IRQ line will be reasserted and 365ebccec0fSMark Brown * the physical IRQ will be handled again if another interrupt is 366ebccec0fSMark Brown * asserted while we run - in the normal course of events this is a 367ebccec0fSMark Brown * rare occurrence so we save I2C/SPI reads. 368ebccec0fSMark Brown */ 369ebccec0fSMark Brown static void wm8350_irq_worker(struct work_struct *work) 370ebccec0fSMark Brown { 371ebccec0fSMark Brown struct wm8350 *wm8350 = container_of(work, struct wm8350, irq_work); 372ebccec0fSMark Brown u16 level_one, status1, status2, comp; 373ebccec0fSMark Brown 374ebccec0fSMark Brown /* TODO: Use block reads to improve performance? */ 375ebccec0fSMark Brown level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS) 376ebccec0fSMark Brown & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK); 377ebccec0fSMark Brown status1 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_1) 378ebccec0fSMark Brown & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_1_MASK); 379ebccec0fSMark Brown status2 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_2) 380ebccec0fSMark Brown & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_2_MASK); 381ebccec0fSMark Brown comp = wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS) 382ebccec0fSMark Brown & ~wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK); 383ebccec0fSMark Brown 384ebccec0fSMark Brown /* over current */ 385ebccec0fSMark Brown if (level_one & WM8350_OC_INT) { 386ebccec0fSMark Brown u16 oc; 387ebccec0fSMark Brown 388ebccec0fSMark Brown oc = wm8350_reg_read(wm8350, WM8350_OVER_CURRENT_INT_STATUS); 389ebccec0fSMark Brown oc &= ~wm8350_reg_read(wm8350, 390ebccec0fSMark Brown WM8350_OVER_CURRENT_INT_STATUS_MASK); 391ebccec0fSMark Brown 392ebccec0fSMark Brown if (oc & WM8350_OC_LS_EINT) /* limit switch */ 393ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_OC_LS); 394ebccec0fSMark Brown } 395ebccec0fSMark Brown 396ebccec0fSMark Brown /* under voltage */ 397ebccec0fSMark Brown if (level_one & WM8350_UV_INT) { 398ebccec0fSMark Brown u16 uv; 399ebccec0fSMark Brown 400ebccec0fSMark Brown uv = wm8350_reg_read(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS); 401ebccec0fSMark Brown uv &= ~wm8350_reg_read(wm8350, 402ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK); 403ebccec0fSMark Brown 404ebccec0fSMark Brown if (uv & WM8350_UV_DC1_EINT) 405ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC1); 406ebccec0fSMark Brown if (uv & WM8350_UV_DC2_EINT) 407ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC2); 408ebccec0fSMark Brown if (uv & WM8350_UV_DC3_EINT) 409ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC3); 410ebccec0fSMark Brown if (uv & WM8350_UV_DC4_EINT) 411ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC4); 412ebccec0fSMark Brown if (uv & WM8350_UV_DC5_EINT) 413ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC5); 414ebccec0fSMark Brown if (uv & WM8350_UV_DC6_EINT) 415ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC6); 416ebccec0fSMark Brown if (uv & WM8350_UV_LDO1_EINT) 417ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO1); 418ebccec0fSMark Brown if (uv & WM8350_UV_LDO2_EINT) 419ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO2); 420ebccec0fSMark Brown if (uv & WM8350_UV_LDO3_EINT) 421ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO3); 422ebccec0fSMark Brown if (uv & WM8350_UV_LDO4_EINT) 423ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO4); 424ebccec0fSMark Brown } 425ebccec0fSMark Brown 426ebccec0fSMark Brown /* charger, RTC */ 427ebccec0fSMark Brown if (status1) { 428ebccec0fSMark Brown if (status1 & WM8350_CHG_BAT_HOT_EINT) 429ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 430ebccec0fSMark Brown WM8350_IRQ_CHG_BAT_HOT); 431ebccec0fSMark Brown if (status1 & WM8350_CHG_BAT_COLD_EINT) 432ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 433ebccec0fSMark Brown WM8350_IRQ_CHG_BAT_COLD); 434ebccec0fSMark Brown if (status1 & WM8350_CHG_BAT_FAIL_EINT) 435ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 436ebccec0fSMark Brown WM8350_IRQ_CHG_BAT_FAIL); 437ebccec0fSMark Brown if (status1 & WM8350_CHG_TO_EINT) 438ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_TO); 439ebccec0fSMark Brown if (status1 & WM8350_CHG_END_EINT) 440ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_END); 441ebccec0fSMark Brown if (status1 & WM8350_CHG_START_EINT) 442ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_START); 443ebccec0fSMark Brown if (status1 & WM8350_CHG_FAST_RDY_EINT) 444ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 445ebccec0fSMark Brown WM8350_IRQ_CHG_FAST_RDY); 446ebccec0fSMark Brown if (status1 & WM8350_CHG_VBATT_LT_3P9_EINT) 447ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 448ebccec0fSMark Brown WM8350_IRQ_CHG_VBATT_LT_3P9); 449ebccec0fSMark Brown if (status1 & WM8350_CHG_VBATT_LT_3P1_EINT) 450ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 451ebccec0fSMark Brown WM8350_IRQ_CHG_VBATT_LT_3P1); 452ebccec0fSMark Brown if (status1 & WM8350_CHG_VBATT_LT_2P85_EINT) 453ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 454ebccec0fSMark Brown WM8350_IRQ_CHG_VBATT_LT_2P85); 455ebccec0fSMark Brown if (status1 & WM8350_RTC_ALM_EINT) 456ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_ALM); 457ebccec0fSMark Brown if (status1 & WM8350_RTC_SEC_EINT) 458ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_SEC); 459ebccec0fSMark Brown if (status1 & WM8350_RTC_PER_EINT) 460ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_PER); 461ebccec0fSMark Brown } 462ebccec0fSMark Brown 463ebccec0fSMark Brown /* current sink, system, aux adc */ 464ebccec0fSMark Brown if (status2) { 465ebccec0fSMark Brown if (status2 & WM8350_CS1_EINT) 466ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS1); 467ebccec0fSMark Brown if (status2 & WM8350_CS2_EINT) 468ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS2); 469ebccec0fSMark Brown 470ebccec0fSMark Brown if (status2 & WM8350_SYS_HYST_COMP_FAIL_EINT) 471ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 472ebccec0fSMark Brown WM8350_IRQ_SYS_HYST_COMP_FAIL); 473ebccec0fSMark Brown if (status2 & WM8350_SYS_CHIP_GT115_EINT) 474ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 475ebccec0fSMark Brown WM8350_IRQ_SYS_CHIP_GT115); 476ebccec0fSMark Brown if (status2 & WM8350_SYS_CHIP_GT140_EINT) 477ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 478ebccec0fSMark Brown WM8350_IRQ_SYS_CHIP_GT140); 479ebccec0fSMark Brown if (status2 & WM8350_SYS_WDOG_TO_EINT) 480ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 481ebccec0fSMark Brown WM8350_IRQ_SYS_WDOG_TO); 482ebccec0fSMark Brown 483ebccec0fSMark Brown if (status2 & WM8350_AUXADC_DATARDY_EINT) 484ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 485ebccec0fSMark Brown WM8350_IRQ_AUXADC_DATARDY); 486ebccec0fSMark Brown if (status2 & WM8350_AUXADC_DCOMP4_EINT) 487ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 488ebccec0fSMark Brown WM8350_IRQ_AUXADC_DCOMP4); 489ebccec0fSMark Brown if (status2 & WM8350_AUXADC_DCOMP3_EINT) 490ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 491ebccec0fSMark Brown WM8350_IRQ_AUXADC_DCOMP3); 492ebccec0fSMark Brown if (status2 & WM8350_AUXADC_DCOMP2_EINT) 493ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 494ebccec0fSMark Brown WM8350_IRQ_AUXADC_DCOMP2); 495ebccec0fSMark Brown if (status2 & WM8350_AUXADC_DCOMP1_EINT) 496ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 497ebccec0fSMark Brown WM8350_IRQ_AUXADC_DCOMP1); 498ebccec0fSMark Brown 499ebccec0fSMark Brown if (status2 & WM8350_USB_LIMIT_EINT) 500ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_USB_LIMIT); 501ebccec0fSMark Brown } 502ebccec0fSMark Brown 503ebccec0fSMark Brown /* wake, codec, ext */ 504ebccec0fSMark Brown if (comp) { 505ebccec0fSMark Brown if (comp & WM8350_WKUP_OFF_STATE_EINT) 506ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 507ebccec0fSMark Brown WM8350_IRQ_WKUP_OFF_STATE); 508ebccec0fSMark Brown if (comp & WM8350_WKUP_HIB_STATE_EINT) 509ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 510ebccec0fSMark Brown WM8350_IRQ_WKUP_HIB_STATE); 511ebccec0fSMark Brown if (comp & WM8350_WKUP_CONV_FAULT_EINT) 512ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 513ebccec0fSMark Brown WM8350_IRQ_WKUP_CONV_FAULT); 514ebccec0fSMark Brown if (comp & WM8350_WKUP_WDOG_RST_EINT) 515ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 516ebccec0fSMark Brown WM8350_IRQ_WKUP_WDOG_RST); 517ebccec0fSMark Brown if (comp & WM8350_WKUP_GP_PWR_ON_EINT) 518ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 519ebccec0fSMark Brown WM8350_IRQ_WKUP_GP_PWR_ON); 520ebccec0fSMark Brown if (comp & WM8350_WKUP_ONKEY_EINT) 521ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_WKUP_ONKEY); 522ebccec0fSMark Brown if (comp & WM8350_WKUP_GP_WAKEUP_EINT) 523ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 524ebccec0fSMark Brown WM8350_IRQ_WKUP_GP_WAKEUP); 525ebccec0fSMark Brown 526ebccec0fSMark Brown if (comp & WM8350_CODEC_JCK_DET_L_EINT) 527ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 528ebccec0fSMark Brown WM8350_IRQ_CODEC_JCK_DET_L); 529ebccec0fSMark Brown if (comp & WM8350_CODEC_JCK_DET_R_EINT) 530ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 531ebccec0fSMark Brown WM8350_IRQ_CODEC_JCK_DET_R); 532ebccec0fSMark Brown if (comp & WM8350_CODEC_MICSCD_EINT) 533ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 534ebccec0fSMark Brown WM8350_IRQ_CODEC_MICSCD); 535ebccec0fSMark Brown if (comp & WM8350_CODEC_MICD_EINT) 536ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_CODEC_MICD); 537ebccec0fSMark Brown 538ebccec0fSMark Brown if (comp & WM8350_EXT_USB_FB_EINT) 539ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_USB_FB); 540ebccec0fSMark Brown if (comp & WM8350_EXT_WALL_FB_EINT) 541ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 542ebccec0fSMark Brown WM8350_IRQ_EXT_WALL_FB); 543ebccec0fSMark Brown if (comp & WM8350_EXT_BAT_FB_EINT) 544ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_BAT_FB); 545ebccec0fSMark Brown } 546ebccec0fSMark Brown 547ebccec0fSMark Brown if (level_one & WM8350_GP_INT) { 548ebccec0fSMark Brown int i; 549ebccec0fSMark Brown u16 gpio; 550ebccec0fSMark Brown 551ebccec0fSMark Brown gpio = wm8350_reg_read(wm8350, WM8350_GPIO_INT_STATUS); 552ebccec0fSMark Brown gpio &= ~wm8350_reg_read(wm8350, 553ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK); 554ebccec0fSMark Brown 555ebccec0fSMark Brown for (i = 0; i < 12; i++) { 556ebccec0fSMark Brown if (gpio & (1 << i)) 557ebccec0fSMark Brown wm8350_irq_call_handler(wm8350, 558ebccec0fSMark Brown WM8350_IRQ_GPIO(i)); 559ebccec0fSMark Brown } 560ebccec0fSMark Brown } 561ebccec0fSMark Brown 562ebccec0fSMark Brown enable_irq(wm8350->chip_irq); 563ebccec0fSMark Brown } 564ebccec0fSMark Brown 565ebccec0fSMark Brown static irqreturn_t wm8350_irq(int irq, void *data) 566ebccec0fSMark Brown { 567ebccec0fSMark Brown struct wm8350 *wm8350 = data; 568ebccec0fSMark Brown 569ebccec0fSMark Brown disable_irq_nosync(irq); 570ebccec0fSMark Brown schedule_work(&wm8350->irq_work); 571ebccec0fSMark Brown 572ebccec0fSMark Brown return IRQ_HANDLED; 573ebccec0fSMark Brown } 574ebccec0fSMark Brown 575ebccec0fSMark Brown int wm8350_register_irq(struct wm8350 *wm8350, int irq, 576ebccec0fSMark Brown void (*handler) (struct wm8350 *, int, void *), 577ebccec0fSMark Brown void *data) 578ebccec0fSMark Brown { 579ebccec0fSMark Brown if (irq < 0 || irq > WM8350_NUM_IRQ || !handler) 580ebccec0fSMark Brown return -EINVAL; 581ebccec0fSMark Brown 582ebccec0fSMark Brown if (wm8350->irq[irq].handler) 583ebccec0fSMark Brown return -EBUSY; 584ebccec0fSMark Brown 585ebccec0fSMark Brown mutex_lock(&wm8350->irq_mutex); 586ebccec0fSMark Brown wm8350->irq[irq].handler = handler; 587ebccec0fSMark Brown wm8350->irq[irq].data = data; 588ebccec0fSMark Brown mutex_unlock(&wm8350->irq_mutex); 589ebccec0fSMark Brown 590ebccec0fSMark Brown return 0; 591ebccec0fSMark Brown } 592ebccec0fSMark Brown EXPORT_SYMBOL_GPL(wm8350_register_irq); 593ebccec0fSMark Brown 594ebccec0fSMark Brown int wm8350_free_irq(struct wm8350 *wm8350, int irq) 595ebccec0fSMark Brown { 596ebccec0fSMark Brown if (irq < 0 || irq > WM8350_NUM_IRQ) 597ebccec0fSMark Brown return -EINVAL; 598ebccec0fSMark Brown 599ebccec0fSMark Brown mutex_lock(&wm8350->irq_mutex); 600ebccec0fSMark Brown wm8350->irq[irq].handler = NULL; 601ebccec0fSMark Brown mutex_unlock(&wm8350->irq_mutex); 602ebccec0fSMark Brown return 0; 603ebccec0fSMark Brown } 604ebccec0fSMark Brown EXPORT_SYMBOL_GPL(wm8350_free_irq); 605ebccec0fSMark Brown 606ebccec0fSMark Brown int wm8350_mask_irq(struct wm8350 *wm8350, int irq) 607ebccec0fSMark Brown { 608ebccec0fSMark Brown switch (irq) { 609ebccec0fSMark Brown case WM8350_IRQ_CHG_BAT_HOT: 610ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 611ebccec0fSMark Brown WM8350_IM_CHG_BAT_HOT_EINT); 612ebccec0fSMark Brown case WM8350_IRQ_CHG_BAT_COLD: 613ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 614ebccec0fSMark Brown WM8350_IM_CHG_BAT_COLD_EINT); 615ebccec0fSMark Brown case WM8350_IRQ_CHG_BAT_FAIL: 616ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 617ebccec0fSMark Brown WM8350_IM_CHG_BAT_FAIL_EINT); 618ebccec0fSMark Brown case WM8350_IRQ_CHG_TO: 619ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 620ebccec0fSMark Brown WM8350_IM_CHG_TO_EINT); 621ebccec0fSMark Brown case WM8350_IRQ_CHG_END: 622ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 623ebccec0fSMark Brown WM8350_IM_CHG_END_EINT); 624ebccec0fSMark Brown case WM8350_IRQ_CHG_START: 625ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 626ebccec0fSMark Brown WM8350_IM_CHG_START_EINT); 627ebccec0fSMark Brown case WM8350_IRQ_CHG_FAST_RDY: 628ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 629ebccec0fSMark Brown WM8350_IM_CHG_FAST_RDY_EINT); 630ebccec0fSMark Brown case WM8350_IRQ_RTC_PER: 631ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 632ebccec0fSMark Brown WM8350_IM_RTC_PER_EINT); 633ebccec0fSMark Brown case WM8350_IRQ_RTC_SEC: 634ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 635ebccec0fSMark Brown WM8350_IM_RTC_SEC_EINT); 636ebccec0fSMark Brown case WM8350_IRQ_RTC_ALM: 637ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 638ebccec0fSMark Brown WM8350_IM_RTC_ALM_EINT); 639ebccec0fSMark Brown case WM8350_IRQ_CHG_VBATT_LT_3P9: 640ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 641ebccec0fSMark Brown WM8350_IM_CHG_VBATT_LT_3P9_EINT); 642ebccec0fSMark Brown case WM8350_IRQ_CHG_VBATT_LT_3P1: 643ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 644ebccec0fSMark Brown WM8350_IM_CHG_VBATT_LT_3P1_EINT); 645ebccec0fSMark Brown case WM8350_IRQ_CHG_VBATT_LT_2P85: 646ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK, 647ebccec0fSMark Brown WM8350_IM_CHG_VBATT_LT_2P85_EINT); 648ebccec0fSMark Brown case WM8350_IRQ_CS1: 649ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 650ebccec0fSMark Brown WM8350_IM_CS1_EINT); 651ebccec0fSMark Brown case WM8350_IRQ_CS2: 652ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 653ebccec0fSMark Brown WM8350_IM_CS2_EINT); 654ebccec0fSMark Brown case WM8350_IRQ_USB_LIMIT: 655ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 656ebccec0fSMark Brown WM8350_IM_USB_LIMIT_EINT); 657ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DATARDY: 658ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 659ebccec0fSMark Brown WM8350_IM_AUXADC_DATARDY_EINT); 660ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DCOMP4: 661ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 662ebccec0fSMark Brown WM8350_IM_AUXADC_DCOMP4_EINT); 663ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DCOMP3: 664ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 665ebccec0fSMark Brown WM8350_IM_AUXADC_DCOMP3_EINT); 666ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DCOMP2: 667ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 668ebccec0fSMark Brown WM8350_IM_AUXADC_DCOMP2_EINT); 669ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DCOMP1: 670ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 671ebccec0fSMark Brown WM8350_IM_AUXADC_DCOMP1_EINT); 672ebccec0fSMark Brown case WM8350_IRQ_SYS_HYST_COMP_FAIL: 673ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 674ebccec0fSMark Brown WM8350_IM_SYS_HYST_COMP_FAIL_EINT); 675ebccec0fSMark Brown case WM8350_IRQ_SYS_CHIP_GT115: 676ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 677ebccec0fSMark Brown WM8350_IM_SYS_CHIP_GT115_EINT); 678ebccec0fSMark Brown case WM8350_IRQ_SYS_CHIP_GT140: 679ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 680ebccec0fSMark Brown WM8350_IM_SYS_CHIP_GT140_EINT); 681ebccec0fSMark Brown case WM8350_IRQ_SYS_WDOG_TO: 682ebccec0fSMark Brown return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK, 683ebccec0fSMark Brown WM8350_IM_SYS_WDOG_TO_EINT); 684ebccec0fSMark Brown case WM8350_IRQ_UV_LDO4: 685ebccec0fSMark Brown return wm8350_set_bits(wm8350, 686ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 687ebccec0fSMark Brown WM8350_IM_UV_LDO4_EINT); 688ebccec0fSMark Brown case WM8350_IRQ_UV_LDO3: 689ebccec0fSMark Brown return wm8350_set_bits(wm8350, 690ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 691ebccec0fSMark Brown WM8350_IM_UV_LDO3_EINT); 692ebccec0fSMark Brown case WM8350_IRQ_UV_LDO2: 693ebccec0fSMark Brown return wm8350_set_bits(wm8350, 694ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 695ebccec0fSMark Brown WM8350_IM_UV_LDO2_EINT); 696ebccec0fSMark Brown case WM8350_IRQ_UV_LDO1: 697ebccec0fSMark Brown return wm8350_set_bits(wm8350, 698ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 699ebccec0fSMark Brown WM8350_IM_UV_LDO1_EINT); 700ebccec0fSMark Brown case WM8350_IRQ_UV_DC6: 701ebccec0fSMark Brown return wm8350_set_bits(wm8350, 702ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 703ebccec0fSMark Brown WM8350_IM_UV_DC6_EINT); 704ebccec0fSMark Brown case WM8350_IRQ_UV_DC5: 705ebccec0fSMark Brown return wm8350_set_bits(wm8350, 706ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 707ebccec0fSMark Brown WM8350_IM_UV_DC5_EINT); 708ebccec0fSMark Brown case WM8350_IRQ_UV_DC4: 709ebccec0fSMark Brown return wm8350_set_bits(wm8350, 710ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 711ebccec0fSMark Brown WM8350_IM_UV_DC4_EINT); 712ebccec0fSMark Brown case WM8350_IRQ_UV_DC3: 713ebccec0fSMark Brown return wm8350_set_bits(wm8350, 714ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 715ebccec0fSMark Brown WM8350_IM_UV_DC3_EINT); 716ebccec0fSMark Brown case WM8350_IRQ_UV_DC2: 717ebccec0fSMark Brown return wm8350_set_bits(wm8350, 718ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 719ebccec0fSMark Brown WM8350_IM_UV_DC2_EINT); 720ebccec0fSMark Brown case WM8350_IRQ_UV_DC1: 721ebccec0fSMark Brown return wm8350_set_bits(wm8350, 722ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 723ebccec0fSMark Brown WM8350_IM_UV_DC1_EINT); 724ebccec0fSMark Brown case WM8350_IRQ_OC_LS: 725ebccec0fSMark Brown return wm8350_set_bits(wm8350, 726ebccec0fSMark Brown WM8350_OVER_CURRENT_INT_STATUS_MASK, 727ebccec0fSMark Brown WM8350_IM_OC_LS_EINT); 728ebccec0fSMark Brown case WM8350_IRQ_EXT_USB_FB: 729ebccec0fSMark Brown return wm8350_set_bits(wm8350, 730ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 731ebccec0fSMark Brown WM8350_IM_EXT_USB_FB_EINT); 732ebccec0fSMark Brown case WM8350_IRQ_EXT_WALL_FB: 733ebccec0fSMark Brown return wm8350_set_bits(wm8350, 734ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 735ebccec0fSMark Brown WM8350_IM_EXT_WALL_FB_EINT); 736ebccec0fSMark Brown case WM8350_IRQ_EXT_BAT_FB: 737ebccec0fSMark Brown return wm8350_set_bits(wm8350, 738ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 739ebccec0fSMark Brown WM8350_IM_EXT_BAT_FB_EINT); 740ebccec0fSMark Brown case WM8350_IRQ_CODEC_JCK_DET_L: 741ebccec0fSMark Brown return wm8350_set_bits(wm8350, 742ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 743ebccec0fSMark Brown WM8350_IM_CODEC_JCK_DET_L_EINT); 744ebccec0fSMark Brown case WM8350_IRQ_CODEC_JCK_DET_R: 745ebccec0fSMark Brown return wm8350_set_bits(wm8350, 746ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 747ebccec0fSMark Brown WM8350_IM_CODEC_JCK_DET_R_EINT); 748ebccec0fSMark Brown case WM8350_IRQ_CODEC_MICSCD: 749ebccec0fSMark Brown return wm8350_set_bits(wm8350, 750ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 751ebccec0fSMark Brown WM8350_IM_CODEC_MICSCD_EINT); 752ebccec0fSMark Brown case WM8350_IRQ_CODEC_MICD: 753ebccec0fSMark Brown return wm8350_set_bits(wm8350, 754ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 755ebccec0fSMark Brown WM8350_IM_CODEC_MICD_EINT); 756ebccec0fSMark Brown case WM8350_IRQ_WKUP_OFF_STATE: 757ebccec0fSMark Brown return wm8350_set_bits(wm8350, 758ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 759ebccec0fSMark Brown WM8350_IM_WKUP_OFF_STATE_EINT); 760ebccec0fSMark Brown case WM8350_IRQ_WKUP_HIB_STATE: 761ebccec0fSMark Brown return wm8350_set_bits(wm8350, 762ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 763ebccec0fSMark Brown WM8350_IM_WKUP_HIB_STATE_EINT); 764ebccec0fSMark Brown case WM8350_IRQ_WKUP_CONV_FAULT: 765ebccec0fSMark Brown return wm8350_set_bits(wm8350, 766ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 767ebccec0fSMark Brown WM8350_IM_WKUP_CONV_FAULT_EINT); 768ebccec0fSMark Brown case WM8350_IRQ_WKUP_WDOG_RST: 769ebccec0fSMark Brown return wm8350_set_bits(wm8350, 770ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 771ebccec0fSMark Brown WM8350_IM_WKUP_OFF_STATE_EINT); 772ebccec0fSMark Brown case WM8350_IRQ_WKUP_GP_PWR_ON: 773ebccec0fSMark Brown return wm8350_set_bits(wm8350, 774ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 775ebccec0fSMark Brown WM8350_IM_WKUP_GP_PWR_ON_EINT); 776ebccec0fSMark Brown case WM8350_IRQ_WKUP_ONKEY: 777ebccec0fSMark Brown return wm8350_set_bits(wm8350, 778ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 779ebccec0fSMark Brown WM8350_IM_WKUP_ONKEY_EINT); 780ebccec0fSMark Brown case WM8350_IRQ_WKUP_GP_WAKEUP: 781ebccec0fSMark Brown return wm8350_set_bits(wm8350, 782ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 783ebccec0fSMark Brown WM8350_IM_WKUP_GP_WAKEUP_EINT); 784ebccec0fSMark Brown case WM8350_IRQ_GPIO(0): 785ebccec0fSMark Brown return wm8350_set_bits(wm8350, 786ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 787ebccec0fSMark Brown WM8350_IM_GP0_EINT); 788ebccec0fSMark Brown case WM8350_IRQ_GPIO(1): 789ebccec0fSMark Brown return wm8350_set_bits(wm8350, 790ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 791ebccec0fSMark Brown WM8350_IM_GP1_EINT); 792ebccec0fSMark Brown case WM8350_IRQ_GPIO(2): 793ebccec0fSMark Brown return wm8350_set_bits(wm8350, 794ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 795ebccec0fSMark Brown WM8350_IM_GP2_EINT); 796ebccec0fSMark Brown case WM8350_IRQ_GPIO(3): 797ebccec0fSMark Brown return wm8350_set_bits(wm8350, 798ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 799ebccec0fSMark Brown WM8350_IM_GP3_EINT); 800ebccec0fSMark Brown case WM8350_IRQ_GPIO(4): 801ebccec0fSMark Brown return wm8350_set_bits(wm8350, 802ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 803ebccec0fSMark Brown WM8350_IM_GP4_EINT); 804ebccec0fSMark Brown case WM8350_IRQ_GPIO(5): 805ebccec0fSMark Brown return wm8350_set_bits(wm8350, 806ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 807ebccec0fSMark Brown WM8350_IM_GP5_EINT); 808ebccec0fSMark Brown case WM8350_IRQ_GPIO(6): 809ebccec0fSMark Brown return wm8350_set_bits(wm8350, 810ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 811ebccec0fSMark Brown WM8350_IM_GP6_EINT); 812ebccec0fSMark Brown case WM8350_IRQ_GPIO(7): 813ebccec0fSMark Brown return wm8350_set_bits(wm8350, 814ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 815ebccec0fSMark Brown WM8350_IM_GP7_EINT); 816ebccec0fSMark Brown case WM8350_IRQ_GPIO(8): 817ebccec0fSMark Brown return wm8350_set_bits(wm8350, 818ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 819ebccec0fSMark Brown WM8350_IM_GP8_EINT); 820ebccec0fSMark Brown case WM8350_IRQ_GPIO(9): 821ebccec0fSMark Brown return wm8350_set_bits(wm8350, 822ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 823ebccec0fSMark Brown WM8350_IM_GP9_EINT); 824ebccec0fSMark Brown case WM8350_IRQ_GPIO(10): 825ebccec0fSMark Brown return wm8350_set_bits(wm8350, 826ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 827ebccec0fSMark Brown WM8350_IM_GP10_EINT); 828ebccec0fSMark Brown case WM8350_IRQ_GPIO(11): 829ebccec0fSMark Brown return wm8350_set_bits(wm8350, 830ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 831ebccec0fSMark Brown WM8350_IM_GP11_EINT); 832ebccec0fSMark Brown case WM8350_IRQ_GPIO(12): 833ebccec0fSMark Brown return wm8350_set_bits(wm8350, 834ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 835ebccec0fSMark Brown WM8350_IM_GP12_EINT); 836ebccec0fSMark Brown default: 837ebccec0fSMark Brown dev_warn(wm8350->dev, "Attempting to mask unknown IRQ %d\n", 838ebccec0fSMark Brown irq); 839ebccec0fSMark Brown return -EINVAL; 840ebccec0fSMark Brown } 841ebccec0fSMark Brown return 0; 842ebccec0fSMark Brown } 843ebccec0fSMark Brown EXPORT_SYMBOL_GPL(wm8350_mask_irq); 844ebccec0fSMark Brown 845ebccec0fSMark Brown int wm8350_unmask_irq(struct wm8350 *wm8350, int irq) 846ebccec0fSMark Brown { 847ebccec0fSMark Brown switch (irq) { 848ebccec0fSMark Brown case WM8350_IRQ_CHG_BAT_HOT: 849ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 850ebccec0fSMark Brown WM8350_IM_CHG_BAT_HOT_EINT); 851ebccec0fSMark Brown case WM8350_IRQ_CHG_BAT_COLD: 852ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 853ebccec0fSMark Brown WM8350_IM_CHG_BAT_COLD_EINT); 854ebccec0fSMark Brown case WM8350_IRQ_CHG_BAT_FAIL: 855ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 856ebccec0fSMark Brown WM8350_IM_CHG_BAT_FAIL_EINT); 857ebccec0fSMark Brown case WM8350_IRQ_CHG_TO: 858ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 859ebccec0fSMark Brown WM8350_IM_CHG_TO_EINT); 860ebccec0fSMark Brown case WM8350_IRQ_CHG_END: 861ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 862ebccec0fSMark Brown WM8350_IM_CHG_END_EINT); 863ebccec0fSMark Brown case WM8350_IRQ_CHG_START: 864ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 865ebccec0fSMark Brown WM8350_IM_CHG_START_EINT); 866ebccec0fSMark Brown case WM8350_IRQ_CHG_FAST_RDY: 867ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 868ebccec0fSMark Brown WM8350_IM_CHG_FAST_RDY_EINT); 869ebccec0fSMark Brown case WM8350_IRQ_RTC_PER: 870ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 871ebccec0fSMark Brown WM8350_IM_RTC_PER_EINT); 872ebccec0fSMark Brown case WM8350_IRQ_RTC_SEC: 873ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 874ebccec0fSMark Brown WM8350_IM_RTC_SEC_EINT); 875ebccec0fSMark Brown case WM8350_IRQ_RTC_ALM: 876ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 877ebccec0fSMark Brown WM8350_IM_RTC_ALM_EINT); 878ebccec0fSMark Brown case WM8350_IRQ_CHG_VBATT_LT_3P9: 879ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 880ebccec0fSMark Brown WM8350_IM_CHG_VBATT_LT_3P9_EINT); 881ebccec0fSMark Brown case WM8350_IRQ_CHG_VBATT_LT_3P1: 882ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 883ebccec0fSMark Brown WM8350_IM_CHG_VBATT_LT_3P1_EINT); 884ebccec0fSMark Brown case WM8350_IRQ_CHG_VBATT_LT_2P85: 885ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK, 886ebccec0fSMark Brown WM8350_IM_CHG_VBATT_LT_2P85_EINT); 887ebccec0fSMark Brown case WM8350_IRQ_CS1: 888ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 889ebccec0fSMark Brown WM8350_IM_CS1_EINT); 890ebccec0fSMark Brown case WM8350_IRQ_CS2: 891ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 892ebccec0fSMark Brown WM8350_IM_CS2_EINT); 893ebccec0fSMark Brown case WM8350_IRQ_USB_LIMIT: 894ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 895ebccec0fSMark Brown WM8350_IM_USB_LIMIT_EINT); 896ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DATARDY: 897ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 898ebccec0fSMark Brown WM8350_IM_AUXADC_DATARDY_EINT); 899ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DCOMP4: 900ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 901ebccec0fSMark Brown WM8350_IM_AUXADC_DCOMP4_EINT); 902ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DCOMP3: 903ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 904ebccec0fSMark Brown WM8350_IM_AUXADC_DCOMP3_EINT); 905ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DCOMP2: 906ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 907ebccec0fSMark Brown WM8350_IM_AUXADC_DCOMP2_EINT); 908ebccec0fSMark Brown case WM8350_IRQ_AUXADC_DCOMP1: 909ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 910ebccec0fSMark Brown WM8350_IM_AUXADC_DCOMP1_EINT); 911ebccec0fSMark Brown case WM8350_IRQ_SYS_HYST_COMP_FAIL: 912ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 913ebccec0fSMark Brown WM8350_IM_SYS_HYST_COMP_FAIL_EINT); 914ebccec0fSMark Brown case WM8350_IRQ_SYS_CHIP_GT115: 915ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 916ebccec0fSMark Brown WM8350_IM_SYS_CHIP_GT115_EINT); 917ebccec0fSMark Brown case WM8350_IRQ_SYS_CHIP_GT140: 918ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 919ebccec0fSMark Brown WM8350_IM_SYS_CHIP_GT140_EINT); 920ebccec0fSMark Brown case WM8350_IRQ_SYS_WDOG_TO: 921ebccec0fSMark Brown return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK, 922ebccec0fSMark Brown WM8350_IM_SYS_WDOG_TO_EINT); 923ebccec0fSMark Brown case WM8350_IRQ_UV_LDO4: 924ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 925ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 926ebccec0fSMark Brown WM8350_IM_UV_LDO4_EINT); 927ebccec0fSMark Brown case WM8350_IRQ_UV_LDO3: 928ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 929ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 930ebccec0fSMark Brown WM8350_IM_UV_LDO3_EINT); 931ebccec0fSMark Brown case WM8350_IRQ_UV_LDO2: 932ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 933ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 934ebccec0fSMark Brown WM8350_IM_UV_LDO2_EINT); 935ebccec0fSMark Brown case WM8350_IRQ_UV_LDO1: 936ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 937ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 938ebccec0fSMark Brown WM8350_IM_UV_LDO1_EINT); 939ebccec0fSMark Brown case WM8350_IRQ_UV_DC6: 940ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 941ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 942ebccec0fSMark Brown WM8350_IM_UV_DC6_EINT); 943ebccec0fSMark Brown case WM8350_IRQ_UV_DC5: 944ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 945ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 946ebccec0fSMark Brown WM8350_IM_UV_DC5_EINT); 947ebccec0fSMark Brown case WM8350_IRQ_UV_DC4: 948ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 949ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 950ebccec0fSMark Brown WM8350_IM_UV_DC4_EINT); 951ebccec0fSMark Brown case WM8350_IRQ_UV_DC3: 952ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 953ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 954ebccec0fSMark Brown WM8350_IM_UV_DC3_EINT); 955ebccec0fSMark Brown case WM8350_IRQ_UV_DC2: 956ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 957ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 958ebccec0fSMark Brown WM8350_IM_UV_DC2_EINT); 959ebccec0fSMark Brown case WM8350_IRQ_UV_DC1: 960ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 961ebccec0fSMark Brown WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 962ebccec0fSMark Brown WM8350_IM_UV_DC1_EINT); 963ebccec0fSMark Brown case WM8350_IRQ_OC_LS: 964ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 965ebccec0fSMark Brown WM8350_OVER_CURRENT_INT_STATUS_MASK, 966ebccec0fSMark Brown WM8350_IM_OC_LS_EINT); 967ebccec0fSMark Brown case WM8350_IRQ_EXT_USB_FB: 968ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 969ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 970ebccec0fSMark Brown WM8350_IM_EXT_USB_FB_EINT); 971ebccec0fSMark Brown case WM8350_IRQ_EXT_WALL_FB: 972ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 973ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 974ebccec0fSMark Brown WM8350_IM_EXT_WALL_FB_EINT); 975ebccec0fSMark Brown case WM8350_IRQ_EXT_BAT_FB: 976ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 977ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 978ebccec0fSMark Brown WM8350_IM_EXT_BAT_FB_EINT); 979ebccec0fSMark Brown case WM8350_IRQ_CODEC_JCK_DET_L: 980ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 981ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 982ebccec0fSMark Brown WM8350_IM_CODEC_JCK_DET_L_EINT); 983ebccec0fSMark Brown case WM8350_IRQ_CODEC_JCK_DET_R: 984ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 985ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 986ebccec0fSMark Brown WM8350_IM_CODEC_JCK_DET_R_EINT); 987ebccec0fSMark Brown case WM8350_IRQ_CODEC_MICSCD: 988ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 989ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 990ebccec0fSMark Brown WM8350_IM_CODEC_MICSCD_EINT); 991ebccec0fSMark Brown case WM8350_IRQ_CODEC_MICD: 992ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 993ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 994ebccec0fSMark Brown WM8350_IM_CODEC_MICD_EINT); 995ebccec0fSMark Brown case WM8350_IRQ_WKUP_OFF_STATE: 996ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 997ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 998ebccec0fSMark Brown WM8350_IM_WKUP_OFF_STATE_EINT); 999ebccec0fSMark Brown case WM8350_IRQ_WKUP_HIB_STATE: 1000ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1001ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 1002ebccec0fSMark Brown WM8350_IM_WKUP_HIB_STATE_EINT); 1003ebccec0fSMark Brown case WM8350_IRQ_WKUP_CONV_FAULT: 1004ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1005ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 1006ebccec0fSMark Brown WM8350_IM_WKUP_CONV_FAULT_EINT); 1007ebccec0fSMark Brown case WM8350_IRQ_WKUP_WDOG_RST: 1008ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1009ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 1010ebccec0fSMark Brown WM8350_IM_WKUP_OFF_STATE_EINT); 1011ebccec0fSMark Brown case WM8350_IRQ_WKUP_GP_PWR_ON: 1012ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1013ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 1014ebccec0fSMark Brown WM8350_IM_WKUP_GP_PWR_ON_EINT); 1015ebccec0fSMark Brown case WM8350_IRQ_WKUP_ONKEY: 1016ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1017ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 1018ebccec0fSMark Brown WM8350_IM_WKUP_ONKEY_EINT); 1019ebccec0fSMark Brown case WM8350_IRQ_WKUP_GP_WAKEUP: 1020ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1021ebccec0fSMark Brown WM8350_COMPARATOR_INT_STATUS_MASK, 1022ebccec0fSMark Brown WM8350_IM_WKUP_GP_WAKEUP_EINT); 1023ebccec0fSMark Brown case WM8350_IRQ_GPIO(0): 1024ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1025ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1026ebccec0fSMark Brown WM8350_IM_GP0_EINT); 1027ebccec0fSMark Brown case WM8350_IRQ_GPIO(1): 1028ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1029ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1030ebccec0fSMark Brown WM8350_IM_GP1_EINT); 1031ebccec0fSMark Brown case WM8350_IRQ_GPIO(2): 1032ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1033ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1034ebccec0fSMark Brown WM8350_IM_GP2_EINT); 1035ebccec0fSMark Brown case WM8350_IRQ_GPIO(3): 1036ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1037ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1038ebccec0fSMark Brown WM8350_IM_GP3_EINT); 1039ebccec0fSMark Brown case WM8350_IRQ_GPIO(4): 1040ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1041ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1042ebccec0fSMark Brown WM8350_IM_GP4_EINT); 1043ebccec0fSMark Brown case WM8350_IRQ_GPIO(5): 1044ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1045ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1046ebccec0fSMark Brown WM8350_IM_GP5_EINT); 1047ebccec0fSMark Brown case WM8350_IRQ_GPIO(6): 1048ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1049ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1050ebccec0fSMark Brown WM8350_IM_GP6_EINT); 1051ebccec0fSMark Brown case WM8350_IRQ_GPIO(7): 1052ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1053ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1054ebccec0fSMark Brown WM8350_IM_GP7_EINT); 1055ebccec0fSMark Brown case WM8350_IRQ_GPIO(8): 1056ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1057ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1058ebccec0fSMark Brown WM8350_IM_GP8_EINT); 1059ebccec0fSMark Brown case WM8350_IRQ_GPIO(9): 1060ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1061ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1062ebccec0fSMark Brown WM8350_IM_GP9_EINT); 1063ebccec0fSMark Brown case WM8350_IRQ_GPIO(10): 1064ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1065ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1066ebccec0fSMark Brown WM8350_IM_GP10_EINT); 1067ebccec0fSMark Brown case WM8350_IRQ_GPIO(11): 1068ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1069ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1070ebccec0fSMark Brown WM8350_IM_GP11_EINT); 1071ebccec0fSMark Brown case WM8350_IRQ_GPIO(12): 1072ebccec0fSMark Brown return wm8350_clear_bits(wm8350, 1073ebccec0fSMark Brown WM8350_GPIO_INT_STATUS_MASK, 1074ebccec0fSMark Brown WM8350_IM_GP12_EINT); 1075ebccec0fSMark Brown default: 1076ebccec0fSMark Brown dev_warn(wm8350->dev, "Attempting to unmask unknown IRQ %d\n", 1077ebccec0fSMark Brown irq); 1078ebccec0fSMark Brown return -EINVAL; 1079ebccec0fSMark Brown } 1080ebccec0fSMark Brown return 0; 1081ebccec0fSMark Brown } 1082ebccec0fSMark Brown EXPORT_SYMBOL_GPL(wm8350_unmask_irq); 1083ebccec0fSMark Brown 108467488526SMark Brown int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref) 108567488526SMark Brown { 108667488526SMark Brown u16 reg, result = 0; 108767488526SMark Brown int tries = 5; 108867488526SMark Brown 108967488526SMark Brown if (channel < WM8350_AUXADC_AUX1 || channel > WM8350_AUXADC_TEMP) 109067488526SMark Brown return -EINVAL; 109167488526SMark Brown if (channel >= WM8350_AUXADC_USB && channel <= WM8350_AUXADC_TEMP 109267488526SMark Brown && (scale != 0 || vref != 0)) 109367488526SMark Brown return -EINVAL; 109467488526SMark Brown 109567488526SMark Brown mutex_lock(&wm8350->auxadc_mutex); 109667488526SMark Brown 109767488526SMark Brown /* Turn on the ADC */ 109867488526SMark Brown reg = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5); 109967488526SMark Brown wm8350_reg_write(wm8350, WM8350_POWER_MGMT_5, reg | WM8350_AUXADC_ENA); 110067488526SMark Brown 110167488526SMark Brown if (scale || vref) { 110267488526SMark Brown reg = scale << 13; 110367488526SMark Brown reg |= vref << 12; 110467488526SMark Brown wm8350_reg_write(wm8350, WM8350_AUX1_READBACK + channel, reg); 110567488526SMark Brown } 110667488526SMark Brown 110767488526SMark Brown reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1); 110867488526SMark Brown reg |= 1 << channel | WM8350_AUXADC_POLL; 110967488526SMark Brown wm8350_reg_write(wm8350, WM8350_DIGITISER_CONTROL_1, reg); 111067488526SMark Brown 111167488526SMark Brown do { 111267488526SMark Brown schedule_timeout_interruptible(1); 111367488526SMark Brown reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1); 111467488526SMark Brown } while (tries-- && (reg & WM8350_AUXADC_POLL)); 111567488526SMark Brown 111667488526SMark Brown if (!tries) 111767488526SMark Brown dev_err(wm8350->dev, "adc chn %d read timeout\n", channel); 111867488526SMark Brown else 111967488526SMark Brown result = wm8350_reg_read(wm8350, 112067488526SMark Brown WM8350_AUX1_READBACK + channel); 112167488526SMark Brown 112267488526SMark Brown /* Turn off the ADC */ 112367488526SMark Brown reg = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5); 112467488526SMark Brown wm8350_reg_write(wm8350, WM8350_POWER_MGMT_5, 112567488526SMark Brown reg & ~WM8350_AUXADC_ENA); 112667488526SMark Brown 112767488526SMark Brown mutex_unlock(&wm8350->auxadc_mutex); 112867488526SMark Brown 112967488526SMark Brown return result & WM8350_AUXADC_DATA1_MASK; 113067488526SMark Brown } 113167488526SMark Brown EXPORT_SYMBOL_GPL(wm8350_read_auxadc); 113267488526SMark Brown 113389b4012bSMark Brown /* 113489b4012bSMark Brown * Cache is always host endian. 113589b4012bSMark Brown */ 113696920630SMark Brown static int wm8350_create_cache(struct wm8350 *wm8350, int type, int mode) 113789b4012bSMark Brown { 113889b4012bSMark Brown int i, ret = 0; 113989b4012bSMark Brown u16 value; 114089b4012bSMark Brown const u16 *reg_map; 114189b4012bSMark Brown 114296920630SMark Brown switch (type) { 114396920630SMark Brown case 0: 114489b4012bSMark Brown switch (mode) { 114589b4012bSMark Brown #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0 114689b4012bSMark Brown case 0: 114789b4012bSMark Brown reg_map = wm8350_mode0_defaults; 114889b4012bSMark Brown break; 114989b4012bSMark Brown #endif 115089b4012bSMark Brown #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1 115189b4012bSMark Brown case 1: 115289b4012bSMark Brown reg_map = wm8350_mode1_defaults; 115389b4012bSMark Brown break; 115489b4012bSMark Brown #endif 115589b4012bSMark Brown #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2 115689b4012bSMark Brown case 2: 115789b4012bSMark Brown reg_map = wm8350_mode2_defaults; 115889b4012bSMark Brown break; 115989b4012bSMark Brown #endif 116089b4012bSMark Brown #ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3 116189b4012bSMark Brown case 3: 116289b4012bSMark Brown reg_map = wm8350_mode3_defaults; 116389b4012bSMark Brown break; 116489b4012bSMark Brown #endif 116589b4012bSMark Brown default: 116696920630SMark Brown dev_err(wm8350->dev, 116796920630SMark Brown "WM8350 configuration mode %d not supported\n", 116896920630SMark Brown mode); 116996920630SMark Brown return -EINVAL; 117096920630SMark Brown } 11714331bb32SMark Brown break; 117296920630SMark Brown 1173ca23f8c1SMark Brown case 1: 1174ca23f8c1SMark Brown switch (mode) { 1175ca23f8c1SMark Brown #ifdef CONFIG_MFD_WM8351_CONFIG_MODE_0 1176ca23f8c1SMark Brown case 0: 1177ca23f8c1SMark Brown reg_map = wm8351_mode0_defaults; 1178ca23f8c1SMark Brown break; 1179ca23f8c1SMark Brown #endif 1180ca23f8c1SMark Brown #ifdef CONFIG_MFD_WM8351_CONFIG_MODE_1 1181ca23f8c1SMark Brown case 1: 1182ca23f8c1SMark Brown reg_map = wm8351_mode1_defaults; 1183ca23f8c1SMark Brown break; 1184ca23f8c1SMark Brown #endif 1185ca23f8c1SMark Brown #ifdef CONFIG_MFD_WM8351_CONFIG_MODE_2 1186ca23f8c1SMark Brown case 2: 1187ca23f8c1SMark Brown reg_map = wm8351_mode2_defaults; 1188ca23f8c1SMark Brown break; 1189ca23f8c1SMark Brown #endif 1190ca23f8c1SMark Brown #ifdef CONFIG_MFD_WM8351_CONFIG_MODE_3 1191ca23f8c1SMark Brown case 3: 1192ca23f8c1SMark Brown reg_map = wm8351_mode3_defaults; 1193ca23f8c1SMark Brown break; 1194ca23f8c1SMark Brown #endif 1195ca23f8c1SMark Brown default: 1196ca23f8c1SMark Brown dev_err(wm8350->dev, 1197ca23f8c1SMark Brown "WM8351 configuration mode %d not supported\n", 1198ca23f8c1SMark Brown mode); 1199ca23f8c1SMark Brown return -EINVAL; 1200ca23f8c1SMark Brown } 1201ca23f8c1SMark Brown break; 1202ca23f8c1SMark Brown 120396920630SMark Brown case 2: 120496920630SMark Brown switch (mode) { 120596920630SMark Brown #ifdef CONFIG_MFD_WM8352_CONFIG_MODE_0 120696920630SMark Brown case 0: 120796920630SMark Brown reg_map = wm8352_mode0_defaults; 120896920630SMark Brown break; 120996920630SMark Brown #endif 121096920630SMark Brown #ifdef CONFIG_MFD_WM8352_CONFIG_MODE_1 121196920630SMark Brown case 1: 121296920630SMark Brown reg_map = wm8352_mode1_defaults; 121396920630SMark Brown break; 121496920630SMark Brown #endif 121596920630SMark Brown #ifdef CONFIG_MFD_WM8352_CONFIG_MODE_2 121696920630SMark Brown case 2: 121796920630SMark Brown reg_map = wm8352_mode2_defaults; 121896920630SMark Brown break; 121996920630SMark Brown #endif 122096920630SMark Brown #ifdef CONFIG_MFD_WM8352_CONFIG_MODE_3 122196920630SMark Brown case 3: 122296920630SMark Brown reg_map = wm8352_mode3_defaults; 122396920630SMark Brown break; 122496920630SMark Brown #endif 122596920630SMark Brown default: 122696920630SMark Brown dev_err(wm8350->dev, 122796920630SMark Brown "WM8352 configuration mode %d not supported\n", 122896920630SMark Brown mode); 122996920630SMark Brown return -EINVAL; 123096920630SMark Brown } 123196920630SMark Brown break; 123296920630SMark Brown 123396920630SMark Brown default: 123496920630SMark Brown dev_err(wm8350->dev, 123596920630SMark Brown "WM835x configuration mode %d not supported\n", 123689b4012bSMark Brown mode); 123789b4012bSMark Brown return -EINVAL; 123889b4012bSMark Brown } 123989b4012bSMark Brown 124089b4012bSMark Brown wm8350->reg_cache = 124189b4012bSMark Brown kzalloc(sizeof(u16) * (WM8350_MAX_REGISTER + 1), GFP_KERNEL); 124289b4012bSMark Brown if (wm8350->reg_cache == NULL) 124389b4012bSMark Brown return -ENOMEM; 124489b4012bSMark Brown 124589b4012bSMark Brown /* Read the initial cache state back from the device - this is 124689b4012bSMark Brown * a PMIC so the device many not be in a virgin state and we 124789b4012bSMark Brown * can't rely on the silicon values. 124889b4012bSMark Brown */ 124989b4012bSMark Brown for (i = 0; i < WM8350_MAX_REGISTER; i++) { 125089b4012bSMark Brown /* audio register range */ 125189b4012bSMark Brown if (wm8350_reg_io_map[i].readable && 125289b4012bSMark Brown (i < WM8350_CLOCK_CONTROL_1 || i > WM8350_AIF_TEST)) { 125389b4012bSMark Brown ret = wm8350->read_dev(wm8350, i, 2, (char *)&value); 125489b4012bSMark Brown if (ret < 0) { 125589b4012bSMark Brown dev_err(wm8350->dev, 125689b4012bSMark Brown "failed to read initial cache value\n"); 125789b4012bSMark Brown goto out; 125889b4012bSMark Brown } 125989b4012bSMark Brown value = be16_to_cpu(value); 126089b4012bSMark Brown value &= wm8350_reg_io_map[i].readable; 1261e76f7558SMark Brown value &= ~wm8350_reg_io_map[i].vol; 126289b4012bSMark Brown wm8350->reg_cache[i] = value; 126389b4012bSMark Brown } else 126489b4012bSMark Brown wm8350->reg_cache[i] = reg_map[i]; 126589b4012bSMark Brown } 126689b4012bSMark Brown 126789b4012bSMark Brown out: 126889b4012bSMark Brown return ret; 126989b4012bSMark Brown } 127089b4012bSMark Brown 12719201d38bSMark Brown /* 12729201d38bSMark Brown * Register a client device. This is non-fatal since there is no need to 12739201d38bSMark Brown * fail the entire device init due to a single platform device failing. 12749201d38bSMark Brown */ 12759201d38bSMark Brown static void wm8350_client_dev_register(struct wm8350 *wm8350, 12769201d38bSMark Brown const char *name, 12779201d38bSMark Brown struct platform_device **pdev) 12789201d38bSMark Brown { 12799201d38bSMark Brown int ret; 12809201d38bSMark Brown 12819201d38bSMark Brown *pdev = platform_device_alloc(name, -1); 12829201d38bSMark Brown if (pdev == NULL) { 12839201d38bSMark Brown dev_err(wm8350->dev, "Failed to allocate %s\n", name); 12849201d38bSMark Brown return; 12859201d38bSMark Brown } 12869201d38bSMark Brown 12879201d38bSMark Brown (*pdev)->dev.parent = wm8350->dev; 12889201d38bSMark Brown platform_set_drvdata(*pdev, wm8350); 12899201d38bSMark Brown ret = platform_device_add(*pdev); 12909201d38bSMark Brown if (ret != 0) { 12919201d38bSMark Brown dev_err(wm8350->dev, "Failed to register %s: %d\n", name, ret); 12929201d38bSMark Brown platform_device_put(*pdev); 12939201d38bSMark Brown *pdev = NULL; 12949201d38bSMark Brown } 12959201d38bSMark Brown } 12969201d38bSMark Brown 1297ebccec0fSMark Brown int wm8350_device_init(struct wm8350 *wm8350, int irq, 1298bcdd4efcSMark Brown struct wm8350_platform_data *pdata) 129989b4012bSMark Brown { 130089b4012bSMark Brown int ret = -EINVAL; 1301b797a555SMark Brown u16 id1, id2, mask_rev; 1302b797a555SMark Brown u16 cust_id, mode, chip_rev; 130389b4012bSMark Brown 130489b4012bSMark Brown /* get WM8350 revision and config mode */ 130589b4012bSMark Brown wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1); 130689b4012bSMark Brown wm8350->read_dev(wm8350, WM8350_ID, sizeof(id2), &id2); 1307b797a555SMark Brown wm8350->read_dev(wm8350, WM8350_REVISION, sizeof(mask_rev), &mask_rev); 130889b4012bSMark Brown 130989b4012bSMark Brown id1 = be16_to_cpu(id1); 131089b4012bSMark Brown id2 = be16_to_cpu(id2); 1311b797a555SMark Brown mask_rev = be16_to_cpu(mask_rev); 131289b4012bSMark Brown 1313b797a555SMark Brown if (id1 != 0x6143) { 1314b797a555SMark Brown dev_err(wm8350->dev, 1315b797a555SMark Brown "Device with ID %x is not a WM8350\n", id1); 131689b4012bSMark Brown ret = -ENODEV; 131789b4012bSMark Brown goto err; 131889b4012bSMark Brown } 131989b4012bSMark Brown 132089b4012bSMark Brown mode = id2 & WM8350_CONF_STS_MASK >> 10; 1321b797a555SMark Brown cust_id = id2 & WM8350_CUST_ID_MASK; 1322b797a555SMark Brown chip_rev = (id2 & WM8350_CHIP_REV_MASK) >> 12; 1323b797a555SMark Brown dev_info(wm8350->dev, 1324b797a555SMark Brown "CONF_STS %d, CUST_ID %d, MASK_REV %d, CHIP_REV %d\n", 1325b797a555SMark Brown mode, cust_id, mask_rev, chip_rev); 1326b797a555SMark Brown 1327b797a555SMark Brown if (cust_id != 0) { 1328b797a555SMark Brown dev_err(wm8350->dev, "Unsupported CUST_ID\n"); 1329b797a555SMark Brown ret = -ENODEV; 1330b797a555SMark Brown goto err; 1331b797a555SMark Brown } 1332b797a555SMark Brown 1333b797a555SMark Brown switch (mask_rev) { 1334b797a555SMark Brown case 0: 1335645524a9SMark Brown wm8350->pmic.max_dcdc = WM8350_DCDC_6; 1336645524a9SMark Brown wm8350->pmic.max_isink = WM8350_ISINK_B; 1337645524a9SMark Brown 1338b797a555SMark Brown switch (chip_rev) { 1339b797a555SMark Brown case WM8350_REV_E: 1340b797a555SMark Brown dev_info(wm8350->dev, "WM8350 Rev E\n"); 1341b797a555SMark Brown break; 1342b797a555SMark Brown case WM8350_REV_F: 1343b797a555SMark Brown dev_info(wm8350->dev, "WM8350 Rev F\n"); 1344b797a555SMark Brown break; 1345b797a555SMark Brown case WM8350_REV_G: 1346b797a555SMark Brown dev_info(wm8350->dev, "WM8350 Rev G\n"); 1347b797a555SMark Brown wm8350->power.rev_g_coeff = 1; 1348b797a555SMark Brown break; 1349b797a555SMark Brown case WM8350_REV_H: 1350b797a555SMark Brown dev_info(wm8350->dev, "WM8350 Rev H\n"); 1351b797a555SMark Brown wm8350->power.rev_g_coeff = 1; 1352b797a555SMark Brown break; 1353b797a555SMark Brown default: 1354b797a555SMark Brown /* For safety we refuse to run on unknown hardware */ 1355b797a555SMark Brown dev_err(wm8350->dev, "Unknown WM8350 CHIP_REV\n"); 1356b797a555SMark Brown ret = -ENODEV; 1357b797a555SMark Brown goto err; 1358b797a555SMark Brown } 1359b797a555SMark Brown break; 1360b797a555SMark Brown 1361ca23f8c1SMark Brown case 1: 1362ca23f8c1SMark Brown wm8350->pmic.max_dcdc = WM8350_DCDC_4; 1363ca23f8c1SMark Brown wm8350->pmic.max_isink = WM8350_ISINK_A; 1364ca23f8c1SMark Brown 1365ca23f8c1SMark Brown switch (chip_rev) { 1366ca23f8c1SMark Brown case 0: 1367ca23f8c1SMark Brown dev_info(wm8350->dev, "WM8351 Rev A\n"); 1368ca23f8c1SMark Brown wm8350->power.rev_g_coeff = 1; 1369ca23f8c1SMark Brown break; 1370ca23f8c1SMark Brown 1371ca23f8c1SMark Brown default: 1372ca23f8c1SMark Brown dev_err(wm8350->dev, "Unknown WM8351 CHIP_REV\n"); 1373ca23f8c1SMark Brown ret = -ENODEV; 1374ca23f8c1SMark Brown goto err; 1375ca23f8c1SMark Brown } 1376ca23f8c1SMark Brown break; 1377ca23f8c1SMark Brown 137896920630SMark Brown case 2: 1379645524a9SMark Brown wm8350->pmic.max_dcdc = WM8350_DCDC_6; 1380645524a9SMark Brown wm8350->pmic.max_isink = WM8350_ISINK_B; 1381645524a9SMark Brown 138296920630SMark Brown switch (chip_rev) { 138396920630SMark Brown case 0: 138496920630SMark Brown dev_info(wm8350->dev, "WM8352 Rev A\n"); 138596920630SMark Brown wm8350->power.rev_g_coeff = 1; 138696920630SMark Brown break; 138796920630SMark Brown 138896920630SMark Brown default: 138996920630SMark Brown dev_err(wm8350->dev, "Unknown WM8352 CHIP_REV\n"); 139096920630SMark Brown ret = -ENODEV; 139196920630SMark Brown goto err; 139296920630SMark Brown } 139396920630SMark Brown break; 139496920630SMark Brown 1395b797a555SMark Brown default: 1396b797a555SMark Brown dev_err(wm8350->dev, "Unknown MASK_REV\n"); 1397b797a555SMark Brown ret = -ENODEV; 1398b797a555SMark Brown goto err; 1399b797a555SMark Brown } 140089b4012bSMark Brown 140196920630SMark Brown ret = wm8350_create_cache(wm8350, mask_rev, mode); 140289b4012bSMark Brown if (ret < 0) { 1403b797a555SMark Brown dev_err(wm8350->dev, "Failed to create register cache\n"); 140489b4012bSMark Brown return ret; 140589b4012bSMark Brown } 140689b4012bSMark Brown 140753a0d99bSMark Brown if (pdata && pdata->init) { 1408bcdd4efcSMark Brown ret = pdata->init(wm8350); 1409bcdd4efcSMark Brown if (ret != 0) { 1410bcdd4efcSMark Brown dev_err(wm8350->dev, "Platform init() failed: %d\n", 1411bcdd4efcSMark Brown ret); 1412bcdd4efcSMark Brown goto err; 1413bcdd4efcSMark Brown } 1414bcdd4efcSMark Brown } 1415bcdd4efcSMark Brown 141667488526SMark Brown mutex_init(&wm8350->auxadc_mutex); 1417ebccec0fSMark Brown mutex_init(&wm8350->irq_mutex); 1418ebccec0fSMark Brown INIT_WORK(&wm8350->irq_work, wm8350_irq_worker); 1419c7752351SMark Brown if (irq) { 1420ebccec0fSMark Brown ret = request_irq(irq, wm8350_irq, 0, 1421ebccec0fSMark Brown "wm8350", wm8350); 1422ebccec0fSMark Brown if (ret != 0) { 1423ebccec0fSMark Brown dev_err(wm8350->dev, "Failed to request IRQ: %d\n", 1424ebccec0fSMark Brown ret); 1425ebccec0fSMark Brown goto err; 1426ebccec0fSMark Brown } 1427ebccec0fSMark Brown } else { 1428ebccec0fSMark Brown dev_err(wm8350->dev, "No IRQ configured\n"); 1429ebccec0fSMark Brown goto err; 1430ebccec0fSMark Brown } 1431ebccec0fSMark Brown wm8350->chip_irq = irq; 1432ebccec0fSMark Brown 1433ebccec0fSMark Brown wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0x0); 1434ebccec0fSMark Brown 1435add41cb4SMark Brown wm8350_client_dev_register(wm8350, "wm8350-codec", 1436add41cb4SMark Brown &(wm8350->codec.pdev)); 1437add41cb4SMark Brown wm8350_client_dev_register(wm8350, "wm8350-gpio", 1438add41cb4SMark Brown &(wm8350->gpio.pdev)); 1439add41cb4SMark Brown wm8350_client_dev_register(wm8350, "wm8350-power", 1440add41cb4SMark Brown &(wm8350->power.pdev)); 1441add41cb4SMark Brown wm8350_client_dev_register(wm8350, "wm8350-rtc", &(wm8350->rtc.pdev)); 1442add41cb4SMark Brown wm8350_client_dev_register(wm8350, "wm8350-wdt", &(wm8350->wdt.pdev)); 1443add41cb4SMark Brown 144489b4012bSMark Brown return 0; 144589b4012bSMark Brown 144689b4012bSMark Brown err: 144789b4012bSMark Brown kfree(wm8350->reg_cache); 144889b4012bSMark Brown return ret; 144989b4012bSMark Brown } 145089b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_device_init); 145189b4012bSMark Brown 145289b4012bSMark Brown void wm8350_device_exit(struct wm8350 *wm8350) 145389b4012bSMark Brown { 1454da09155aSMark Brown int i; 1455da09155aSMark Brown 14560081e802SMark Brown for (i = 0; i < ARRAY_SIZE(wm8350->pmic.led); i++) 14570081e802SMark Brown platform_device_unregister(wm8350->pmic.led[i].pdev); 14580081e802SMark Brown 1459da09155aSMark Brown for (i = 0; i < ARRAY_SIZE(wm8350->pmic.pdev); i++) 1460da09155aSMark Brown platform_device_unregister(wm8350->pmic.pdev[i]); 1461da09155aSMark Brown 1462add41cb4SMark Brown platform_device_unregister(wm8350->wdt.pdev); 1463add41cb4SMark Brown platform_device_unregister(wm8350->rtc.pdev); 1464add41cb4SMark Brown platform_device_unregister(wm8350->power.pdev); 1465add41cb4SMark Brown platform_device_unregister(wm8350->gpio.pdev); 1466add41cb4SMark Brown platform_device_unregister(wm8350->codec.pdev); 1467add41cb4SMark Brown 1468ebccec0fSMark Brown free_irq(wm8350->chip_irq, wm8350); 1469ebccec0fSMark Brown flush_work(&wm8350->irq_work); 147089b4012bSMark Brown kfree(wm8350->reg_cache); 147189b4012bSMark Brown } 147289b4012bSMark Brown EXPORT_SYMBOL_GPL(wm8350_device_exit); 147389b4012bSMark Brown 1474ebccec0fSMark Brown MODULE_DESCRIPTION("WM8350 AudioPlus PMIC core driver"); 147589b4012bSMark Brown MODULE_LICENSE("GPL"); 1476