From 311e54c07e784fe63d421f724dcc597d1f82ccad Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 5 Jan 2010 19:55:54 +0100 Subject: mfd: Use resource_size() in sm501 The requested memory region is smaller than the actual ioremap(). Use resource_size() to get the correct size. Signed-off-by: H Hartley Sweeten Cc: Ben Dooks Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 0cc5eef..dc9ea95 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -1430,7 +1430,7 @@ static int __devinit sm501_plat_probe(struct platform_device *dev) } sm->regs_claim = request_mem_region(sm->io_res->start, - 0x100, "sm501"); + resource_size(sm->io_res), "sm501"); if (sm->regs_claim == NULL) { dev_err(&dev->dev, "cannot claim registers\n"); @@ -1440,8 +1440,7 @@ static int __devinit sm501_plat_probe(struct platform_device *dev) platform_set_drvdata(dev, sm); - sm->regs = ioremap(sm->io_res->start, - (sm->io_res->end - sm->io_res->start) - 1); + sm->regs = ioremap(sm->io_res->start, resource_size(sm->io_res)); if (sm->regs == NULL) { dev_err(&dev->dev, "cannot remap registers\n"); @@ -1645,7 +1644,7 @@ static int __devinit sm501_pci_probe(struct pci_dev *dev, sm->mem_res = &dev->resource[0]; sm->regs_claim = request_mem_region(sm->io_res->start, - 0x100, "sm501"); + resource_size(sm->io_res), "sm501"); if (sm->regs_claim == NULL) { dev_err(&dev->dev, "cannot claim registers\n"); err= -EBUSY; -- cgit v0.10.2 From c02e6a5ff43d24d73cf7830c2925e213fc72e037 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 5 Jan 2010 19:58:34 +0100 Subject: mfd: Use resource_size() for t7l66xb Use resource_size() for ioremap. Signed-off-by: H Hartley Sweeten Cc: Ian Molton Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index bcf4687..e0bbddd 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -360,7 +360,7 @@ static int t7l66xb_probe(struct platform_device *dev) if (ret) goto err_request_scr; - t7l66xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1); + t7l66xb->scr = ioremap(rscr->start, resource_size(rscr)); if (!t7l66xb->scr) { ret = -ENOMEM; goto err_ioremap; -- cgit v0.10.2 From 1ecc09e765d3ae16ef42a4d454836d9ed804fd18 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 5 Jan 2010 20:01:16 +0100 Subject: mfd: Use resouce_size for tc6393xb Use resource_size() for ioremap. Signed-off-by: H Hartley Sweeten Cc: Ian Molton Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 4bc5a08..c59e5c5 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -647,7 +647,7 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) if (ret) goto err_request_scr; - tc6393xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1); + tc6393xb->scr = ioremap(rscr->start, resource_size(rscr)); if (!tc6393xb->scr) { ret = -ENOMEM; goto err_ioremap; -- cgit v0.10.2 From 0e820ab60118e06db62ef4e55b6dd96db807a34e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 22 Dec 2009 21:31:43 +0100 Subject: mfd: Correct use after free for t7l66xb The structure t7l66xb should not be freed before the subsequent references to its fields in the arguments to clk_put. Furthermore, this structure is allocated near the beginning of the function, and a goto to the label err_noirq appears after a successful allocation, so it would seem that the kfree should be moved down below this label. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression x,e; identifier f; iterator I; statement S; @@ *kfree(x); ... when != &x when != x = e when != I(x,...) S *x->f // Signed-off-by: Julia Lawall diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index e0bbddd..26d9176 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -403,12 +403,12 @@ static int t7l66xb_probe(struct platform_device *dev) err_ioremap: release_resource(&t7l66xb->rscr); err_request_scr: - kfree(t7l66xb); clk_put(t7l66xb->clk48m); err_clk48m_get: clk_put(t7l66xb->clk32k); err_clk32k_get: err_noirq: + kfree(t7l66xb); return ret; } -- cgit v0.10.2 From f99344fc69c3df46786a39ea4283a4175ea40b3f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Jan 2010 13:59:07 +0000 Subject: mfd: Add a data argument to the WM8350 IRQ free function To better match genirq. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c index 9025f29..655836b 100644 --- a/drivers/mfd/wm8350-irq.c +++ b/drivers/mfd/wm8350-irq.c @@ -451,7 +451,7 @@ int wm8350_register_irq(struct wm8350 *wm8350, int irq, } EXPORT_SYMBOL_GPL(wm8350_register_irq); -int wm8350_free_irq(struct wm8350 *wm8350, int irq) +int wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data) { if (irq < 0 || irq >= WM8350_NUM_IRQ) return -EINVAL; diff --git a/drivers/power/wm8350_power.c b/drivers/power/wm8350_power.c index ad4f071..3839a5e 100644 --- a/drivers/power/wm8350_power.c +++ b/drivers/power/wm8350_power.c @@ -428,18 +428,18 @@ static void wm8350_init_charger(struct wm8350 *wm8350) static void free_charger_irq(struct wm8350 *wm8350) { - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1); - wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85); - wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB); - wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB); - wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, wm8350); } static __devinit int wm8350_power_probe(struct platform_device *pdev) diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 94227dd..723cd1f 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1453,7 +1453,7 @@ static int wm8350_regulator_remove(struct platform_device *pdev) struct regulator_dev *rdev = platform_get_drvdata(pdev); struct wm8350 *wm8350 = rdev_get_drvdata(rdev); - wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq); + wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq, rdev); regulator_unregister(rdev); diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c index f1e44052..a5512f5 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c @@ -478,8 +478,8 @@ static int __devexit wm8350_rtc_remove(struct platform_device *pdev) struct wm8350 *wm8350 = platform_get_drvdata(pdev); struct wm8350_rtc *wm_rtc = &wm8350->rtc; - wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC); - wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM); + wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC, wm8350); + wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM, wm8350); rtc_device_unregister(wm_rtc->rtc); diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h index 4386889..8883125 100644 --- a/include/linux/mfd/wm8350/core.h +++ b/include/linux/mfd/wm8350/core.h @@ -680,7 +680,8 @@ int wm8350_block_write(struct wm8350 *wm8350, int reg, int size, u16 *src); int wm8350_register_irq(struct wm8350 *wm8350, int irq, irq_handler_t handler, unsigned long flags, const char *name, void *data); -int wm8350_free_irq(struct wm8350 *wm8350, int irq); +int wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data); + int wm8350_mask_irq(struct wm8350 *wm8350, int irq); int wm8350_unmask_irq(struct wm8350 *wm8350, int irq); int wm8350_irq_init(struct wm8350 *wm8350, int irq, diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 718ef91..079bf74 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1521,8 +1521,8 @@ static int wm8350_remove(struct platform_device *pdev) WM8350_JDL_ENA | WM8350_JDR_ENA); wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); - wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); - wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); + wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, priv); + wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, priv); priv->hpl.jack = NULL; priv->hpr.jack = NULL; -- cgit v0.10.2 From 29c71b138c83c8191f1f7e46fcc28b9d6bc8a5dd Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Jan 2010 13:59:08 +0000 Subject: rtc: Suppress duplicate enable/disable of WM8350 update interrupt Unlike the wm8350-custom code genirq nests enable and disable calls so we can't just unconditionally mask or unmask the interrupt, we need to remember the state we set and only mask or unmask when there is a real change. Signed-off-by: Mark Brown Acked-by: Alessandro Zummo Cc: rtc-linux@googlegroups.com Signed-off-by: Samuel Ortiz diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c index a5512f5..3d0dc76 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c @@ -307,11 +307,18 @@ static int wm8350_rtc_update_irq_enable(struct device *dev, { struct wm8350 *wm8350 = dev_get_drvdata(dev); + /* Suppress duplicate changes since genirq nests enable and + * disable calls. */ + if (enabled == wm8350->rtc.update_enabled) + return 0; + if (enabled) wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_SEC); else wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC); + wm8350->rtc.update_enabled = enabled; + return 0; } diff --git a/include/linux/mfd/wm8350/rtc.h b/include/linux/mfd/wm8350/rtc.h index 24add2b..ebd72ff 100644 --- a/include/linux/mfd/wm8350/rtc.h +++ b/include/linux/mfd/wm8350/rtc.h @@ -263,6 +263,7 @@ struct wm8350_rtc { struct platform_device *pdev; struct rtc_device *rtc; int alarm_enabled; /* used over suspend/resume */ + int update_enabled; }; #endif -- cgit v0.10.2 From 760e4518788df6762700e6bb9dd8692379f11168 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Jan 2010 13:59:09 +0000 Subject: mfd: Convert WM8350 to genirq This gives us use of the diagnostic facilities genirq provides and will allow implementation of interrupt support for the WM8350 GPIOs. Stub functions are provided to ease the transition of the individual drivers, probably after additional work to pass the IRQ numbers via the struct devices. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c index 655836b..f56c9ad 100644 --- a/drivers/mfd/wm8350-irq.c +++ b/drivers/mfd/wm8350-irq.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include @@ -29,8 +29,6 @@ #include #include -#define WM8350_NUM_IRQ_REGS 7 - #define WM8350_INT_OFFSET_1 0 #define WM8350_INT_OFFSET_2 1 #define WM8350_POWER_UP_INT_OFFSET 2 @@ -366,19 +364,10 @@ static struct wm8350_irq_data wm8350_irqs[] = { }, }; -static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq) +static inline struct wm8350_irq_data *irq_to_wm8350_irq(struct wm8350 *wm8350, + int irq) { - mutex_lock(&wm8350->irq_mutex); - - if (wm8350->irq[irq].handler) - wm8350->irq[irq].handler(irq, wm8350->irq[irq].data); - else { - dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n", - irq); - wm8350_mask_irq(wm8350, irq); - } - - mutex_unlock(&wm8350->irq_mutex); + return &wm8350_irqs[irq - wm8350->irq_base]; } /* @@ -386,7 +375,9 @@ static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq) * interrupts are clear on read the IRQ line will be reasserted and * the physical IRQ will be handled again if another interrupt is * asserted while we run - in the normal course of events this is a - * rare occurrence so we save I2C/SPI reads. + * rare occurrence so we save I2C/SPI reads. We're also assuming that + * it's rare to get lots of interrupts firing simultaneously so try to + * minimise I/O. */ static irqreturn_t wm8350_irq(int irq, void *irq_data) { @@ -397,7 +388,6 @@ static irqreturn_t wm8350_irq(int irq, void *irq_data) struct wm8350_irq_data *data; int i; - /* TODO: Use block reads to improve performance? */ level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS) & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK); @@ -416,93 +406,101 @@ static irqreturn_t wm8350_irq(int irq, void *irq_data) sub_reg[data->reg] = wm8350_reg_read(wm8350, WM8350_INT_STATUS_1 + data->reg); - sub_reg[data->reg] &= - ~wm8350_reg_read(wm8350, - WM8350_INT_STATUS_1_MASK + - data->reg); + sub_reg[data->reg] &= ~wm8350->irq_masks[data->reg]; read_done[data->reg] = 1; } if (sub_reg[data->reg] & data->mask) - wm8350_irq_call_handler(wm8350, i); + handle_nested_irq(wm8350->irq_base + i); } return IRQ_HANDLED; } -int wm8350_register_irq(struct wm8350 *wm8350, int irq, - irq_handler_t handler, unsigned long flags, - const char *name, void *data) +static void wm8350_irq_lock(unsigned int irq) { - if (irq < 0 || irq >= WM8350_NUM_IRQ || !handler) - return -EINVAL; - - if (wm8350->irq[irq].handler) - return -EBUSY; - - mutex_lock(&wm8350->irq_mutex); - wm8350->irq[irq].handler = handler; - wm8350->irq[irq].data = data; - mutex_unlock(&wm8350->irq_mutex); - - wm8350_unmask_irq(wm8350, irq); + struct wm8350 *wm8350 = get_irq_chip_data(irq); - return 0; + mutex_lock(&wm8350->irq_lock); } -EXPORT_SYMBOL_GPL(wm8350_register_irq); -int wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data) +static void wm8350_irq_sync_unlock(unsigned int irq) { - if (irq < 0 || irq >= WM8350_NUM_IRQ) - return -EINVAL; + struct wm8350 *wm8350 = get_irq_chip_data(irq); + int i; - wm8350_mask_irq(wm8350, irq); + for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) { + /* If there's been a change in the mask write it back + * to the hardware. */ + if (wm8350->irq_masks[i] != + wm8350->reg_cache[WM8350_INT_STATUS_1_MASK + i]) + WARN_ON(wm8350_reg_write(wm8350, + WM8350_INT_STATUS_1_MASK + i, + wm8350->irq_masks[i])); + } - mutex_lock(&wm8350->irq_mutex); - wm8350->irq[irq].handler = NULL; - mutex_unlock(&wm8350->irq_mutex); - return 0; + mutex_unlock(&wm8350->irq_lock); } -EXPORT_SYMBOL_GPL(wm8350_free_irq); -int wm8350_mask_irq(struct wm8350 *wm8350, int irq) +static void wm8350_irq_enable(unsigned int irq) { - return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK + - wm8350_irqs[irq].reg, - wm8350_irqs[irq].mask); + struct wm8350 *wm8350 = get_irq_chip_data(irq); + struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq); + + wm8350->irq_masks[irq_data->reg] &= ~irq_data->mask; } -EXPORT_SYMBOL_GPL(wm8350_mask_irq); -int wm8350_unmask_irq(struct wm8350 *wm8350, int irq) +static void wm8350_irq_disable(unsigned int irq) { - return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK + - wm8350_irqs[irq].reg, - wm8350_irqs[irq].mask); + struct wm8350 *wm8350 = get_irq_chip_data(irq); + struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq); + + wm8350->irq_masks[irq_data->reg] |= irq_data->mask; } -EXPORT_SYMBOL_GPL(wm8350_unmask_irq); + +static struct irq_chip wm8350_irq_chip = { + .name = "wm8350", + .bus_lock = wm8350_irq_lock, + .bus_sync_unlock = wm8350_irq_sync_unlock, + .disable = wm8350_irq_disable, + .enable = wm8350_irq_enable, +}; int wm8350_irq_init(struct wm8350 *wm8350, int irq, struct wm8350_platform_data *pdata) { - int ret; + int ret, cur_irq, i; int flags = IRQF_ONESHOT; if (!irq) { - dev_err(wm8350->dev, "No IRQ configured\n"); - return -EINVAL; + dev_warn(wm8350->dev, "No interrupt support, no core IRQ\n"); + return 0; + } + + if (!pdata || !pdata->irq_base) { + dev_warn(wm8350->dev, "No interrupt support, no IRQ base\n"); + return 0; } + /* Mask top level interrupts */ wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF); - wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF); - wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF); - wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF); - wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF); - wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF); - mutex_init(&wm8350->irq_mutex); + /* Mask all individual interrupts by default and cache the + * masks. We read the masks back since there are unwritable + * bits in the mask registers. */ + for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) { + wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK + i, + 0xFFFF); + wm8350->irq_masks[i] = + wm8350_reg_read(wm8350, + WM8350_INT_STATUS_1_MASK + i); + } + + mutex_init(&wm8350->irq_lock); wm8350->chip_irq = irq; + wm8350->irq_base = pdata->irq_base; - if (pdata && pdata->irq_high) { + if (pdata->irq_high) { flags |= IRQF_TRIGGER_HIGH; wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1, @@ -514,11 +512,32 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq, WM8350_IRQ_POL); } + /* Register with genirq */ + for (cur_irq = wm8350->irq_base; + cur_irq < ARRAY_SIZE(wm8350_irqs) + wm8350->irq_base; + cur_irq++) { + set_irq_chip_data(cur_irq, wm8350); + set_irq_chip_and_handler(cur_irq, &wm8350_irq_chip, + handle_edge_irq); + set_irq_nested_thread(cur_irq, 1); + + /* ARM needs us to explicitly flag the IRQ as valid + * and will set them noprobe when we do so. */ +#ifdef CONFIG_ARM + set_irq_flags(cur_irq, IRQF_VALID); +#else + set_irq_noprobe(cur_irq); +#endif + } + ret = request_threaded_irq(irq, NULL, wm8350_irq, flags, "wm8350", wm8350); if (ret != 0) dev_err(wm8350->dev, "Failed to request IRQ: %d\n", ret); + /* Allow interrupts to fire */ + wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0); + return ret; } diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h index 8883125..04217a7 100644 --- a/include/linux/mfd/wm8350/core.h +++ b/include/linux/mfd/wm8350/core.h @@ -579,6 +579,8 @@ #define WM8350_NUM_IRQ 63 +#define WM8350_NUM_IRQ_REGS 7 + struct wm8350_reg_access { u16 readable; /* Mask of readable bits */ u16 writable; /* Mask of writable bits */ @@ -600,11 +602,6 @@ extern const u16 wm8352_mode3_defaults[]; struct wm8350; -struct wm8350_irq { - irq_handler_t handler; - void *data; -}; - struct wm8350_hwmon { struct platform_device *pdev; struct device *classdev; @@ -626,9 +623,10 @@ struct wm8350 { struct mutex auxadc_mutex; /* Interrupt handling */ - struct mutex irq_mutex; /* IRQ table mutex */ - struct wm8350_irq irq[WM8350_NUM_IRQ]; + struct mutex irq_lock; int chip_irq; + int irq_base; + u16 irq_masks[WM8350_NUM_IRQ_REGS]; /* Client devices */ struct wm8350_codec codec; @@ -677,13 +675,33 @@ int wm8350_block_write(struct wm8350 *wm8350, int reg, int size, u16 *src); /* * WM8350 internal interrupts */ -int wm8350_register_irq(struct wm8350 *wm8350, int irq, - irq_handler_t handler, unsigned long flags, - const char *name, void *data); -int wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data); +static inline int wm8350_register_irq(struct wm8350 *wm8350, int irq, + irq_handler_t handler, + unsigned long flags, + const char *name, void *data) +{ + if (!wm8350->irq_base) + return -ENODEV; + + return request_threaded_irq(irq + wm8350->irq_base, NULL, + handler, flags, name, data); +} + +static inline void wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data) +{ + free_irq(irq + wm8350->irq_base, data); +} + +static inline void wm8350_mask_irq(struct wm8350 *wm8350, int irq) +{ + disable_irq(irq + wm8350->irq_base); +} + +static inline void wm8350_unmask_irq(struct wm8350 *wm8350, int irq) +{ + enable_irq(irq + wm8350->irq_base); +} -int wm8350_mask_irq(struct wm8350 *wm8350, int irq); -int wm8350_unmask_irq(struct wm8350 *wm8350, int irq); int wm8350_irq_init(struct wm8350 *wm8350, int irq, struct wm8350_platform_data *pdata); int wm8350_irq_exit(struct wm8350 *wm8350); -- cgit v0.10.2 From ecf926bcda5ba1da7269dcaa71a1b6920dc48349 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 5 Jan 2010 20:40:47 +0000 Subject: mfd: Don't allow WM8350 to be built modular The genirq implementation does not allow modules to implement irq_chips so the conversion of WM8350 to genirq means we can no longer allow the driver to be built as a module. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b670d10..d957373 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -205,7 +205,7 @@ config MFD_WM831X functionality of the device. config MFD_WM8350 - tristate + bool config MFD_WM8350_CONFIG_MODE_0 bool @@ -256,9 +256,9 @@ config MFD_WM8352_CONFIG_MODE_3 depends on MFD_WM8350 config MFD_WM8350_I2C - tristate "Support Wolfson Microelectronics WM8350 with I2C" + bool "Support Wolfson Microelectronics WM8350 with I2C" select MFD_WM8350 - depends on I2C + depends on I2C=y help The WM8350 is an integrated audio and power management subsystem with watchdog and RTC functionality for embedded -- cgit v0.10.2 From 59f25070df0325067d7916b467ad15725657fedc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 6 Jan 2010 19:24:25 +0000 Subject: mfd: Update WM8350 drivers for changed interrupt numbers The headphone detect and charger are using the IRQ numbers so need to take account of irq_base with the genirq conversion. I obviously picked the wrong system for initial testing. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz diff --git a/drivers/power/wm8350_power.c b/drivers/power/wm8350_power.c index 3839a5e..0693902 100644 --- a/drivers/power/wm8350_power.c +++ b/drivers/power/wm8350_power.c @@ -190,7 +190,7 @@ static irqreturn_t wm8350_charger_handler(int irq, void *data) struct wm8350_power *power = &wm8350->power; struct wm8350_charger_policy *policy = power->policy; - switch (irq) { + switch (irq - wm8350->irq_base) { case WM8350_IRQ_CHG_BAT_FAIL: dev_err(wm8350->dev, "battery failed\n"); break; diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 079bf74..df2c6d9 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1349,7 +1349,7 @@ static irqreturn_t wm8350_hp_jack_handler(int irq, void *data) int mask; struct wm8350_jack_data *jack = NULL; - switch (irq) { + switch (irq - wm8350->irq_base) { case WM8350_IRQ_CODEC_JCK_DET_L: jack = &priv->hpl; mask = WM8350_JACK_L_LVL; @@ -1424,7 +1424,7 @@ int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which, wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena); /* Sync status */ - wm8350_hp_jack_handler(irq, priv); + wm8350_hp_jack_handler(irq + wm8350->irq_base, priv); return 0; } -- cgit v0.10.2 From 38f6ce45f0bca04ac653c57cacd375c469995321 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 7 Jan 2010 16:10:08 +0000 Subject: gpiolib: Add support for WM8350 GPIO controller Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index a4cdbd5..acac9f6 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -185,6 +185,13 @@ config GPIO_WM831X Say yes here to access the GPIO signals of WM831x power management chips from Wolfson Microelectronics. +config GPIO_WM8350 + tristate "WM8350 GPIOs" + depends on MFD_WM8350 + help + Say yes here to access the GPIO signals of WM8350 power management + chips from Wolfson Microelectronics. + config GPIO_ADP5520 tristate "GPIO Support for ADP5520 PMIC" depends on PMIC_ADP5520 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 128abf8..90b0880 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o obj-$(CONFIG_GPIO_IT8761E) += it8761e_gpio.o obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o +obj-$(CONFIG_GPIO_WM8350) += wm8350-gpiolib.o diff --git a/drivers/gpio/wm8350-gpiolib.c b/drivers/gpio/wm8350-gpiolib.c new file mode 100644 index 0000000..511840d --- /dev/null +++ b/drivers/gpio/wm8350-gpiolib.c @@ -0,0 +1,181 @@ +/* + * wm835x-gpiolib.c -- gpiolib support for Wolfson WM835x PMICs + * + * Copyright 2009 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +struct wm8350_gpio_data { + struct wm8350 *wm8350; + struct gpio_chip gpio_chip; +}; + +static inline struct wm8350_gpio_data *to_wm8350_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct wm8350_gpio_data, gpio_chip); +} + +static int wm8350_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip); + struct wm8350 *wm8350 = wm8350_gpio->wm8350; + + return wm8350_set_bits(wm8350, WM8350_GPIO_CONFIGURATION_I_O, + 1 << offset); +} + +static int wm8350_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip); + struct wm8350 *wm8350 = wm8350_gpio->wm8350; + int ret; + + ret = wm8350_reg_read(wm8350, WM8350_GPIO_LEVEL); + if (ret < 0) + return ret; + + if (ret & (1 << offset)) + return 1; + else + return 0; +} + +static void wm8350_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip); + struct wm8350 *wm8350 = wm8350_gpio->wm8350; + + if (value) + wm8350_set_bits(wm8350, WM8350_GPIO_LEVEL, 1 << offset); + else + wm8350_clear_bits(wm8350, WM8350_GPIO_LEVEL, 1 << offset); +} + +static int wm8350_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip); + struct wm8350 *wm8350 = wm8350_gpio->wm8350; + int ret; + + ret = wm8350_clear_bits(wm8350, WM8350_GPIO_CONFIGURATION_I_O, + 1 << offset); + if (ret < 0) + return ret; + + /* Don't have an atomic direction/value setup */ + wm8350_gpio_set(chip, offset, value); + + return 0; +} + +static int wm8350_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct wm8350_gpio_data *wm8350_gpio = to_wm8350_gpio(chip); + struct wm8350 *wm8350 = wm8350_gpio->wm8350; + + if (!wm8350->irq_base) + return -EINVAL; + + return wm8350->irq_base + WM8350_IRQ_GPIO(offset); +} + +static struct gpio_chip template_chip = { + .label = "wm8350", + .owner = THIS_MODULE, + .direction_input = wm8350_gpio_direction_in, + .get = wm8350_gpio_get, + .direction_output = wm8350_gpio_direction_out, + .set = wm8350_gpio_set, + .to_irq = wm8350_gpio_to_irq, + .can_sleep = 1, +}; + +static int __devinit wm8350_gpio_probe(struct platform_device *pdev) +{ + struct wm8350 *wm8350 = dev_get_drvdata(pdev->dev.parent); + struct wm8350_platform_data *pdata = wm8350->dev->platform_data; + struct wm8350_gpio_data *wm8350_gpio; + int ret; + + wm8350_gpio = kzalloc(sizeof(*wm8350_gpio), GFP_KERNEL); + if (wm8350_gpio == NULL) + return -ENOMEM; + + wm8350_gpio->wm8350 = wm8350; + wm8350_gpio->gpio_chip = template_chip; + wm8350_gpio->gpio_chip.ngpio = 13; + wm8350_gpio->gpio_chip.dev = &pdev->dev; + if (pdata && pdata->gpio_base) + wm8350_gpio->gpio_chip.base = pdata->gpio_base; + else + wm8350_gpio->gpio_chip.base = -1; + + ret = gpiochip_add(&wm8350_gpio->gpio_chip); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", + ret); + goto err; + } + + platform_set_drvdata(pdev, wm8350_gpio); + + return ret; + +err: + kfree(wm8350_gpio); + return ret; +} + +static int __devexit wm8350_gpio_remove(struct platform_device *pdev) +{ + struct wm8350_gpio_data *wm8350_gpio = platform_get_drvdata(pdev); + int ret; + + ret = gpiochip_remove(&wm8350_gpio->gpio_chip); + if (ret == 0) + kfree(wm8350_gpio); + + return ret; +} + +static struct platform_driver wm8350_gpio_driver = { + .driver.name = "wm8350-gpio", + .driver.owner = THIS_MODULE, + .probe = wm8350_gpio_probe, + .remove = __devexit_p(wm8350_gpio_remove), +}; + +static int __init wm8350_gpio_init(void) +{ + return platform_driver_register(&wm8350_gpio_driver); +} +subsys_initcall(wm8350_gpio_init); + +static void __exit wm8350_gpio_exit(void) +{ + platform_driver_unregister(&wm8350_gpio_driver); +} +module_exit(wm8350_gpio_exit); + +MODULE_AUTHOR("Mark Brown "); +MODULE_DESCRIPTION("GPIO interface for WM8350 PMICs"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:wm8350-gpio"); diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h index 04217a7..fae08aa 100644 --- a/include/linux/mfd/wm8350/core.h +++ b/include/linux/mfd/wm8350/core.h @@ -645,11 +645,13 @@ struct wm8350 { * used by the platform to configure GPIO functions and similar. * @irq_high: Set if WM8350 IRQ is active high. * @irq_base: Base IRQ for genirq (not currently used). + * @gpio_base: Base for gpiolib. */ struct wm8350_platform_data { int (*init)(struct wm8350 *wm8350); int irq_high; int irq_base; + int gpio_base; }; diff --git a/include/linux/mfd/wm8350/gpio.h b/include/linux/mfd/wm8350/gpio.h index 71af3d6..d657bcd 100644 --- a/include/linux/mfd/wm8350/gpio.h +++ b/include/linux/mfd/wm8350/gpio.h @@ -29,6 +29,7 @@ #define WM8350_GPIO_FUNCTION_SELECT_2 0x8D #define WM8350_GPIO_FUNCTION_SELECT_3 0x8E #define WM8350_GPIO_FUNCTION_SELECT_4 0x8F +#define WM8350_GPIO_LEVEL 0xE6 /* * GPIO Functions -- cgit v0.10.2 From 0df883df8e8aea79b501f6262b595e66dec175dc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 8 Jan 2010 10:44:16 +0100 Subject: mfd: Convert AB3100 driver to threaded IRQ This converts the AB3100 core MFD driver to use a threaded interrupt handler instead of the explicit top/bottom-half construction with a workqueue. This saves some code and make it more similar to other modern MFD drivers. Signed-off-by: Linus Walleij Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index fd42a80..aa3824a 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -365,10 +365,13 @@ int ab3100_event_registers_startup_state_get(struct ab3100 *ab3100, } EXPORT_SYMBOL(ab3100_event_registers_startup_state_get); -/* Interrupt handling worker */ -static void ab3100_work(struct work_struct *work) +/* + * This is a threaded interrupt handler so we can make some + * I2C calls etc. + */ +static irqreturn_t ab3100_irq_handler(int irq, void *data) { - struct ab3100 *ab3100 = container_of(work, struct ab3100, work); + struct ab3100 *ab3100 = data; u8 event_regs[3]; u32 fatevent; int err; @@ -376,7 +379,7 @@ static void ab3100_work(struct work_struct *work) err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1, event_regs, 3); if (err) - goto err_event_wq; + goto err_event; fatevent = (event_regs[0] << 16) | (event_regs[1] << 8) | @@ -398,29 +401,11 @@ static void ab3100_work(struct work_struct *work) dev_dbg(ab3100->dev, "IRQ Event: 0x%08x\n", fatevent); - /* By now the IRQ should be acked and deasserted so enable it again */ - enable_irq(ab3100->i2c_client->irq); - return; + return IRQ_HANDLED; - err_event_wq: + err_event: dev_dbg(ab3100->dev, - "error in event workqueue\n"); - /* Enable the IRQ anyway, what choice do we have? */ - enable_irq(ab3100->i2c_client->irq); - return; -} - -static irqreturn_t ab3100_irq_handler(int irq, void *data) -{ - struct ab3100 *ab3100 = data; - /* - * Disable the IRQ and dispatch a worker to handle the - * event. Since the chip resides on I2C this is slow - * stuff and we will re-enable the interrupts once th - * worker has finished. - */ - disable_irq_nosync(irq); - schedule_work(&ab3100->work); + "error reading event status\n"); return IRQ_HANDLED; } @@ -904,12 +889,10 @@ static int __init ab3100_probe(struct i2c_client *client, if (err) goto exit_no_setup; - INIT_WORK(&ab3100->work, ab3100_work); - /* This real unpredictable IRQ is of course sampled for entropy */ - err = request_irq(client->irq, ab3100_irq_handler, - IRQF_DISABLED | IRQF_SAMPLE_RANDOM, - "AB3100 IRQ", ab3100); + err = request_threaded_irq(client->irq, NULL, ab3100_irq_handler, + IRQF_ONESHOT, + "ab3100-core", ab3100); if (err) goto exit_no_irq; diff --git a/include/linux/mfd/ab3100.h b/include/linux/mfd/ab3100.h index e9aa4c9..9a881c3 100644 --- a/include/linux/mfd/ab3100.h +++ b/include/linux/mfd/ab3100.h @@ -6,7 +6,6 @@ */ #include -#include #include #ifndef MFD_AB3100_H @@ -74,7 +73,6 @@ * @testreg_client: secondary client for test registers * @chip_name: name of this chip variant * @chip_id: 8 bit chip ID for this chip variant - * @work: an event handling worker * @event_subscribers: event subscribers are listed here * @startup_events: a copy of the first reading of the event registers * @startup_events_read: whether the first events have been read @@ -90,7 +88,6 @@ struct ab3100 { struct i2c_client *testreg_client; char chip_name[32]; u8 chip_id; - struct work_struct work; struct blocking_notifier_head event_subscribers; u32 startup_events; bool startup_events_read; -- cgit v0.10.2 From bbd51b1ff1bf57b9ed7f062486a415509968d4d9 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 6 Jan 2010 17:04:18 -0500 Subject: mfd: Split 88pm8607 driver Create 88pm8607-i2c driver to support all I2C operation of 88PM8607. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/88pm8607.c b/drivers/mfd/88pm8607.c deleted file mode 100644 index 7e3f659..0000000 --- a/drivers/mfd/88pm8607.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Base driver for Marvell 88PM8607 - * - * Copyright (C) 2009 Marvell International Ltd. - * Haojian Zhuang - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include - - -#define PM8607_REG_RESOURCE(_start, _end) \ -{ \ - .start = PM8607_##_start, \ - .end = PM8607_##_end, \ - .flags = IORESOURCE_IO, \ -} - -static struct resource pm8607_regulator_resources[] = { - PM8607_REG_RESOURCE(BUCK1, BUCK1), - PM8607_REG_RESOURCE(BUCK2, BUCK2), - PM8607_REG_RESOURCE(BUCK3, BUCK3), - PM8607_REG_RESOURCE(LDO1, LDO1), - PM8607_REG_RESOURCE(LDO2, LDO2), - PM8607_REG_RESOURCE(LDO3, LDO3), - PM8607_REG_RESOURCE(LDO4, LDO4), - PM8607_REG_RESOURCE(LDO5, LDO5), - PM8607_REG_RESOURCE(LDO6, LDO6), - PM8607_REG_RESOURCE(LDO7, LDO7), - PM8607_REG_RESOURCE(LDO8, LDO8), - PM8607_REG_RESOURCE(LDO9, LDO9), - PM8607_REG_RESOURCE(LDO10, LDO10), - PM8607_REG_RESOURCE(LDO12, LDO12), - PM8607_REG_RESOURCE(LDO14, LDO14), -}; - -#define PM8607_REG_DEVS(_name, _id) \ -{ \ - .name = "88pm8607-" #_name, \ - .num_resources = 1, \ - .resources = &pm8607_regulator_resources[PM8607_ID_##_id], \ -} - -static struct mfd_cell pm8607_devs[] = { - PM8607_REG_DEVS(buck1, BUCK1), - PM8607_REG_DEVS(buck2, BUCK2), - PM8607_REG_DEVS(buck3, BUCK3), - PM8607_REG_DEVS(ldo1, LDO1), - PM8607_REG_DEVS(ldo2, LDO2), - PM8607_REG_DEVS(ldo3, LDO3), - PM8607_REG_DEVS(ldo4, LDO4), - PM8607_REG_DEVS(ldo5, LDO5), - PM8607_REG_DEVS(ldo6, LDO6), - PM8607_REG_DEVS(ldo7, LDO7), - PM8607_REG_DEVS(ldo8, LDO8), - PM8607_REG_DEVS(ldo9, LDO9), - PM8607_REG_DEVS(ldo10, LDO10), - PM8607_REG_DEVS(ldo12, LDO12), - PM8607_REG_DEVS(ldo14, LDO14), -}; - -static inline int pm8607_read_device(struct pm8607_chip *chip, - int reg, int bytes, void *dest) -{ - struct i2c_client *i2c = chip->client; - unsigned char data; - int ret; - - data = (unsigned char)reg; - ret = i2c_master_send(i2c, &data, 1); - if (ret < 0) - return ret; - - ret = i2c_master_recv(i2c, dest, bytes); - if (ret < 0) - return ret; - return 0; -} - -static inline int pm8607_write_device(struct pm8607_chip *chip, - int reg, int bytes, void *src) -{ - struct i2c_client *i2c = chip->client; - unsigned char buf[bytes + 1]; - int ret; - - buf[0] = (unsigned char)reg; - memcpy(&buf[1], src, bytes); - - ret = i2c_master_send(i2c, buf, bytes + 1); - if (ret < 0) - return ret; - return 0; -} - -int pm8607_reg_read(struct pm8607_chip *chip, int reg) -{ - unsigned char data; - int ret; - - mutex_lock(&chip->io_lock); - ret = chip->read(chip, reg, 1, &data); - mutex_unlock(&chip->io_lock); - - if (ret < 0) - return ret; - else - return (int)data; -} -EXPORT_SYMBOL(pm8607_reg_read); - -int pm8607_reg_write(struct pm8607_chip *chip, int reg, - unsigned char data) -{ - int ret; - - mutex_lock(&chip->io_lock); - ret = chip->write(chip, reg, 1, &data); - mutex_unlock(&chip->io_lock); - - return ret; -} -EXPORT_SYMBOL(pm8607_reg_write); - -int pm8607_bulk_read(struct pm8607_chip *chip, int reg, - int count, unsigned char *buf) -{ - int ret; - - mutex_lock(&chip->io_lock); - ret = chip->read(chip, reg, count, buf); - mutex_unlock(&chip->io_lock); - - return ret; -} -EXPORT_SYMBOL(pm8607_bulk_read); - -int pm8607_bulk_write(struct pm8607_chip *chip, int reg, - int count, unsigned char *buf) -{ - int ret; - - mutex_lock(&chip->io_lock); - ret = chip->write(chip, reg, count, buf); - mutex_unlock(&chip->io_lock); - - return ret; -} -EXPORT_SYMBOL(pm8607_bulk_write); - -int pm8607_set_bits(struct pm8607_chip *chip, int reg, - unsigned char mask, unsigned char data) -{ - unsigned char value; - int ret; - - mutex_lock(&chip->io_lock); - ret = chip->read(chip, reg, 1, &value); - if (ret < 0) - goto out; - value &= ~mask; - value |= data; - ret = chip->write(chip, reg, 1, &value); -out: - mutex_unlock(&chip->io_lock); - return ret; -} -EXPORT_SYMBOL(pm8607_set_bits); - - -static const struct i2c_device_id pm8607_id_table[] = { - { "88PM8607", 0 }, - {} -}; -MODULE_DEVICE_TABLE(i2c, pm8607_id_table); - - -static int __devinit pm8607_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct pm8607_platform_data *pdata = client->dev.platform_data; - struct pm8607_chip *chip; - int i, count; - int ret; - - chip = kzalloc(sizeof(struct pm8607_chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; - - chip->client = client; - chip->dev = &client->dev; - chip->read = pm8607_read_device; - chip->write = pm8607_write_device; - i2c_set_clientdata(client, chip); - - mutex_init(&chip->io_lock); - dev_set_drvdata(chip->dev, chip); - - ret = pm8607_reg_read(chip, PM8607_CHIP_ID); - if (ret < 0) { - dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret); - goto out; - } - if ((ret & CHIP_ID_MASK) == CHIP_ID) - dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n", - ret); - else { - dev_err(chip->dev, "Failed to detect Marvell 88PM8607. " - "Chip ID: %02x\n", ret); - goto out; - } - chip->chip_id = ret; - - ret = pm8607_reg_read(chip, PM8607_BUCK3); - if (ret < 0) { - dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret); - goto out; - } - if (ret & PM8607_BUCK3_DOUBLE) - chip->buck3_double = 1; - - ret = pm8607_reg_read(chip, PM8607_MISC1); - if (ret < 0) { - dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret); - goto out; - } - if (pdata->i2c_port == PI2C_PORT) - ret |= PM8607_MISC1_PI2C; - else - ret &= ~PM8607_MISC1_PI2C; - ret = pm8607_reg_write(chip, PM8607_MISC1, ret); - if (ret < 0) { - dev_err(chip->dev, "Failed to write MISC1 register: %d\n", ret); - goto out; - } - - - count = ARRAY_SIZE(pm8607_devs); - for (i = 0; i < count; i++) { - ret = mfd_add_devices(chip->dev, i, &pm8607_devs[i], - 1, NULL, 0); - if (ret != 0) { - dev_err(chip->dev, "Failed to add subdevs\n"); - goto out; - } - } - - return 0; - -out: - i2c_set_clientdata(client, NULL); - kfree(chip); - return ret; -} - -static int __devexit pm8607_remove(struct i2c_client *client) -{ - struct pm8607_chip *chip = i2c_get_clientdata(client); - - mfd_remove_devices(chip->dev); - kfree(chip); - return 0; -} - -static struct i2c_driver pm8607_driver = { - .driver = { - .name = "88PM8607", - .owner = THIS_MODULE, - }, - .probe = pm8607_probe, - .remove = __devexit_p(pm8607_remove), - .id_table = pm8607_id_table, -}; - -static int __init pm8607_init(void) -{ - int ret; - ret = i2c_add_driver(&pm8607_driver); - if (ret != 0) - pr_err("Failed to register 88PM8607 I2C driver: %d\n", ret); - return ret; -} -subsys_initcall(pm8607_init); - -static void __exit pm8607_exit(void) -{ - i2c_del_driver(&pm8607_driver); -} -module_exit(pm8607_exit); - -MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM8607"); -MODULE_AUTHOR("Haojian Zhuang "); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c new file mode 100644 index 0000000..d1464e5 --- /dev/null +++ b/drivers/mfd/88pm860x-core.c @@ -0,0 +1,134 @@ +/* + * Base driver for Marvell 88PM8607 + * + * Copyright (C) 2009 Marvell International Ltd. + * Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + + +#define PM8607_REG_RESOURCE(_start, _end) \ +{ \ + .start = PM8607_##_start, \ + .end = PM8607_##_end, \ + .flags = IORESOURCE_IO, \ +} + +static struct resource pm8607_regulator_resources[] = { + PM8607_REG_RESOURCE(BUCK1, BUCK1), + PM8607_REG_RESOURCE(BUCK2, BUCK2), + PM8607_REG_RESOURCE(BUCK3, BUCK3), + PM8607_REG_RESOURCE(LDO1, LDO1), + PM8607_REG_RESOURCE(LDO2, LDO2), + PM8607_REG_RESOURCE(LDO3, LDO3), + PM8607_REG_RESOURCE(LDO4, LDO4), + PM8607_REG_RESOURCE(LDO5, LDO5), + PM8607_REG_RESOURCE(LDO6, LDO6), + PM8607_REG_RESOURCE(LDO7, LDO7), + PM8607_REG_RESOURCE(LDO8, LDO8), + PM8607_REG_RESOURCE(LDO9, LDO9), + PM8607_REG_RESOURCE(LDO10, LDO10), + PM8607_REG_RESOURCE(LDO12, LDO12), + PM8607_REG_RESOURCE(LDO14, LDO14), +}; + +#define PM8607_REG_DEVS(_name, _id) \ +{ \ + .name = "88pm8607-" #_name, \ + .num_resources = 1, \ + .resources = &pm8607_regulator_resources[PM8607_ID_##_id], \ +} + +static struct mfd_cell pm8607_devs[] = { + PM8607_REG_DEVS(buck1, BUCK1), + PM8607_REG_DEVS(buck2, BUCK2), + PM8607_REG_DEVS(buck3, BUCK3), + PM8607_REG_DEVS(ldo1, LDO1), + PM8607_REG_DEVS(ldo2, LDO2), + PM8607_REG_DEVS(ldo3, LDO3), + PM8607_REG_DEVS(ldo4, LDO4), + PM8607_REG_DEVS(ldo5, LDO5), + PM8607_REG_DEVS(ldo6, LDO6), + PM8607_REG_DEVS(ldo7, LDO7), + PM8607_REG_DEVS(ldo8, LDO8), + PM8607_REG_DEVS(ldo9, LDO9), + PM8607_REG_DEVS(ldo10, LDO10), + PM8607_REG_DEVS(ldo12, LDO12), + PM8607_REG_DEVS(ldo14, LDO14), +}; + +int pm860x_device_init(struct pm8607_chip *chip, + struct pm8607_platform_data *pdata) +{ + int i, count; + int ret; + + ret = pm8607_reg_read(chip, PM8607_CHIP_ID); + if (ret < 0) { + dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret); + goto out; + } + if ((ret & PM8607_ID_MASK) == PM8607_ID) + dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n", + ret); + else { + dev_err(chip->dev, "Failed to detect Marvell 88PM8607. " + "Chip ID: %02x\n", ret); + goto out; + } + chip->chip_id = ret; + + ret = pm8607_reg_read(chip, PM8607_BUCK3); + if (ret < 0) { + dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret); + goto out; + } + if (ret & PM8607_BUCK3_DOUBLE) + chip->buck3_double = 1; + + ret = pm8607_reg_read(chip, PM8607_MISC1); + if (ret < 0) { + dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret); + goto out; + } + if (pdata->i2c_port == PI2C_PORT) + ret |= PM8607_MISC1_PI2C; + else + ret &= ~PM8607_MISC1_PI2C; + ret = pm8607_reg_write(chip, PM8607_MISC1, ret); + if (ret < 0) { + dev_err(chip->dev, "Failed to write MISC1 register: %d\n", ret); + goto out; + } + + count = ARRAY_SIZE(pm8607_devs); + for (i = 0; i < count; i++) { + ret = mfd_add_devices(chip->dev, i, &pm8607_devs[i], + 1, NULL, 0); + if (ret != 0) { + dev_err(chip->dev, "Failed to add subdevs\n"); + goto out; + } + } +out: + return ret; +} + +void pm8607_device_exit(struct pm8607_chip *chip) +{ + mfd_remove_devices(chip->dev); +} + +MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM8607"); +MODULE_AUTHOR("Haojian Zhuang "); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c new file mode 100644 index 0000000..dda23cb --- /dev/null +++ b/drivers/mfd/88pm860x-i2c.c @@ -0,0 +1,202 @@ +/* + * I2C driver for Marvell 88PM8607 + * + * Copyright (C) 2009 Marvell International Ltd. + * Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include + +static inline int pm8607_read_device(struct pm8607_chip *chip, + int reg, int bytes, void *dest) +{ + struct i2c_client *i2c = chip->client; + unsigned char data; + int ret; + + data = (unsigned char)reg; + ret = i2c_master_send(i2c, &data, 1); + if (ret < 0) + return ret; + + ret = i2c_master_recv(i2c, dest, bytes); + if (ret < 0) + return ret; + return 0; +} + +static inline int pm8607_write_device(struct pm8607_chip *chip, + int reg, int bytes, void *src) +{ + struct i2c_client *i2c = chip->client; + unsigned char buf[bytes + 1]; + int ret; + + buf[0] = (unsigned char)reg; + memcpy(&buf[1], src, bytes); + + ret = i2c_master_send(i2c, buf, bytes + 1); + if (ret < 0) + return ret; + return 0; +} + +int pm8607_reg_read(struct pm8607_chip *chip, int reg) +{ + unsigned char data; + int ret; + + mutex_lock(&chip->io_lock); + ret = chip->read(chip, reg, 1, &data); + mutex_unlock(&chip->io_lock); + + if (ret < 0) + return ret; + else + return (int)data; +} +EXPORT_SYMBOL(pm8607_reg_read); + +int pm8607_reg_write(struct pm8607_chip *chip, int reg, + unsigned char data) +{ + int ret; + + mutex_lock(&chip->io_lock); + ret = chip->write(chip, reg, 1, &data); + mutex_unlock(&chip->io_lock); + + return ret; +} +EXPORT_SYMBOL(pm8607_reg_write); + +int pm8607_bulk_read(struct pm8607_chip *chip, int reg, + int count, unsigned char *buf) +{ + int ret; + + mutex_lock(&chip->io_lock); + ret = chip->read(chip, reg, count, buf); + mutex_unlock(&chip->io_lock); + + return ret; +} +EXPORT_SYMBOL(pm8607_bulk_read); + +int pm8607_bulk_write(struct pm8607_chip *chip, int reg, + int count, unsigned char *buf) +{ + int ret; + + mutex_lock(&chip->io_lock); + ret = chip->write(chip, reg, count, buf); + mutex_unlock(&chip->io_lock); + + return ret; +} +EXPORT_SYMBOL(pm8607_bulk_write); + +int pm8607_set_bits(struct pm8607_chip *chip, int reg, + unsigned char mask, unsigned char data) +{ + unsigned char value; + int ret; + + mutex_lock(&chip->io_lock); + ret = chip->read(chip, reg, 1, &value); + if (ret < 0) + goto out; + value &= ~mask; + value |= data; + ret = chip->write(chip, reg, 1, &value); +out: + mutex_unlock(&chip->io_lock); + return ret; +} +EXPORT_SYMBOL(pm8607_set_bits); + + +static const struct i2c_device_id pm860x_id_table[] = { + { "88PM8607", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, pm860x_id_table); + +static int __devinit pm860x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pm8607_platform_data *pdata = client->dev.platform_data; + struct pm8607_chip *chip; + int ret; + + chip = kzalloc(sizeof(struct pm8607_chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + chip->client = client; + chip->dev = &client->dev; + chip->read = pm8607_read_device; + chip->write = pm8607_write_device; + memcpy(&chip->id, id, sizeof(struct i2c_device_id)); + i2c_set_clientdata(client, chip); + + mutex_init(&chip->io_lock); + dev_set_drvdata(chip->dev, chip); + + ret = pm860x_device_init(chip, pdata); + if (ret < 0) + goto out; + + + return 0; + +out: + i2c_set_clientdata(client, NULL); + kfree(chip); + return ret; +} + +static int __devexit pm860x_remove(struct i2c_client *client) +{ + struct pm8607_chip *chip = i2c_get_clientdata(client); + + kfree(chip); + return 0; +} + +static struct i2c_driver pm860x_driver = { + .driver = { + .name = "88PM860x", + .owner = THIS_MODULE, + }, + .probe = pm860x_probe, + .remove = __devexit_p(pm860x_remove), + .id_table = pm860x_id_table, +}; + +static int __init pm860x_i2c_init(void) +{ + int ret; + ret = i2c_add_driver(&pm860x_driver); + if (ret != 0) + pr_err("Failed to register 88PM860x I2C driver: %d\n", ret); + return ret; +} +subsys_initcall(pm860x_i2c_init); + +static void __exit pm860x_i2c_exit(void) +{ + i2c_del_driver(&pm860x_driver); +} +module_exit(pm860x_i2c_exit); + +MODULE_DESCRIPTION("I2C Driver for Marvell 88PM860x"); +MODULE_AUTHOR("Haojian Zhuang "); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 78295d6..88fa200 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -2,6 +2,7 @@ # Makefile for multifunction miscellaneous devices # +obj-$(CONFIG_MFD_88PM8607) += 88pm860x-core.o 88pm860x-i2c.o obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o obj-$(CONFIG_MFD_SH_MOBILE_SDHI) += sh_mobile_sdhi.o @@ -55,5 +56,4 @@ obj-$(CONFIG_AB3100_CORE) += ab3100-core.o obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o obj-$(CONFIG_AB4500_CORE) += ab4500-core.o obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o -obj-$(CONFIG_MFD_88PM8607) += 88pm8607.o obj-$(CONFIG_PMIC_ADP5520) += adp5520.o diff --git a/include/linux/mfd/88pm8607.h b/include/linux/mfd/88pm8607.h index f41b428..6e4dcdc 100644 --- a/include/linux/mfd/88pm8607.h +++ b/include/linux/mfd/88pm8607.h @@ -33,8 +33,8 @@ enum { PM8607_ID_RG_MAX, }; -#define CHIP_ID (0x40) -#define CHIP_ID_MASK (0xF8) +#define PM8607_ID (0x40) /* 8607 chip ID */ +#define PM8607_ID_MASK (0xF8) /* 8607 chip ID mask */ /* Interrupt Registers */ #define PM8607_STATUS_1 (0x01) @@ -185,6 +185,7 @@ struct pm8607_chip { struct device *dev; struct mutex io_lock; struct i2c_client *client; + struct i2c_device_id id; int (*read)(struct pm8607_chip *chip, int reg, int bytes, void *dest); int (*write)(struct pm8607_chip *chip, int reg, int bytes, void *src); @@ -214,4 +215,9 @@ extern int pm8607_bulk_write(struct pm8607_chip *, int, int, unsigned char *); extern int pm8607_set_bits(struct pm8607_chip *, int, unsigned char, unsigned char); -#endif /* __LINUX_MFD_88PM8607_H */ + +extern int pm860x_device_init(struct pm8607_chip *chip, + struct pm8607_platform_data *pdata); +extern void pm860x_device_exit(struct pm8607_chip *chip); + +#endif /* __LINUX_MFD_88PM860X_H */ -- cgit v0.10.2 From 53dbab7af9ca13fa95605e9a5c31bb803dcba363 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 8 Jan 2010 06:01:24 -0500 Subject: mfd: Support 88pm8606 in 860x driver 88PM8606 and 88PM8607 are two discrete chips used for power management. Hardware designer can use them together or only one of them according to requirement. There's some logic tightly linked between these two chips. For example, USB charger driver needs to access both chips by I2C interface. Now share one driver to these two devices. Only one I2C client is identified in platform init data. If another chip is also used, user should mark it in companion_addr field of platform init data. Then driver could create another I2C client for the companion chip. All I2C operations are accessed by 860x-i2c driver. In order to support both I2C client address, the read/write API is changed in below. reg_read(client, offset) reg_write(client, offset, data) The benefit is that client drivers only need one kind of read/write API. I2C and MFD driver can be shared in both 8606 and 8607. Since API is changed, update API in 8607 regulator driver. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index d1464e5..72b0030 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #define PM8607_REG_RESOURCE(_start, _end) \ @@ -67,18 +67,23 @@ static struct mfd_cell pm8607_devs[] = { PM8607_REG_DEVS(ldo14, LDO14), }; -int pm860x_device_init(struct pm8607_chip *chip, - struct pm8607_platform_data *pdata) +static void device_8606_init(struct pm860x_chip *chip, struct i2c_client *i2c, + struct pm860x_platform_data *pdata) +{ +} + +static void device_8607_init(struct pm860x_chip *chip, struct i2c_client *i2c, + struct pm860x_platform_data *pdata) { int i, count; int ret; - ret = pm8607_reg_read(chip, PM8607_CHIP_ID); + ret = pm860x_reg_read(i2c, PM8607_CHIP_ID); if (ret < 0) { dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret); goto out; } - if ((ret & PM8607_ID_MASK) == PM8607_ID) + if ((ret & PM8607_VERSION_MASK) == PM8607_VERSION) dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n", ret); else { @@ -86,9 +91,9 @@ int pm860x_device_init(struct pm8607_chip *chip, "Chip ID: %02x\n", ret); goto out; } - chip->chip_id = ret; + chip->chip_version = ret; - ret = pm8607_reg_read(chip, PM8607_BUCK3); + ret = pm860x_reg_read(i2c, PM8607_BUCK3); if (ret < 0) { dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret); goto out; @@ -96,20 +101,11 @@ int pm860x_device_init(struct pm8607_chip *chip, if (ret & PM8607_BUCK3_DOUBLE) chip->buck3_double = 1; - ret = pm8607_reg_read(chip, PM8607_MISC1); + ret = pm860x_reg_read(i2c, PM8607_MISC1); if (ret < 0) { dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret); goto out; } - if (pdata->i2c_port == PI2C_PORT) - ret |= PM8607_MISC1_PI2C; - else - ret &= ~PM8607_MISC1_PI2C; - ret = pm8607_reg_write(chip, PM8607_MISC1, ret); - if (ret < 0) { - dev_err(chip->dev, "Failed to write MISC1 register: %d\n", ret); - goto out; - } count = ARRAY_SIZE(pm8607_devs); for (i = 0; i < count; i++) { @@ -121,14 +117,39 @@ int pm860x_device_init(struct pm8607_chip *chip, } } out: - return ret; + return; +} + +int pm860x_device_init(struct pm860x_chip *chip, + struct pm860x_platform_data *pdata) +{ + switch (chip->id) { + case CHIP_PM8606: + device_8606_init(chip, chip->client, pdata); + break; + case CHIP_PM8607: + device_8607_init(chip, chip->client, pdata); + break; + } + + if (chip->companion) { + switch (chip->id) { + case CHIP_PM8607: + device_8606_init(chip, chip->companion, pdata); + break; + case CHIP_PM8606: + device_8607_init(chip, chip->companion, pdata); + break; + } + } + return 0; } -void pm8607_device_exit(struct pm8607_chip *chip) +void pm860x_device_exit(struct pm860x_chip *chip) { mfd_remove_devices(chip->dev); } -MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM8607"); +MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x"); MODULE_AUTHOR("Haojian Zhuang "); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index dda23cb..6d7dba2 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c @@ -1,5 +1,5 @@ /* - * I2C driver for Marvell 88PM8607 + * I2C driver for Marvell 88PM860x * * Copyright (C) 2009 Marvell International Ltd. * Haojian Zhuang @@ -12,12 +12,11 @@ #include #include #include -#include +#include -static inline int pm8607_read_device(struct pm8607_chip *chip, +static inline int pm860x_read_device(struct i2c_client *i2c, int reg, int bytes, void *dest) { - struct i2c_client *i2c = chip->client; unsigned char data; int ret; @@ -32,10 +31,9 @@ static inline int pm8607_read_device(struct pm8607_chip *chip, return 0; } -static inline int pm8607_write_device(struct pm8607_chip *chip, +static inline int pm860x_write_device(struct i2c_client *i2c, int reg, int bytes, void *src) { - struct i2c_client *i2c = chip->client; unsigned char buf[bytes + 1]; int ret; @@ -48,13 +46,14 @@ static inline int pm8607_write_device(struct pm8607_chip *chip, return 0; } -int pm8607_reg_read(struct pm8607_chip *chip, int reg) +int pm860x_reg_read(struct i2c_client *i2c, int reg) { + struct pm860x_chip *chip = i2c_get_clientdata(i2c); unsigned char data; int ret; mutex_lock(&chip->io_lock); - ret = chip->read(chip, reg, 1, &data); + ret = pm860x_read_device(i2c, reg, 1, &data); mutex_unlock(&chip->io_lock); if (ret < 0) @@ -62,111 +61,178 @@ int pm8607_reg_read(struct pm8607_chip *chip, int reg) else return (int)data; } -EXPORT_SYMBOL(pm8607_reg_read); +EXPORT_SYMBOL(pm860x_reg_read); -int pm8607_reg_write(struct pm8607_chip *chip, int reg, +int pm860x_reg_write(struct i2c_client *i2c, int reg, unsigned char data) { + struct pm860x_chip *chip = i2c_get_clientdata(i2c); int ret; mutex_lock(&chip->io_lock); - ret = chip->write(chip, reg, 1, &data); + ret = pm860x_write_device(i2c, reg, 1, &data); mutex_unlock(&chip->io_lock); return ret; } -EXPORT_SYMBOL(pm8607_reg_write); +EXPORT_SYMBOL(pm860x_reg_write); -int pm8607_bulk_read(struct pm8607_chip *chip, int reg, +int pm860x_bulk_read(struct i2c_client *i2c, int reg, int count, unsigned char *buf) { + struct pm860x_chip *chip = i2c_get_clientdata(i2c); int ret; mutex_lock(&chip->io_lock); - ret = chip->read(chip, reg, count, buf); + ret = pm860x_read_device(i2c, reg, count, buf); mutex_unlock(&chip->io_lock); return ret; } -EXPORT_SYMBOL(pm8607_bulk_read); +EXPORT_SYMBOL(pm860x_bulk_read); -int pm8607_bulk_write(struct pm8607_chip *chip, int reg, +int pm860x_bulk_write(struct i2c_client *i2c, int reg, int count, unsigned char *buf) { + struct pm860x_chip *chip = i2c_get_clientdata(i2c); int ret; mutex_lock(&chip->io_lock); - ret = chip->write(chip, reg, count, buf); + ret = pm860x_write_device(i2c, reg, count, buf); mutex_unlock(&chip->io_lock); return ret; } -EXPORT_SYMBOL(pm8607_bulk_write); +EXPORT_SYMBOL(pm860x_bulk_write); -int pm8607_set_bits(struct pm8607_chip *chip, int reg, +int pm860x_set_bits(struct i2c_client *i2c, int reg, unsigned char mask, unsigned char data) { + struct pm860x_chip *chip = i2c_get_clientdata(i2c); unsigned char value; int ret; mutex_lock(&chip->io_lock); - ret = chip->read(chip, reg, 1, &value); + ret = pm860x_read_device(i2c, reg, 1, &value); if (ret < 0) goto out; value &= ~mask; value |= data; - ret = chip->write(chip, reg, 1, &value); + ret = pm860x_write_device(i2c, reg, 1, &value); out: mutex_unlock(&chip->io_lock); return ret; } -EXPORT_SYMBOL(pm8607_set_bits); +EXPORT_SYMBOL(pm860x_set_bits); static const struct i2c_device_id pm860x_id_table[] = { - { "88PM8607", 0 }, + { "88PM860x", 0 }, {} }; MODULE_DEVICE_TABLE(i2c, pm860x_id_table); +static int verify_addr(struct i2c_client *i2c) +{ + unsigned short addr_8607[] = {0x30, 0x34}; + unsigned short addr_8606[] = {0x10, 0x11}; + int size, i; + + if (i2c == NULL) + return 0; + size = ARRAY_SIZE(addr_8606); + for (i = 0; i < size; i++) { + if (i2c->addr == *(addr_8606 + i)) + return CHIP_PM8606; + } + size = ARRAY_SIZE(addr_8607); + for (i = 0; i < size; i++) { + if (i2c->addr == *(addr_8607 + i)) + return CHIP_PM8607; + } + return 0; +} + static int __devinit pm860x_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct pm8607_platform_data *pdata = client->dev.platform_data; - struct pm8607_chip *chip; - int ret; - - chip = kzalloc(sizeof(struct pm8607_chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; - - chip->client = client; - chip->dev = &client->dev; - chip->read = pm8607_read_device; - chip->write = pm8607_write_device; - memcpy(&chip->id, id, sizeof(struct i2c_device_id)); - i2c_set_clientdata(client, chip); - - mutex_init(&chip->io_lock); - dev_set_drvdata(chip->dev, chip); - - ret = pm860x_device_init(chip, pdata); - if (ret < 0) - goto out; - - + struct pm860x_platform_data *pdata = client->dev.platform_data; + static struct pm860x_chip *chip; + struct i2c_board_info i2c_info = { + .type = "88PM860x", + .platform_data = client->dev.platform_data, + }; + int addr_c, found_companion = 0; + + if (pdata == NULL) { + pr_info("No platform data in %s!\n", __func__); + return -EINVAL; + } + + /* + * Both client and companion client shares same platform driver. + * Driver distinguishes them by pdata->companion_addr. + * pdata->companion_addr is only assigned if companion chip exists. + * At the same time, the companion_addr shouldn't equal to client + * address. + */ + addr_c = pdata->companion_addr; + if (addr_c && (addr_c != client->addr)) { + i2c_info.addr = addr_c; + found_companion = 1; + } + + if (found_companion || (addr_c == 0)) { + chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + chip->id = verify_addr(client); + chip->companion_addr = addr_c; + chip->client = client; + i2c_set_clientdata(client, chip); + chip->dev = &client->dev; + mutex_init(&chip->io_lock); + dev_set_drvdata(chip->dev, chip); + + if (found_companion) { + /* + * If this driver is built in, probe function is + * recursive. + * If this driver is built as module, the next probe + * function is called after the first one finished. + */ + chip->companion = i2c_new_device(client->adapter, + &i2c_info); + } + } + + /* + * If companion chip existes, it's called by companion probe. + * If there's no companion chip, it's called by client probe. + */ + if ((addr_c == 0) || (addr_c == client->addr)) { + chip->companion = client; + i2c_set_clientdata(chip->companion, chip); + pm860x_device_init(chip, pdata); + } return 0; - -out: - i2c_set_clientdata(client, NULL); - kfree(chip); - return ret; } static int __devexit pm860x_remove(struct i2c_client *client) { - struct pm8607_chip *chip = i2c_get_clientdata(client); - + struct pm860x_chip *chip = i2c_get_clientdata(client); + + /* + * If companion existes, companion client is removed first. + * Because companion client is registered last and removed first. + */ + if (chip->companion_addr == client->addr) + return 0; + pm860x_device_exit(chip); + i2c_unregister_device(chip->companion); + i2c_set_clientdata(chip->companion, NULL); + i2c_set_clientdata(chip->client, NULL); kfree(chip); return 0; } diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 0471955..97897a6 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -11,15 +11,17 @@ #include #include #include +#include #include #include #include -#include +#include struct pm8607_regulator_info { struct regulator_desc desc; - struct pm8607_chip *chip; + struct pm860x_chip *chip; struct regulator_dev *regulator; + struct i2c_client *i2c; int min_uV; int max_uV; @@ -46,7 +48,7 @@ static inline int check_range(struct pm8607_regulator_info *info, static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - uint8_t chip_id = info->chip->chip_id; + uint8_t chip_id = info->chip->chip_version; int ret = -EINVAL; switch (info->desc.id) { @@ -169,7 +171,7 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - uint8_t chip_id = info->chip->chip_id; + uint8_t chip_id = info->chip->chip_version; int val = -ENOENT; int ret; @@ -428,7 +430,6 @@ static int pm8607_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - struct pm8607_chip *chip = info->chip; uint8_t val, mask; int ret; @@ -443,13 +444,13 @@ static int pm8607_set_voltage(struct regulator_dev *rdev, val = (uint8_t)(ret << info->vol_shift); mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; - ret = pm8607_set_bits(chip, info->vol_reg, mask, val); + ret = pm860x_set_bits(info->i2c, info->vol_reg, mask, val); if (ret) return ret; switch (info->desc.id) { case PM8607_ID_BUCK1: case PM8607_ID_BUCK3: - ret = pm8607_set_bits(chip, info->update_reg, + ret = pm860x_set_bits(info->i2c, info->update_reg, 1 << info->update_bit, 1 << info->update_bit); break; @@ -460,11 +461,10 @@ static int pm8607_set_voltage(struct regulator_dev *rdev, static int pm8607_get_voltage(struct regulator_dev *rdev) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - struct pm8607_chip *chip = info->chip; uint8_t val, mask; int ret; - ret = pm8607_reg_read(chip, info->vol_reg); + ret = pm860x_reg_read(info->i2c, info->vol_reg); if (ret < 0) return ret; @@ -477,9 +477,8 @@ static int pm8607_get_voltage(struct regulator_dev *rdev) static int pm8607_enable(struct regulator_dev *rdev) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - struct pm8607_chip *chip = info->chip; - return pm8607_set_bits(chip, info->enable_reg, + return pm860x_set_bits(info->i2c, info->enable_reg, 1 << info->enable_bit, 1 << info->enable_bit); } @@ -487,19 +486,17 @@ static int pm8607_enable(struct regulator_dev *rdev) static int pm8607_disable(struct regulator_dev *rdev) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - struct pm8607_chip *chip = info->chip; - return pm8607_set_bits(chip, info->enable_reg, + return pm860x_set_bits(info->i2c, info->enable_reg, 1 << info->enable_bit, 0); } static int pm8607_is_enabled(struct regulator_dev *rdev) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - struct pm8607_chip *chip = info->chip; int ret; - ret = pm8607_reg_read(chip, info->enable_reg); + ret = pm860x_reg_read(info->i2c, info->enable_reg); if (ret < 0) return ret; @@ -589,8 +586,8 @@ static inline struct pm8607_regulator_info *find_regulator_info(int id) static int __devinit pm8607_regulator_probe(struct platform_device *pdev) { - struct pm8607_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm8607_platform_data *pdata = chip->dev->platform_data; + struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct pm860x_platform_data *pdata = chip->dev->platform_data; struct pm8607_regulator_info *info = NULL; info = find_regulator_info(pdev->id); @@ -599,6 +596,7 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) return -EINVAL; } + info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; info->chip = chip; info->regulator = regulator_register(&info->desc, &pdev->dev, diff --git a/include/linux/mfd/88pm8607.h b/include/linux/mfd/88pm8607.h deleted file mode 100644 index 6e4dcdc..0000000 --- a/include/linux/mfd/88pm8607.h +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Marvell 88PM8607 Interface - * - * Copyright (C) 2009 Marvell International Ltd. - * Haojian Zhuang - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __LINUX_MFD_88PM8607_H -#define __LINUX_MFD_88PM8607_H - -enum { - PM8607_ID_BUCK1 = 0, - PM8607_ID_BUCK2, - PM8607_ID_BUCK3, - - PM8607_ID_LDO1, - PM8607_ID_LDO2, - PM8607_ID_LDO3, - PM8607_ID_LDO4, - PM8607_ID_LDO5, - PM8607_ID_LDO6, - PM8607_ID_LDO7, - PM8607_ID_LDO8, - PM8607_ID_LDO9, - PM8607_ID_LDO10, - PM8607_ID_LDO12, - PM8607_ID_LDO14, - - PM8607_ID_RG_MAX, -}; - -#define PM8607_ID (0x40) /* 8607 chip ID */ -#define PM8607_ID_MASK (0xF8) /* 8607 chip ID mask */ - -/* Interrupt Registers */ -#define PM8607_STATUS_1 (0x01) -#define PM8607_STATUS_2 (0x02) -#define PM8607_INT_STATUS1 (0x03) -#define PM8607_INT_STATUS2 (0x04) -#define PM8607_INT_STATUS3 (0x05) -#define PM8607_INT_MASK_1 (0x06) -#define PM8607_INT_MASK_2 (0x07) -#define PM8607_INT_MASK_3 (0x08) - -/* Regulator Control Registers */ -#define PM8607_LDO1 (0x10) -#define PM8607_LDO2 (0x11) -#define PM8607_LDO3 (0x12) -#define PM8607_LDO4 (0x13) -#define PM8607_LDO5 (0x14) -#define PM8607_LDO6 (0x15) -#define PM8607_LDO7 (0x16) -#define PM8607_LDO8 (0x17) -#define PM8607_LDO9 (0x18) -#define PM8607_LDO10 (0x19) -#define PM8607_LDO12 (0x1A) -#define PM8607_LDO14 (0x1B) -#define PM8607_SLEEP_MODE1 (0x1C) -#define PM8607_SLEEP_MODE2 (0x1D) -#define PM8607_SLEEP_MODE3 (0x1E) -#define PM8607_SLEEP_MODE4 (0x1F) -#define PM8607_GO (0x20) -#define PM8607_SLEEP_BUCK1 (0x21) -#define PM8607_SLEEP_BUCK2 (0x22) -#define PM8607_SLEEP_BUCK3 (0x23) -#define PM8607_BUCK1 (0x24) -#define PM8607_BUCK2 (0x25) -#define PM8607_BUCK3 (0x26) -#define PM8607_BUCK_CONTROLS (0x27) -#define PM8607_SUPPLIES_EN11 (0x2B) -#define PM8607_SUPPLIES_EN12 (0x2C) -#define PM8607_GROUP1 (0x2D) -#define PM8607_GROUP2 (0x2E) -#define PM8607_GROUP3 (0x2F) -#define PM8607_GROUP4 (0x30) -#define PM8607_GROUP5 (0x31) -#define PM8607_GROUP6 (0x32) -#define PM8607_SUPPLIES_EN21 (0x33) -#define PM8607_SUPPLIES_EN22 (0x34) - -/* RTC Control Registers */ -#define PM8607_RTC1 (0xA0) -#define PM8607_RTC_COUNTER1 (0xA1) -#define PM8607_RTC_COUNTER2 (0xA2) -#define PM8607_RTC_COUNTER3 (0xA3) -#define PM8607_RTC_COUNTER4 (0xA4) -#define PM8607_RTC_EXPIRE1 (0xA5) -#define PM8607_RTC_EXPIRE2 (0xA6) -#define PM8607_RTC_EXPIRE3 (0xA7) -#define PM8607_RTC_EXPIRE4 (0xA8) -#define PM8607_RTC_TRIM1 (0xA9) -#define PM8607_RTC_TRIM2 (0xAA) -#define PM8607_RTC_TRIM3 (0xAB) -#define PM8607_RTC_TRIM4 (0xAC) -#define PM8607_RTC_MISC1 (0xAD) -#define PM8607_RTC_MISC2 (0xAE) -#define PM8607_RTC_MISC3 (0xAF) - -/* Misc Registers */ -#define PM8607_CHIP_ID (0x00) -#define PM8607_LDO1 (0x10) -#define PM8607_DVC3 (0x26) -#define PM8607_MISC1 (0x40) - -/* bit definitions for PM8607 events */ -#define PM8607_EVENT_ONKEY (1 << 0) -#define PM8607_EVENT_EXTON (1 << 1) -#define PM8607_EVENT_CHG (1 << 2) -#define PM8607_EVENT_BAT (1 << 3) -#define PM8607_EVENT_RTC (1 << 4) -#define PM8607_EVENT_CC (1 << 5) -#define PM8607_EVENT_VBAT (1 << 8) -#define PM8607_EVENT_VCHG (1 << 9) -#define PM8607_EVENT_VSYS (1 << 10) -#define PM8607_EVENT_TINT (1 << 11) -#define PM8607_EVENT_GPADC0 (1 << 12) -#define PM8607_EVENT_GPADC1 (1 << 13) -#define PM8607_EVENT_GPADC2 (1 << 14) -#define PM8607_EVENT_GPADC3 (1 << 15) -#define PM8607_EVENT_AUDIO_SHORT (1 << 16) -#define PM8607_EVENT_PEN (1 << 17) -#define PM8607_EVENT_HEADSET (1 << 18) -#define PM8607_EVENT_HOOK (1 << 19) -#define PM8607_EVENT_MICIN (1 << 20) -#define PM8607_EVENT_CHG_TIMEOUT (1 << 21) -#define PM8607_EVENT_CHG_DONE (1 << 22) -#define PM8607_EVENT_CHG_FAULT (1 << 23) - -/* bit definitions of Status Query Interface */ -#define PM8607_STATUS_CC (1 << 3) -#define PM8607_STATUS_PEN (1 << 4) -#define PM8607_STATUS_HEADSET (1 << 5) -#define PM8607_STATUS_HOOK (1 << 6) -#define PM8607_STATUS_MICIN (1 << 7) -#define PM8607_STATUS_ONKEY (1 << 8) -#define PM8607_STATUS_EXTON (1 << 9) -#define PM8607_STATUS_CHG (1 << 10) -#define PM8607_STATUS_BAT (1 << 11) -#define PM8607_STATUS_VBUS (1 << 12) -#define PM8607_STATUS_OV (1 << 13) - -/* bit definitions of BUCK3 */ -#define PM8607_BUCK3_DOUBLE (1 << 6) - -/* bit definitions of Misc1 */ -#define PM8607_MISC1_PI2C (1 << 0) - -/* Interrupt Number in 88PM8607 */ -enum { - PM8607_IRQ_ONKEY = 0, - PM8607_IRQ_EXTON, - PM8607_IRQ_CHG, - PM8607_IRQ_BAT, - PM8607_IRQ_RTC, - PM8607_IRQ_VBAT = 8, - PM8607_IRQ_VCHG, - PM8607_IRQ_VSYS, - PM8607_IRQ_TINT, - PM8607_IRQ_GPADC0, - PM8607_IRQ_GPADC1, - PM8607_IRQ_GPADC2, - PM8607_IRQ_GPADC3, - PM8607_IRQ_AUDIO_SHORT = 16, - PM8607_IRQ_PEN, - PM8607_IRQ_HEADSET, - PM8607_IRQ_HOOK, - PM8607_IRQ_MICIN, - PM8607_IRQ_CHG_FAIL, - PM8607_IRQ_CHG_DONE, - PM8607_IRQ_CHG_FAULT, -}; - -enum { - PM8607_CHIP_A0 = 0x40, - PM8607_CHIP_A1 = 0x41, - PM8607_CHIP_B0 = 0x48, -}; - - -struct pm8607_chip { - struct device *dev; - struct mutex io_lock; - struct i2c_client *client; - struct i2c_device_id id; - - int (*read)(struct pm8607_chip *chip, int reg, int bytes, void *dest); - int (*write)(struct pm8607_chip *chip, int reg, int bytes, void *src); - - int buck3_double; /* DVC ramp slope double */ - unsigned char chip_id; - -}; - -#define PM8607_MAX_REGULATOR 15 /* 3 Bucks, 12 LDOs */ - -enum { - GI2C_PORT = 0, - PI2C_PORT, -}; - -struct pm8607_platform_data { - int i2c_port; /* Controlled by GI2C or PI2C */ - struct regulator_init_data *regulator[PM8607_MAX_REGULATOR]; -}; - -extern int pm8607_reg_read(struct pm8607_chip *, int); -extern int pm8607_reg_write(struct pm8607_chip *, int, unsigned char); -extern int pm8607_bulk_read(struct pm8607_chip *, int, int, - unsigned char *); -extern int pm8607_bulk_write(struct pm8607_chip *, int, int, - unsigned char *); -extern int pm8607_set_bits(struct pm8607_chip *, int, unsigned char, - unsigned char); - -extern int pm860x_device_init(struct pm8607_chip *chip, - struct pm8607_platform_data *pdata); -extern void pm860x_device_exit(struct pm8607_chip *chip); - -#endif /* __LINUX_MFD_88PM860X_H */ diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h new file mode 100644 index 0000000..5845ae4 --- /dev/null +++ b/include/linux/mfd/88pm860x.h @@ -0,0 +1,227 @@ +/* + * Marvell 88PM860x Interface + * + * Copyright (C) 2009 Marvell International Ltd. + * Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_MFD_88PM860X_H +#define __LINUX_MFD_88PM860X_H + +enum { + CHIP_INVALID = 0, + CHIP_PM8606, + CHIP_PM8607, + CHIP_MAX, +}; + +enum { + PM8607_ID_BUCK1 = 0, + PM8607_ID_BUCK2, + PM8607_ID_BUCK3, + + PM8607_ID_LDO1, + PM8607_ID_LDO2, + PM8607_ID_LDO3, + PM8607_ID_LDO4, + PM8607_ID_LDO5, + PM8607_ID_LDO6, + PM8607_ID_LDO7, + PM8607_ID_LDO8, + PM8607_ID_LDO9, + PM8607_ID_LDO10, + PM8607_ID_LDO12, + PM8607_ID_LDO14, + + PM8607_ID_RG_MAX, +}; + +#define PM8607_VERSION (0x40) /* 8607 chip ID */ +#define PM8607_VERSION_MASK (0xF0) /* 8607 chip ID mask */ + +/* Interrupt Registers */ +#define PM8607_STATUS_1 (0x01) +#define PM8607_STATUS_2 (0x02) +#define PM8607_INT_STATUS1 (0x03) +#define PM8607_INT_STATUS2 (0x04) +#define PM8607_INT_STATUS3 (0x05) +#define PM8607_INT_MASK_1 (0x06) +#define PM8607_INT_MASK_2 (0x07) +#define PM8607_INT_MASK_3 (0x08) + +/* Regulator Control Registers */ +#define PM8607_LDO1 (0x10) +#define PM8607_LDO2 (0x11) +#define PM8607_LDO3 (0x12) +#define PM8607_LDO4 (0x13) +#define PM8607_LDO5 (0x14) +#define PM8607_LDO6 (0x15) +#define PM8607_LDO7 (0x16) +#define PM8607_LDO8 (0x17) +#define PM8607_LDO9 (0x18) +#define PM8607_LDO10 (0x19) +#define PM8607_LDO12 (0x1A) +#define PM8607_LDO14 (0x1B) +#define PM8607_SLEEP_MODE1 (0x1C) +#define PM8607_SLEEP_MODE2 (0x1D) +#define PM8607_SLEEP_MODE3 (0x1E) +#define PM8607_SLEEP_MODE4 (0x1F) +#define PM8607_GO (0x20) +#define PM8607_SLEEP_BUCK1 (0x21) +#define PM8607_SLEEP_BUCK2 (0x22) +#define PM8607_SLEEP_BUCK3 (0x23) +#define PM8607_BUCK1 (0x24) +#define PM8607_BUCK2 (0x25) +#define PM8607_BUCK3 (0x26) +#define PM8607_BUCK_CONTROLS (0x27) +#define PM8607_SUPPLIES_EN11 (0x2B) +#define PM8607_SUPPLIES_EN12 (0x2C) +#define PM8607_GROUP1 (0x2D) +#define PM8607_GROUP2 (0x2E) +#define PM8607_GROUP3 (0x2F) +#define PM8607_GROUP4 (0x30) +#define PM8607_GROUP5 (0x31) +#define PM8607_GROUP6 (0x32) +#define PM8607_SUPPLIES_EN21 (0x33) +#define PM8607_SUPPLIES_EN22 (0x34) + +/* RTC Control Registers */ +#define PM8607_RTC1 (0xA0) +#define PM8607_RTC_COUNTER1 (0xA1) +#define PM8607_RTC_COUNTER2 (0xA2) +#define PM8607_RTC_COUNTER3 (0xA3) +#define PM8607_RTC_COUNTER4 (0xA4) +#define PM8607_RTC_EXPIRE1 (0xA5) +#define PM8607_RTC_EXPIRE2 (0xA6) +#define PM8607_RTC_EXPIRE3 (0xA7) +#define PM8607_RTC_EXPIRE4 (0xA8) +#define PM8607_RTC_TRIM1 (0xA9) +#define PM8607_RTC_TRIM2 (0xAA) +#define PM8607_RTC_TRIM3 (0xAB) +#define PM8607_RTC_TRIM4 (0xAC) +#define PM8607_RTC_MISC1 (0xAD) +#define PM8607_RTC_MISC2 (0xAE) +#define PM8607_RTC_MISC3 (0xAF) + +/* Misc Registers */ +#define PM8607_CHIP_ID (0x00) +#define PM8607_LDO1 (0x10) +#define PM8607_DVC3 (0x26) +#define PM8607_MISC1 (0x40) + +/* bit definitions for PM8607 events */ +#define PM8607_EVENT_ONKEY (1 << 0) +#define PM8607_EVENT_EXTON (1 << 1) +#define PM8607_EVENT_CHG (1 << 2) +#define PM8607_EVENT_BAT (1 << 3) +#define PM8607_EVENT_RTC (1 << 4) +#define PM8607_EVENT_CC (1 << 5) +#define PM8607_EVENT_VBAT (1 << 8) +#define PM8607_EVENT_VCHG (1 << 9) +#define PM8607_EVENT_VSYS (1 << 10) +#define PM8607_EVENT_TINT (1 << 11) +#define PM8607_EVENT_GPADC0 (1 << 12) +#define PM8607_EVENT_GPADC1 (1 << 13) +#define PM8607_EVENT_GPADC2 (1 << 14) +#define PM8607_EVENT_GPADC3 (1 << 15) +#define PM8607_EVENT_AUDIO_SHORT (1 << 16) +#define PM8607_EVENT_PEN (1 << 17) +#define PM8607_EVENT_HEADSET (1 << 18) +#define PM8607_EVENT_HOOK (1 << 19) +#define PM8607_EVENT_MICIN (1 << 20) +#define PM8607_EVENT_CHG_TIMEOUT (1 << 21) +#define PM8607_EVENT_CHG_DONE (1 << 22) +#define PM8607_EVENT_CHG_FAULT (1 << 23) + +/* bit definitions of Status Query Interface */ +#define PM8607_STATUS_CC (1 << 3) +#define PM8607_STATUS_PEN (1 << 4) +#define PM8607_STATUS_HEADSET (1 << 5) +#define PM8607_STATUS_HOOK (1 << 6) +#define PM8607_STATUS_MICIN (1 << 7) +#define PM8607_STATUS_ONKEY (1 << 8) +#define PM8607_STATUS_EXTON (1 << 9) +#define PM8607_STATUS_CHG (1 << 10) +#define PM8607_STATUS_BAT (1 << 11) +#define PM8607_STATUS_VBUS (1 << 12) +#define PM8607_STATUS_OV (1 << 13) + +/* bit definitions of BUCK3 */ +#define PM8607_BUCK3_DOUBLE (1 << 6) + +/* bit definitions of Misc1 */ +#define PM8607_MISC1_PI2C (1 << 0) + +/* Interrupt Number in 88PM8607 */ +enum { + PM8607_IRQ_ONKEY = 0, + PM8607_IRQ_EXTON, + PM8607_IRQ_CHG, + PM8607_IRQ_BAT, + PM8607_IRQ_RTC, + PM8607_IRQ_VBAT = 8, + PM8607_IRQ_VCHG, + PM8607_IRQ_VSYS, + PM8607_IRQ_TINT, + PM8607_IRQ_GPADC0, + PM8607_IRQ_GPADC1, + PM8607_IRQ_GPADC2, + PM8607_IRQ_GPADC3, + PM8607_IRQ_AUDIO_SHORT = 16, + PM8607_IRQ_PEN, + PM8607_IRQ_HEADSET, + PM8607_IRQ_HOOK, + PM8607_IRQ_MICIN, + PM8607_IRQ_CHG_FAIL, + PM8607_IRQ_CHG_DONE, + PM8607_IRQ_CHG_FAULT, +}; + +enum { + PM8607_CHIP_A0 = 0x40, + PM8607_CHIP_A1 = 0x41, + PM8607_CHIP_B0 = 0x48, +}; + +struct pm860x_chip { + struct device *dev; + struct mutex io_lock; + struct i2c_client *client; + struct i2c_client *companion; /* companion chip client */ + + int buck3_double; /* DVC ramp slope double */ + unsigned short companion_addr; + int id; + unsigned char chip_version; + +}; + +#define PM8607_MAX_REGULATOR 15 /* 3 Bucks, 12 LDOs */ + +enum { + GI2C_PORT = 0, + PI2C_PORT, +}; + +struct pm860x_platform_data { + unsigned short companion_addr; /* I2C address of companion chip */ + int i2c_port; /* Controlled by GI2C or PI2C */ + struct regulator_init_data *regulator[PM8607_MAX_REGULATOR]; +}; + +extern int pm860x_reg_read(struct i2c_client *, int); +extern int pm860x_reg_write(struct i2c_client *, int, unsigned char); +extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *); +extern int pm860x_bulk_write(struct i2c_client *, int, int, unsigned char *); +extern int pm860x_set_bits(struct i2c_client *, int, unsigned char, + unsigned char); + +extern int pm860x_device_init(struct pm860x_chip *chip, + struct pm860x_platform_data *pdata); +extern void pm860x_device_exit(struct pm860x_chip *chip); + +#endif /* __LINUX_MFD_88PM860X_H */ -- cgit v0.10.2 From 2cc50bee9934deb6dfe32929a4c1742cf83d6db3 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 6 Jan 2010 17:07:13 -0500 Subject: mfd: Rename 88pm8607 to 88pm860x in mfd Rename 88PM8607 to 88PM860X in both Makefile and Kconfig under mfd directory. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d957373..815907e 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -9,6 +9,16 @@ config MFD_CORE tristate default n +config MFD_88PM860X + bool "Support Marvell 88PM8606/88PM8607" + depends on I2C=y + select MFD_CORE + help + This supports for Marvell 88PM8606/88PM8607 Power Management IC. + This includes the I2C driver and the core APIs _only_, you have to + select individual components like voltage regulators, RTC and + battery-charger under the corresponding menus. + config MFD_SM501 tristate "Support for Silicon Motion SM501" ---help--- @@ -329,16 +339,6 @@ config EZX_PCAP This enables the PCAP ASIC present on EZX Phones. This is needed for MMC, TouchScreen, Sound, USB, etc.. -config MFD_88PM8607 - bool "Support Marvell 88PM8607" - depends on I2C=y - select MFD_CORE - help - This supports for Marvell 88PM8607 Power Management IC. This includes - the I2C driver and the core APIs _only_, you have to select - individual components like voltage regulators, RTC and - battery-charger under the corresponding menus. - config AB4500_CORE tristate "ST-Ericsson's AB4500 Mixed Signal Power management chip" depends on SPI diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 88fa200..1e3ae06 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -2,7 +2,8 @@ # Makefile for multifunction miscellaneous devices # -obj-$(CONFIG_MFD_88PM8607) += 88pm860x-core.o 88pm860x-i2c.o +88pm860x-objs := 88pm860x-core.o 88pm860x-i2c.o +obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o obj-$(CONFIG_MFD_SH_MOBILE_SDHI) += sh_mobile_sdhi.o diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 834b484..dbfe31a 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -191,7 +191,7 @@ config REGULATOR_TPS6507X config REGULATOR_88PM8607 bool "Marvell 88PM8607 Power regulators" - depends on MFD_88PM8607=y + depends on MFD_88PM860X=y help This driver supports 88PM8607 voltage regulator chips. -- cgit v0.10.2 From 5c42e8c4a9c86ea26ed4ecb732a842dea0dfb6b6 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Tue, 15 Dec 2009 16:01:47 -0500 Subject: mfd: Add irq support in 88pm860x 88PM860x is a complex PMIC device. It contains touch, charger, sound, rtc, backlight, led, and so on. Host communicates to 88PM860x by I2C bus. Use thread irq to support this usage case. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 72b0030..9185f0d 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -67,15 +68,209 @@ static struct mfd_cell pm8607_devs[] = { PM8607_REG_DEVS(ldo14, LDO14), }; -static void device_8606_init(struct pm860x_chip *chip, struct i2c_client *i2c, - struct pm860x_platform_data *pdata) +#define CHECK_IRQ(irq) \ +do { \ + if ((irq < 0) || (irq >= PM860X_NUM_IRQ)) \ + return -EINVAL; \ +} while (0) + +/* IRQs only occur on 88PM8607 */ +int pm860x_mask_irq(struct pm860x_chip *chip, int irq) +{ + struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ + : chip->companion; + int offset, data, ret; + + CHECK_IRQ(irq); + + offset = (irq >> 3) + PM8607_INT_MASK_1; + data = 1 << (irq % 8); + ret = pm860x_set_bits(i2c, offset, data, 0); + + return ret; +} +EXPORT_SYMBOL(pm860x_mask_irq); + +int pm860x_unmask_irq(struct pm860x_chip *chip, int irq) +{ + struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ + : chip->companion; + int offset, data, ret; + + CHECK_IRQ(irq); + + offset = (irq >> 3) + PM8607_INT_MASK_1; + data = 1 << (irq % 8); + ret = pm860x_set_bits(i2c, offset, data, data); + + return ret; +} +EXPORT_SYMBOL(pm860x_unmask_irq); + +#define INT_STATUS_NUM (3) + +static irqreturn_t pm8607_irq_thread(int irq, void *data) +{ + DECLARE_BITMAP(irq_status, PM860X_NUM_IRQ); + struct pm860x_chip *chip = data; + struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ + : chip->companion; + unsigned char status_buf[INT_STATUS_NUM << 1]; + unsigned long value; + int i, ret; + + irq_status[0] = 0; + + /* read out status register */ + ret = pm860x_bulk_read(i2c, PM8607_INT_STATUS1, + INT_STATUS_NUM << 1, status_buf); + if (ret < 0) + goto out; + if (chip->irq_mode) { + /* 0, clear by read. 1, clear by write */ + ret = pm860x_bulk_write(i2c, PM8607_INT_STATUS1, + INT_STATUS_NUM, status_buf); + if (ret < 0) + goto out; + } + + /* clear masked interrupt status */ + for (i = 0, value = 0; i < INT_STATUS_NUM; i++) { + status_buf[i] &= status_buf[i + INT_STATUS_NUM]; + irq_status[0] |= status_buf[i] << (i * 8); + } + + while (!bitmap_empty(irq_status, PM860X_NUM_IRQ)) { + irq = find_first_bit(irq_status, PM860X_NUM_IRQ); + clear_bit(irq, irq_status); + dev_dbg(chip->dev, "Servicing IRQ #%d\n", irq); + + mutex_lock(&chip->irq_lock); + if (chip->irq[irq].handler) + chip->irq[irq].handler(irq, chip->irq[irq].data); + else { + pm860x_mask_irq(chip, irq); + dev_err(chip->dev, "Nobody cares IRQ %d. " + "Now mask it.\n", irq); + for (i = 0; i < (INT_STATUS_NUM << 1); i++) { + dev_err(chip->dev, "status[%d]:%x\n", i, + status_buf[i]); + } + } + mutex_unlock(&chip->irq_lock); + } +out: + return IRQ_HANDLED; +} + +int pm860x_request_irq(struct pm860x_chip *chip, int irq, + irq_handler_t handler, void *data) { + CHECK_IRQ(irq); + if (!handler) + return -EINVAL; + + mutex_lock(&chip->irq_lock); + chip->irq[irq].handler = handler; + chip->irq[irq].data = data; + mutex_unlock(&chip->irq_lock); + + return 0; } +EXPORT_SYMBOL(pm860x_request_irq); -static void device_8607_init(struct pm860x_chip *chip, struct i2c_client *i2c, - struct pm860x_platform_data *pdata) +int pm860x_free_irq(struct pm860x_chip *chip, int irq) { - int i, count; + CHECK_IRQ(irq); + + mutex_lock(&chip->irq_lock); + chip->irq[irq].handler = NULL; + chip->irq[irq].data = NULL; + mutex_unlock(&chip->irq_lock); + + return 0; +} +EXPORT_SYMBOL(pm860x_free_irq); + +static int __devinit device_irq_init(struct pm860x_chip *chip, + struct pm860x_platform_data *pdata) +{ + struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ + : chip->companion; + unsigned char status_buf[INT_STATUS_NUM]; + int data, mask, ret = -EINVAL; + + mutex_init(&chip->irq_lock); + + mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR + | PM8607_B0_MISC1_INT_MASK; + data = 0; + chip->irq_mode = 0; + if (pdata && pdata->irq_mode) { + /* + * irq_mode defines the way of clearing interrupt. If it's 1, + * clear IRQ by write. Otherwise, clear it by read. + * This control bit is valid from 88PM8607 B0 steping. + */ + data |= PM8607_B0_MISC1_INT_CLEAR; + chip->irq_mode = 1; + } + ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, mask, data); + if (ret < 0) + goto out; + + /* mask all IRQs */ + memset(status_buf, 0, INT_STATUS_NUM); + ret = pm860x_bulk_write(i2c, PM8607_INT_MASK_1, + INT_STATUS_NUM, status_buf); + if (ret < 0) + goto out; + + if (chip->irq_mode) { + /* clear interrupt status by write */ + memset(status_buf, 0xFF, INT_STATUS_NUM); + ret = pm860x_bulk_write(i2c, PM8607_INT_STATUS1, + INT_STATUS_NUM, status_buf); + } else { + /* clear interrupt status by read */ + ret = pm860x_bulk_read(i2c, PM8607_INT_STATUS1, + INT_STATUS_NUM, status_buf); + } + if (ret < 0) + goto out; + + memset(chip->irq, 0, sizeof(struct pm860x_irq) * PM860X_NUM_IRQ); + + ret = request_threaded_irq(i2c->irq, NULL, pm8607_irq_thread, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "88PM8607", chip); + if (ret < 0) { + dev_err(chip->dev, "Failed to request IRQ #%d.\n", i2c->irq); + goto out; + } + chip->chip_irq = i2c->irq; + return 0; +out: + return ret; +} + +static void __devexit device_irq_exit(struct pm860x_chip *chip) +{ + if (chip->chip_irq >= 0) + free_irq(chip->chip_irq, chip); +} + +static void __devinit device_8606_init(struct pm860x_chip *chip, + struct i2c_client *i2c, + struct pm860x_platform_data *pdata) +{ +} + +static void __devinit device_8607_init(struct pm860x_chip *chip, + struct i2c_client *i2c, + struct pm860x_platform_data *pdata) +{ + int i, count, data; int ret; ret = pm860x_reg_read(i2c, PM8607_CHIP_ID); @@ -91,7 +286,6 @@ static void device_8607_init(struct pm860x_chip *chip, struct i2c_client *i2c, "Chip ID: %02x\n", ret); goto out; } - chip->chip_version = ret; ret = pm860x_reg_read(i2c, PM8607_BUCK3); if (ret < 0) { @@ -101,12 +295,26 @@ static void device_8607_init(struct pm860x_chip *chip, struct i2c_client *i2c, if (ret & PM8607_BUCK3_DOUBLE) chip->buck3_double = 1; - ret = pm860x_reg_read(i2c, PM8607_MISC1); + ret = pm860x_reg_read(i2c, PM8607_B0_MISC1); if (ret < 0) { dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret); goto out; } + if (pdata && (pdata->i2c_port == PI2C_PORT)) + data = PM8607_B0_MISC1_PI2C; + else + data = 0; + ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, PM8607_B0_MISC1_PI2C, data); + if (ret < 0) { + dev_err(chip->dev, "Failed to access MISC1:%d\n", ret); + goto out; + } + + ret = device_irq_init(chip, pdata); + if (ret < 0) + goto out; + count = ARRAY_SIZE(pm8607_devs); for (i = 0; i < count; i++) { ret = mfd_add_devices(chip->dev, i, &pm8607_devs[i], @@ -123,6 +331,8 @@ out: int pm860x_device_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { + chip->chip_irq = -EINVAL; + switch (chip->id) { case CHIP_PM8606: device_8606_init(chip, chip->client, pdata); @@ -142,11 +352,13 @@ int pm860x_device_init(struct pm860x_chip *chip, break; } } + return 0; } void pm860x_device_exit(struct pm860x_chip *chip) { + device_irq_exit(chip); mfd_remove_devices(chip->dev); } diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h index 5845ae4..b4d6018 100644 --- a/include/linux/mfd/88pm860x.h +++ b/include/linux/mfd/88pm860x.h @@ -12,6 +12,8 @@ #ifndef __LINUX_MFD_88PM860X_H #define __LINUX_MFD_88PM860X_H +#include + enum { CHIP_INVALID = 0, CHIP_PM8606, @@ -109,33 +111,10 @@ enum { /* Misc Registers */ #define PM8607_CHIP_ID (0x00) +#define PM8607_B0_MISC1 (0x0C) #define PM8607_LDO1 (0x10) #define PM8607_DVC3 (0x26) -#define PM8607_MISC1 (0x40) - -/* bit definitions for PM8607 events */ -#define PM8607_EVENT_ONKEY (1 << 0) -#define PM8607_EVENT_EXTON (1 << 1) -#define PM8607_EVENT_CHG (1 << 2) -#define PM8607_EVENT_BAT (1 << 3) -#define PM8607_EVENT_RTC (1 << 4) -#define PM8607_EVENT_CC (1 << 5) -#define PM8607_EVENT_VBAT (1 << 8) -#define PM8607_EVENT_VCHG (1 << 9) -#define PM8607_EVENT_VSYS (1 << 10) -#define PM8607_EVENT_TINT (1 << 11) -#define PM8607_EVENT_GPADC0 (1 << 12) -#define PM8607_EVENT_GPADC1 (1 << 13) -#define PM8607_EVENT_GPADC2 (1 << 14) -#define PM8607_EVENT_GPADC3 (1 << 15) -#define PM8607_EVENT_AUDIO_SHORT (1 << 16) -#define PM8607_EVENT_PEN (1 << 17) -#define PM8607_EVENT_HEADSET (1 << 18) -#define PM8607_EVENT_HOOK (1 << 19) -#define PM8607_EVENT_MICIN (1 << 20) -#define PM8607_EVENT_CHG_TIMEOUT (1 << 21) -#define PM8607_EVENT_CHG_DONE (1 << 22) -#define PM8607_EVENT_CHG_FAULT (1 << 23) +#define PM8607_A1_MISC1 (0x40) /* bit definitions of Status Query Interface */ #define PM8607_STATUS_CC (1 << 3) @@ -154,7 +133,12 @@ enum { #define PM8607_BUCK3_DOUBLE (1 << 6) /* bit definitions of Misc1 */ -#define PM8607_MISC1_PI2C (1 << 0) +#define PM8607_A1_MISC1_PI2C (1 << 0) +#define PM8607_B0_MISC1_INV_INT (1 << 0) +#define PM8607_B0_MISC1_INT_CLEAR (1 << 1) +#define PM8607_B0_MISC1_INT_MASK (1 << 2) +#define PM8607_B0_MISC1_PI2C (1 << 3) +#define PM8607_B0_MISC1_RESET (1 << 6) /* Interrupt Number in 88PM8607 */ enum { @@ -187,15 +171,26 @@ enum { PM8607_CHIP_B0 = 0x48, }; +#define PM860X_NUM_IRQ 24 + +struct pm860x_irq { + irq_handler_t handler; + void *data; +}; + struct pm860x_chip { struct device *dev; struct mutex io_lock; + struct mutex irq_lock; struct i2c_client *client; struct i2c_client *companion; /* companion chip client */ + struct pm860x_irq irq[PM860X_NUM_IRQ]; int buck3_double; /* DVC ramp slope double */ unsigned short companion_addr; int id; + int irq_mode; + int chip_irq; unsigned char chip_version; }; @@ -210,6 +205,7 @@ enum { struct pm860x_platform_data { unsigned short companion_addr; /* I2C address of companion chip */ int i2c_port; /* Controlled by GI2C or PI2C */ + int irq_mode; /* Clear interrupt by read/write(0/1) */ struct regulator_init_data *regulator[PM8607_MAX_REGULATOR]; }; @@ -220,6 +216,12 @@ extern int pm860x_bulk_write(struct i2c_client *, int, int, unsigned char *); extern int pm860x_set_bits(struct i2c_client *, int, unsigned char, unsigned char); +extern int pm860x_mask_irq(struct pm860x_chip *, int); +extern int pm860x_unmask_irq(struct pm860x_chip *, int); +extern int pm860x_request_irq(struct pm860x_chip *, int, + irq_handler_t handler, void *); +extern int pm860x_free_irq(struct pm860x_chip *, int); + extern int pm860x_device_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata); extern void pm860x_device_exit(struct pm860x_chip *chip); -- cgit v0.10.2 From a16122bcacf050e7f83015183053cf799713cc37 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Tue, 15 Dec 2009 16:04:36 -0500 Subject: mfd: Append subdev into 88pm860x driver Append backlight, led & touch subdevs into 88pm860x driver. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 9185f0d..16f0dca 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -17,6 +17,100 @@ #include #include +char pm860x_backlight_name[][MFD_NAME_SIZE] = { + "backlight-0", + "backlight-1", + "backlight-2", +}; +EXPORT_SYMBOL(pm860x_backlight_name); + +char pm860x_led_name[][MFD_NAME_SIZE] = { + "led0-red", + "led0-green", + "led0-blue", + "led1-red", + "led1-green", + "led1-blue", +}; +EXPORT_SYMBOL(pm860x_led_name); + +#define PM8606_BACKLIGHT_RESOURCE(_i, _x) \ +{ \ + .name = pm860x_backlight_name[_i], \ + .start = PM8606_##_x, \ + .end = PM8606_##_x, \ + .flags = IORESOURCE_IO, \ +} + +static struct resource backlight_resources[] = { + PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT1, WLED1A), + PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT2, WLED2A), + PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT3, WLED3A), +}; + +#define PM8606_BACKLIGHT_DEVS(_i) \ +{ \ + .name = "88pm860x-backlight", \ + .num_resources = 1, \ + .resources = &backlight_resources[_i], \ + .id = _i, \ +} + +static struct mfd_cell backlight_devs[] = { + PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT1), + PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT2), + PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT3), +}; + +#define PM8606_LED_RESOURCE(_i, _x) \ +{ \ + .name = pm860x_led_name[_i], \ + .start = PM8606_##_x, \ + .end = PM8606_##_x, \ + .flags = IORESOURCE_IO, \ +} + +static struct resource led_resources[] = { + PM8606_LED_RESOURCE(PM8606_LED1_RED, RGB2B), + PM8606_LED_RESOURCE(PM8606_LED1_GREEN, RGB2C), + PM8606_LED_RESOURCE(PM8606_LED1_BLUE, RGB2D), + PM8606_LED_RESOURCE(PM8606_LED2_RED, RGB1B), + PM8606_LED_RESOURCE(PM8606_LED2_GREEN, RGB1C), + PM8606_LED_RESOURCE(PM8606_LED2_BLUE, RGB1D), +}; + +#define PM8606_LED_DEVS(_i) \ +{ \ + .name = "88pm860x-led", \ + .num_resources = 1, \ + .resources = &led_resources[_i], \ + .id = _i, \ +} + +static struct mfd_cell led_devs[] = { + PM8606_LED_DEVS(PM8606_LED1_RED), + PM8606_LED_DEVS(PM8606_LED1_GREEN), + PM8606_LED_DEVS(PM8606_LED1_BLUE), + PM8606_LED_DEVS(PM8606_LED2_RED), + PM8606_LED_DEVS(PM8606_LED2_GREEN), + PM8606_LED_DEVS(PM8606_LED2_BLUE), +}; + +static struct resource touch_resources[] = { + { + .start = PM8607_IRQ_PEN, + .end = PM8607_IRQ_PEN, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mfd_cell touch_devs[] = { + { + .name = "88pm860x-touch", + .num_resources = 1, + .resources = &touch_resources[0], + }, +}; #define PM8607_REG_RESOURCE(_start, _end) \ { \ @@ -25,7 +119,7 @@ .flags = IORESOURCE_IO, \ } -static struct resource pm8607_regulator_resources[] = { +static struct resource regulator_resources[] = { PM8607_REG_RESOURCE(BUCK1, BUCK1), PM8607_REG_RESOURCE(BUCK2, BUCK2), PM8607_REG_RESOURCE(BUCK3, BUCK3), @@ -47,10 +141,11 @@ static struct resource pm8607_regulator_resources[] = { { \ .name = "88pm8607-" #_name, \ .num_resources = 1, \ - .resources = &pm8607_regulator_resources[PM8607_ID_##_id], \ + .resources = ®ulator_resources[PM8607_ID_##_id], \ + .id = PM8607_ID_##_id, \ } -static struct mfd_cell pm8607_devs[] = { +static struct mfd_cell regulator_devs[] = { PM8607_REG_DEVS(buck1, BUCK1), PM8607_REG_DEVS(buck2, BUCK2), PM8607_REG_DEVS(buck3, BUCK3), @@ -192,6 +287,61 @@ int pm860x_free_irq(struct pm860x_chip *chip, int irq) } EXPORT_SYMBOL(pm860x_free_irq); +static int __devinit device_gpadc_init(struct pm860x_chip *chip, + struct pm860x_platform_data *pdata) +{ + struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ + : chip->companion; + int use_gpadc = 0, data, ret; + + /* initialize GPADC without activating it */ + + if (pdata && pdata->touch) { + /* set GPADC MISC1 register */ + data = 0; + data |= (pdata->touch->gpadc_prebias << 1) + & PM8607_GPADC_PREBIAS_MASK; + data |= (pdata->touch->slot_cycle << 3) + & PM8607_GPADC_SLOT_CYCLE_MASK; + data |= (pdata->touch->off_scale << 5) + & PM8607_GPADC_OFF_SCALE_MASK; + data |= (pdata->touch->sw_cal << 7) + & PM8607_GPADC_SW_CAL_MASK; + if (data) { + ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data); + if (ret < 0) + goto out; + } + /* set tsi prebias time */ + if (pdata->touch->tsi_prebias) { + data = pdata->touch->tsi_prebias; + ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data); + if (ret < 0) + goto out; + } + /* set prebias & prechg time of pen detect */ + data = 0; + data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK; + data |= (pdata->touch->pen_prechg << 5) + & PM8607_PD_PRECHG_MASK; + if (data) { + ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data); + if (ret < 0) + goto out; + } + + use_gpadc = 1; + } + + /* turn on GPADC */ + if (use_gpadc) { + ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1, + PM8607_GPADC_EN, PM8607_GPADC_EN); + } +out: + return ret; +} + static int __devinit device_irq_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { @@ -264,14 +414,40 @@ static void __devinit device_8606_init(struct pm860x_chip *chip, struct i2c_client *i2c, struct pm860x_platform_data *pdata) { + int ret; + + if (pdata && pdata->backlight) { + ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0], + ARRAY_SIZE(backlight_devs), + &backlight_resources[0], 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add backlight " + "subdev\n"); + goto out_dev; + } + } + + if (pdata && pdata->led) { + ret = mfd_add_devices(chip->dev, 0, &led_devs[0], + ARRAY_SIZE(led_devs), + &led_resources[0], 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add led " + "subdev\n"); + goto out_dev; + } + } + return; +out_dev: + mfd_remove_devices(chip->dev); + device_irq_exit(chip); } static void __devinit device_8607_init(struct pm860x_chip *chip, struct i2c_client *i2c, struct pm860x_platform_data *pdata) { - int i, count, data; - int ret; + int data, ret; ret = pm860x_reg_read(i2c, PM8607_CHIP_ID); if (ret < 0) { @@ -311,19 +487,36 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, goto out; } + ret = device_gpadc_init(chip, pdata); + if (ret < 0) + goto out; + ret = device_irq_init(chip, pdata); if (ret < 0) goto out; - count = ARRAY_SIZE(pm8607_devs); - for (i = 0; i < count; i++) { - ret = mfd_add_devices(chip->dev, i, &pm8607_devs[i], - 1, NULL, 0); - if (ret != 0) { - dev_err(chip->dev, "Failed to add subdevs\n"); - goto out; + ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], + ARRAY_SIZE(regulator_devs), + ®ulator_resources[0], 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add regulator subdev\n"); + goto out_dev; + } + + if (pdata && pdata->touch) { + ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], + ARRAY_SIZE(touch_devs), + &touch_resources[0], 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add touch " + "subdev\n"); + goto out_dev; } } + return; +out_dev: + mfd_remove_devices(chip->dev); + device_irq_exit(chip); out: return; } diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h index b4d6018..d7edf11 100644 --- a/include/linux/mfd/88pm860x.h +++ b/include/linux/mfd/88pm860x.h @@ -14,6 +14,8 @@ #include +#define MFD_NAME_SIZE (40) + enum { CHIP_INVALID = 0, CHIP_PM8606, @@ -22,6 +24,99 @@ enum { }; enum { + PM8606_ID_INVALID, + PM8606_ID_BACKLIGHT, + PM8606_ID_LED, + PM8606_ID_VIBRATOR, + PM8606_ID_TOUCH, + PM8606_ID_SOUND, + PM8606_ID_CHARGER, + PM8606_ID_MAX, +}; + +enum { + PM8606_BACKLIGHT1 = 0, + PM8606_BACKLIGHT2, + PM8606_BACKLIGHT3, +}; + +enum { + PM8606_LED1_RED = 0, + PM8606_LED1_GREEN, + PM8606_LED1_BLUE, + PM8606_LED2_RED, + PM8606_LED2_GREEN, + PM8606_LED2_BLUE, + PM8607_LED_VIBRATOR, +}; + + +/* 8606 Registers */ +#define PM8606_DCM_BOOST (0x00) +#define PM8606_PWM (0x01) + +/* Backlight Registers */ +#define PM8606_WLED1A (0x02) +#define PM8606_WLED1B (0x03) +#define PM8606_WLED2A (0x04) +#define PM8606_WLED2B (0x05) +#define PM8606_WLED3A (0x06) +#define PM8606_WLED3B (0x07) + +/* LED Registers */ +#define PM8606_RGB2A (0x08) +#define PM8606_RGB2B (0x09) +#define PM8606_RGB2C (0x0A) +#define PM8606_RGB2D (0x0B) +#define PM8606_RGB1A (0x0C) +#define PM8606_RGB1B (0x0D) +#define PM8606_RGB1C (0x0E) +#define PM8606_RGB1D (0x0F) + +#define PM8606_PREREGULATORA (0x10) +#define PM8606_PREREGULATORB (0x11) +#define PM8606_VIBRATORA (0x12) +#define PM8606_VIBRATORB (0x13) +#define PM8606_VCHG (0x14) +#define PM8606_VSYS (0x15) +#define PM8606_MISC (0x16) +#define PM8606_CHIP_ID (0x17) +#define PM8606_STATUS (0x18) +#define PM8606_FLAGS (0x19) +#define PM8606_PROTECTA (0x1A) +#define PM8606_PROTECTB (0x1B) +#define PM8606_PROTECTC (0x1C) + +/* Bit definitions of PM8606 registers */ +#define PM8606_DCM_500MA (0x0) /* current limit */ +#define PM8606_DCM_750MA (0x1) +#define PM8606_DCM_1000MA (0x2) +#define PM8606_DCM_1250MA (0x3) +#define PM8606_DCM_250MV (0x0 << 2) +#define PM8606_DCM_300MV (0x1 << 2) +#define PM8606_DCM_350MV (0x2 << 2) +#define PM8606_DCM_400MV (0x3 << 2) + +#define PM8606_PWM_31200HZ (0x0) +#define PM8606_PWM_15600HZ (0x1) +#define PM8606_PWM_7800HZ (0x2) +#define PM8606_PWM_3900HZ (0x3) +#define PM8606_PWM_1950HZ (0x4) +#define PM8606_PWM_976HZ (0x5) +#define PM8606_PWM_488HZ (0x6) +#define PM8606_PWM_244HZ (0x7) +#define PM8606_PWM_FREQ_MASK (0x7) + +#define PM8606_WLED_ON (1 << 0) +#define PM8606_WLED_CURRENT(x) ((x & 0x1F) << 1) + +#define PM8606_LED_CURRENT(x) (((x >> 2) & 0x07) << 5) + +#define PM8606_VSYS_EN (1 << 1) + +#define PM8606_MISC_OSC_EN (1 << 4) + +enum { PM8607_ID_BUCK1 = 0, PM8607_ID_BUCK2, PM8607_ID_BUCK3, @@ -91,6 +186,21 @@ enum { #define PM8607_SUPPLIES_EN21 (0x33) #define PM8607_SUPPLIES_EN22 (0x34) +/* Vibrator Control Registers */ +#define PM8607_VIBRATOR_SET (0x28) +#define PM8607_VIBRATOR_PWM (0x29) + +/* GPADC Registers */ +#define PM8607_GP_BIAS1 (0x4F) +#define PM8607_MEAS_EN1 (0x50) +#define PM8607_MEAS_EN2 (0x51) +#define PM8607_MEAS_EN3 (0x52) +#define PM8607_MEAS_OFF_TIME1 (0x53) +#define PM8607_MEAS_OFF_TIME2 (0x54) +#define PM8607_TSI_PREBIAS (0x55) /* prebias time */ +#define PM8607_PD_PREBIAS (0x56) /* prebias time */ +#define PM8607_GPADC_MISC1 (0x57) + /* RTC Control Registers */ #define PM8607_RTC1 (0xA0) #define PM8607_RTC_COUNTER1 (0xA1) @@ -140,6 +250,16 @@ enum { #define PM8607_B0_MISC1_PI2C (1 << 3) #define PM8607_B0_MISC1_RESET (1 << 6) +/* bits definitions of GPADC */ +#define PM8607_GPADC_EN (1 << 0) +#define PM8607_GPADC_PREBIAS_MASK (3 << 1) +#define PM8607_GPADC_SLOT_CYCLE_MASK (3 << 3) /* slow mode */ +#define PM8607_GPADC_OFF_SCALE_MASK (3 << 5) /* GP sleep mode */ +#define PM8607_GPADC_SW_CAL_MASK (1 << 7) + +#define PM8607_PD_PREBIAS_MASK (0x1F << 0) +#define PM8607_PD_PRECHG_MASK (7 << 5) + /* Interrupt Number in 88PM8607 */ enum { PM8607_IRQ_ONKEY = 0, @@ -202,13 +322,44 @@ enum { PI2C_PORT, }; +struct pm860x_backlight_pdata { + int id; + int pwm; + int iset; + unsigned long flags; +}; + +struct pm860x_led_pdata { + int id; + int iset; + unsigned long flags; +}; + +struct pm860x_touch_pdata { + int gpadc_prebias; + int slot_cycle; + int off_scale; + int sw_cal; + int tsi_prebias; /* time, slot */ + int pen_prebias; /* time, slot */ + int pen_prechg; /* time, slot */ + unsigned long flags; +}; + struct pm860x_platform_data { + struct pm860x_backlight_pdata *backlight; + struct pm860x_led_pdata *led; + struct pm860x_touch_pdata *touch; + unsigned short companion_addr; /* I2C address of companion chip */ int i2c_port; /* Controlled by GI2C or PI2C */ int irq_mode; /* Clear interrupt by read/write(0/1) */ struct regulator_init_data *regulator[PM8607_MAX_REGULATOR]; }; +extern char pm860x_backlight_name[][MFD_NAME_SIZE]; +extern char pm860x_led_name[][MFD_NAME_SIZE]; + extern int pm860x_reg_read(struct i2c_client *, int); extern int pm860x_reg_write(struct i2c_client *, int, unsigned char); extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *); -- cgit v0.10.2 From d07e8bf83fd71567aaf9c27c3b133ab3cf8f3c4c Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 9 Nov 2009 12:41:07 -0500 Subject: backlight: Enable backlight in 88pm860x At most, three backlight device can be supported in 88pm860x driver. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c new file mode 100644 index 0000000..b8f705c --- /dev/null +++ b/drivers/video/backlight/88pm860x_bl.c @@ -0,0 +1,304 @@ +/* + * Backlight driver for Marvell Semiconductor 88PM8606 + * + * Copyright (C) 2009 Marvell International Ltd. + * Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_BRIGHTNESS (0xFF) +#define MIN_BRIGHTNESS (0) + +#define CURRENT_MASK (0x1F << 1) + +struct pm860x_backlight_data { + struct pm860x_chip *chip; + struct i2c_client *i2c; + int current_brightness; + int port; + int pwm; + int iset; +}; + +static inline int wled_a(int port) +{ + int ret; + + ret = ((port - PM8606_BACKLIGHT1) << 1) + 2; + return ret; +} + +static inline int wled_b(int port) +{ + int ret; + + ret = ((port - PM8606_BACKLIGHT1) << 1) + 3; + return ret; +} + +/* WLED2 & WLED3 share the same IDC */ +static inline int wled_idc(int port) +{ + int ret; + + switch (port) { + case PM8606_BACKLIGHT1: + case PM8606_BACKLIGHT2: + ret = ((port - PM8606_BACKLIGHT1) << 1) + 3; + break; + case PM8606_BACKLIGHT3: + default: + ret = ((port - PM8606_BACKLIGHT2) << 1) + 3; + break; + } + return ret; +} + +static int pm860x_backlight_set(struct backlight_device *bl, int brightness) +{ + struct pm860x_backlight_data *data = bl_get_data(bl); + struct pm860x_chip *chip = data->chip; + unsigned char value; + int ret; + + if (brightness > MAX_BRIGHTNESS) + value = MAX_BRIGHTNESS; + else + value = brightness; + + ret = pm860x_reg_write(data->i2c, wled_a(data->port), value); + if (ret < 0) + goto out; + + if ((data->current_brightness == 0) && brightness) { + if (data->iset) { + ret = pm860x_set_bits(data->i2c, wled_idc(data->port), + CURRENT_MASK, data->iset); + if (ret < 0) + goto out; + } + if (data->pwm) { + ret = pm860x_set_bits(data->i2c, PM8606_PWM, + PM8606_PWM_FREQ_MASK, data->pwm); + if (ret < 0) + goto out; + } + if (brightness == MAX_BRIGHTNESS) { + /* set WLED_ON bit as 100% */ + ret = pm860x_set_bits(data->i2c, wled_b(data->port), + PM8606_WLED_ON, PM8606_WLED_ON); + } + } else { + if (brightness == MAX_BRIGHTNESS) { + /* set WLED_ON bit as 100% */ + ret = pm860x_set_bits(data->i2c, wled_b(data->port), + PM8606_WLED_ON, PM8606_WLED_ON); + } else { + /* clear WLED_ON bit since it's not 100% */ + ret = pm860x_set_bits(data->i2c, wled_b(data->port), + PM8606_WLED_ON, 0); + } + } + if (ret < 0) + goto out; + + dev_dbg(chip->dev, "set brightness %d\n", value); + data->current_brightness = value; + return 0; +out: + dev_dbg(chip->dev, "set brightness %d failure with return " + "value:%d\n", value, ret); + return ret; +} + +static int pm860x_backlight_update_status(struct backlight_device *bl) +{ + int brightness = bl->props.brightness; + + if (bl->props.power != FB_BLANK_UNBLANK) + brightness = 0; + + if (bl->props.fb_blank != FB_BLANK_UNBLANK) + brightness = 0; + + if (bl->props.state & BL_CORE_SUSPENDED) + brightness = 0; + + return pm860x_backlight_set(bl, brightness); +} + +static int pm860x_backlight_get_brightness(struct backlight_device *bl) +{ + struct pm860x_backlight_data *data = bl_get_data(bl); + struct pm860x_chip *chip = data->chip; + int ret; + + ret = pm860x_reg_read(data->i2c, wled_a(data->port)); + if (ret < 0) + goto out; + data->current_brightness = ret; + dev_dbg(chip->dev, "get brightness %d\n", data->current_brightness); + return data->current_brightness; +out: + return -EINVAL; +} + +static struct backlight_ops pm860x_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = pm860x_backlight_update_status, + .get_brightness = pm860x_backlight_get_brightness, +}; + +static int __check_device(struct pm860x_backlight_pdata *pdata, char *name) +{ + struct pm860x_backlight_pdata *p = pdata; + int ret = -EINVAL; + + while (p && p->id) { + if ((p->id != PM8606_ID_BACKLIGHT) || (p->flags < 0)) + break; + + if (!strncmp(name, pm860x_backlight_name[p->flags], + MFD_NAME_SIZE)) { + ret = (int)p->flags; + break; + } + p++; + } + return ret; +} + +static int pm860x_backlight_probe(struct platform_device *pdev) +{ + struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct pm860x_platform_data *pm860x_pdata; + struct pm860x_backlight_pdata *pdata = NULL; + struct pm860x_backlight_data *data; + struct backlight_device *bl; + struct resource *res; + unsigned char value; + char name[MFD_NAME_SIZE]; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (res == NULL) { + dev_err(&pdev->dev, "No I/O resource!\n"); + return -EINVAL; + } + + if (pdev->dev.parent->platform_data) { + pm860x_pdata = pdev->dev.parent->platform_data; + pdata = pm860x_pdata->backlight; + } + if (pdata == NULL) { + dev_err(&pdev->dev, "platform data isn't assigned to " + "backlight\n"); + return -EINVAL; + } + + data = kzalloc(sizeof(struct pm860x_backlight_data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + strncpy(name, res->name, MFD_NAME_SIZE); + data->chip = chip; + data->i2c = (chip->id == CHIP_PM8606) ? chip->client \ + : chip->companion; + data->current_brightness = MAX_BRIGHTNESS; + data->pwm = pdata->pwm; + data->iset = pdata->iset; + data->port = __check_device(pdata, name); + if (data->port < 0) { + dev_err(&pdev->dev, "wrong platform data is assigned"); + return -EINVAL; + } + + bl = backlight_device_register(name, &pdev->dev, data, + &pm860x_backlight_ops); + if (IS_ERR(bl)) { + dev_err(&pdev->dev, "failed to register backlight\n"); + kfree(data); + return PTR_ERR(bl); + } + bl->props.max_brightness = MAX_BRIGHTNESS; + bl->props.brightness = MAX_BRIGHTNESS; + + platform_set_drvdata(pdev, bl); + + /* Enable reference VSYS */ + ret = pm860x_reg_read(data->i2c, PM8606_VSYS); + if (ret < 0) + goto out; + if ((ret & PM8606_VSYS_EN) == 0) { + value = ret | PM8606_VSYS_EN; + ret = pm860x_reg_write(data->i2c, PM8606_VSYS, value); + if (ret < 0) + goto out; + } + /* Enable reference OSC */ + ret = pm860x_reg_read(data->i2c, PM8606_MISC); + if (ret < 0) + goto out; + if ((ret & PM8606_MISC_OSC_EN) == 0) { + value = ret | PM8606_MISC_OSC_EN; + ret = pm860x_reg_write(data->i2c, PM8606_MISC, value); + if (ret < 0) + goto out; + } + /* read current backlight */ + ret = pm860x_backlight_get_brightness(bl); + if (ret < 0) + goto out; + + backlight_update_status(bl); + return 0; +out: + kfree(data); + return ret; +} + +static int pm860x_backlight_remove(struct platform_device *pdev) +{ + struct backlight_device *bl = platform_get_drvdata(pdev); + struct pm860x_backlight_data *data = bl_get_data(bl); + + backlight_device_unregister(bl); + kfree(data); + return 0; +} + +static struct platform_driver pm860x_backlight_driver = { + .driver = { + .name = "88pm860x-backlight", + .owner = THIS_MODULE, + }, + .probe = pm860x_backlight_probe, + .remove = pm860x_backlight_remove, +}; + +static int __init pm860x_backlight_init(void) +{ + return platform_driver_register(&pm860x_backlight_driver); +} +module_init(pm860x_backlight_init); + +static void __exit pm860x_backlight_exit(void) +{ + platform_driver_unregister(&pm860x_backlight_driver); +} +module_exit(pm860x_backlight_exit); + +MODULE_DESCRIPTION("Backlight Driver for Marvell Semiconductor 88PM8606"); +MODULE_AUTHOR("Haojian Zhuang "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:88pm860x-backlight"); diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 09bfa96..96a6b30 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -262,3 +262,9 @@ config BACKLIGHT_ADP5520 To compile this driver as a module, choose M here: the module will be called adp5520_bl. +config BACKLIGHT_88PM860X + tristate "Backlight Driver for 88PM8606 using WLED" + depends on BACKLIGHT_CLASS_DEVICE && MFD_88PM860X + help + Say Y to enable the backlight driver for Marvell 88PM8606. + diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 9a40554..802d467 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -28,4 +28,5 @@ obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o obj-$(CONFIG_BACKLIGHT_ADX) += adx_bl.o obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o +obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o -- cgit v0.10.2 From 0a2f915b405ac1a8d19d9b7cf7873f26ba682a24 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 6 Jan 2010 17:10:09 -0500 Subject: led: Enable led in 88pm860x Enable led sub device in Marvell 88PM860x. Two LED arrays can be supported. Each LED array can be used for R,G,B leds. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 8a0e1ec..e0b6431 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -17,6 +17,13 @@ config LEDS_CLASS comment "LED drivers" +config LEDS_88PM860X + tristate "LED Support for Marvell 88PM860x PMIC" + depends on LEDS_CLASS && MFD_88PM860X + help + This option enables support for on-chip LED drivers found on Marvell + Semiconductor 88PM8606 PMIC. + config LEDS_ATMEL_PWM tristate "LED Support using Atmel PWM outputs" depends on LEDS_CLASS && ATMEL_PWM diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 9e63869..d76fb32 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_LEDS_CLASS) += led-class.o obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o # LED Platform Drivers +obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c new file mode 100644 index 0000000..d196073 --- /dev/null +++ b/drivers/leds/leds-88pm860x.c @@ -0,0 +1,325 @@ +/* + * LED driver for Marvell 88PM860x + * + * Copyright (C) 2009 Marvell International Ltd. + * Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define LED_PWM_SHIFT (3) +#define LED_PWM_MASK (0x1F) +#define LED_CURRENT_MASK (0x07 << 5) + +#define LED_BLINK_ON_MASK (0x07) +#define LED_BLINK_PERIOD_MASK (0x0F << 3) +#define LED_BLINK_MASK (0x7F) + +#define LED_BLINK_ON(x) ((x & 0x7) * 66 + 66) +#define LED_BLINK_PERIOD(x) ((x & 0xF) * 530 + 930) +#define LED_BLINK_ON_MIN LED_BLINK_ON(0) +#define LED_BLINK_ON_MAX LED_BLINK_ON(0x7) +#define LED_BLINK_PERIOD_MIN LED_BLINK_PERIOD(0) +#define LED_BLINK_PERIOD_MAX LED_BLINK_PERIOD(0xE) +#define LED_TO_ON(x) ((x - 66) / 66) +#define LED_TO_PERIOD(x) ((x - 930) / 530) + +#define LED1_BLINK_EN (1 << 1) +#define LED2_BLINK_EN (1 << 2) + +enum { + SET_BRIGHTNESS, + SET_BLINK, +}; + +struct pm860x_led { + struct led_classdev cdev; + struct i2c_client *i2c; + struct work_struct work; + struct pm860x_chip *chip; + struct mutex lock; + char name[MFD_NAME_SIZE]; + + int port; + int iset; + int command; + int offset; + unsigned char brightness; + unsigned char current_brightness; + + int blink_data; + int blink_time; + int blink_on; + int blink_off; +}; + +/* return offset of color register */ +static inline int __led_off(int port) +{ + int ret = -EINVAL; + + switch (port) { + case PM8606_LED1_RED: + case PM8606_LED1_GREEN: + case PM8606_LED1_BLUE: + ret = port - PM8606_LED1_RED + PM8606_RGB1B; + break; + case PM8606_LED2_RED: + case PM8606_LED2_GREEN: + case PM8606_LED2_BLUE: + ret = port - PM8606_LED2_RED + PM8606_RGB2B; + break; + } + return ret; +} + +/* return offset of blink register */ +static inline int __blink_off(int port) +{ + int ret = -EINVAL; + + switch (port) { + case PM8606_LED1_RED: + case PM8606_LED1_GREEN: + case PM8606_LED1_BLUE: + ret = PM8606_RGB1A; + case PM8606_LED2_RED: + case PM8606_LED2_GREEN: + case PM8606_LED2_BLUE: + ret = PM8606_RGB2A; + } + return ret; +} + +static inline int __blink_ctl_mask(int port) +{ + int ret = -EINVAL; + + switch (port) { + case PM8606_LED1_RED: + case PM8606_LED1_GREEN: + case PM8606_LED1_BLUE: + ret = LED1_BLINK_EN; + break; + case PM8606_LED2_RED: + case PM8606_LED2_GREEN: + case PM8606_LED2_BLUE: + ret = LED2_BLINK_EN; + break; + } + return ret; +} + +static int __led_set(struct pm860x_led *led, int command) +{ + struct pm860x_chip *chip = led->chip; + int mask, ret; + + mutex_lock(&led->lock); + switch (command) { + case SET_BRIGHTNESS: + if ((led->current_brightness == 0) && led->brightness) { + if (led->iset) { + ret = pm860x_set_bits(led->i2c, led->offset, + LED_CURRENT_MASK, led->iset); + if (ret < 0) + goto out; + } + } else if (led->brightness == 0) { + ret = pm860x_set_bits(led->i2c, led->offset, + LED_CURRENT_MASK, 0); + if (ret < 0) + goto out; + } + ret = pm860x_set_bits(led->i2c, led->offset, LED_PWM_MASK, + led->brightness); + if (ret < 0) + goto out; + led->current_brightness = led->brightness; + dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n", + led->offset, led->brightness); + break; + case SET_BLINK: + ret = pm860x_set_bits(led->i2c, led->offset, + LED_BLINK_MASK, led->blink_data); + if (ret < 0) + goto out; + + mask = __blink_ctl_mask(led->port); + ret = pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask); + if (ret < 0) + goto out; + dev_dbg(chip->dev, "LED blink delay on:%dms, delay off:%dms\n", + led->blink_on, led->blink_off); + break; + } +out: + mutex_unlock(&led->lock); + return 0; +} + +static void pm860x_led_work(struct work_struct *work) +{ + struct pm860x_led *led; + + led = container_of(work, struct pm860x_led, work); + __led_set(led, led->command); +} + +static void pm860x_led_set(struct led_classdev *cdev, + enum led_brightness value) +{ + struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev); + + data->offset = __led_off(data->port); + data->brightness = value >> 3; + data->command = SET_BRIGHTNESS; + schedule_work(&data->work); +} + +static int pm860x_led_blink(struct led_classdev *cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev); + int period, on; + + on = *delay_on; + if ((on < LED_BLINK_ON_MIN) || (on > LED_BLINK_ON_MAX)) + return -EINVAL; + + on = LED_TO_ON(on); + on = LED_BLINK_ON(on); + + period = on + *delay_off; + if ((period < LED_BLINK_PERIOD_MIN) || (period > LED_BLINK_PERIOD_MAX)) + return -EINVAL; + period = LED_TO_PERIOD(period); + period = LED_BLINK_PERIOD(period); + + data->offset = __blink_off(data->port); + data->blink_on = on; + data->blink_off = period - data->blink_on; + data->blink_data = (period << 3) | data->blink_on; + data->command = SET_BLINK; + schedule_work(&data->work); + + return 0; +} + +static int __check_device(struct pm860x_led_pdata *pdata, char *name) +{ + struct pm860x_led_pdata *p = pdata; + int ret = -EINVAL; + + while (p && p->id) { + if ((p->id != PM8606_ID_LED) || (p->flags < 0)) + break; + + if (!strncmp(name, pm860x_led_name[p->flags], + MFD_NAME_SIZE)) { + ret = (int)p->flags; + break; + } + p++; + } + return ret; +} + +static int pm860x_led_probe(struct platform_device *pdev) +{ + struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct pm860x_platform_data *pm860x_pdata; + struct pm860x_led_pdata *pdata; + struct pm860x_led *data; + struct resource *res; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (res == NULL) { + dev_err(&pdev->dev, "No I/O resource!\n"); + return -EINVAL; + } + + if (pdev->dev.parent->platform_data) { + pm860x_pdata = pdev->dev.parent->platform_data; + pdata = pm860x_pdata->led; + } else + pdata = NULL; + + data = kzalloc(sizeof(struct pm860x_led), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + strncpy(data->name, res->name, MFD_NAME_SIZE); + dev_set_drvdata(&pdev->dev, data); + data->chip = chip; + data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion; + data->iset = pdata->iset; + data->port = __check_device(pdata, data->name); + if (data->port < 0) + return -EINVAL; + + data->current_brightness = 0; + data->cdev.name = data->name; + data->cdev.brightness_set = pm860x_led_set; + data->cdev.blink_set = pm860x_led_blink; + mutex_init(&data->lock); + INIT_WORK(&data->work, pm860x_led_work); + + ret = led_classdev_register(chip->dev, &data->cdev); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register LED: %d\n", ret); + goto out; + } + return 0; +out: + kfree(data); + return ret; +} + +static int pm860x_led_remove(struct platform_device *pdev) +{ + struct pm860x_led *data = platform_get_drvdata(pdev); + + led_classdev_unregister(&data->cdev); + kfree(data); + + return 0; +} + +static struct platform_driver pm860x_led_driver = { + .driver = { + .name = "88pm860x-led", + .owner = THIS_MODULE, + }, + .probe = pm860x_led_probe, + .remove = pm860x_led_remove, +}; + +static int __devinit pm860x_led_init(void) +{ + return platform_driver_register(&pm860x_led_driver); +} +module_init(pm860x_led_init); + +static void __devexit pm860x_led_exit(void) +{ + platform_driver_unregister(&pm860x_led_driver); +} +module_exit(pm860x_led_exit); + +MODULE_DESCRIPTION("LED driver for Marvell PM860x"); +MODULE_AUTHOR("Haojian Zhuang "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:88pm860x-led"); -- cgit v0.10.2 From 866a98ae6e1a9768cd25fe1185481569c7e4b4a9 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Tue, 15 Dec 2009 16:06:17 -0500 Subject: input: Enable touch on 88pm860x Enable touchscreen driver for the 88pm860x multi function core. Signed-off-by: Haojian Zhuang Acked-by: Dmitry Torokhov Signed-off-by: Samuel Ortiz diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c new file mode 100644 index 0000000..56254d2 --- /dev/null +++ b/drivers/input/touchscreen/88pm860x-ts.c @@ -0,0 +1,241 @@ +/* + * Touchscreen driver for Marvell 88PM860x + * + * Copyright (C) 2009 Marvell International Ltd. + * Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include + +#define MEAS_LEN (8) +#define ACCURATE_BIT (12) + +/* touch register */ +#define MEAS_EN3 (0x52) + +#define MEAS_TSIX_1 (0x8D) +#define MEAS_TSIX_2 (0x8E) +#define MEAS_TSIY_1 (0x8F) +#define MEAS_TSIY_2 (0x90) +#define MEAS_TSIZ1_1 (0x91) +#define MEAS_TSIZ1_2 (0x92) +#define MEAS_TSIZ2_1 (0x93) +#define MEAS_TSIZ2_2 (0x94) + +/* bit definitions of touch */ +#define MEAS_PD_EN (1 << 3) +#define MEAS_TSIX_EN (1 << 4) +#define MEAS_TSIY_EN (1 << 5) +#define MEAS_TSIZ1_EN (1 << 6) +#define MEAS_TSIZ2_EN (1 << 7) + +struct pm860x_touch { + struct input_dev *idev; + struct i2c_client *i2c; + struct pm860x_chip *chip; + int irq; + int res_x; /* resistor of Xplate */ +}; + +static irqreturn_t pm860x_touch_handler(int irq, void *data) +{ + struct pm860x_touch *touch = data; + struct pm860x_chip *chip = touch->chip; + unsigned char buf[MEAS_LEN]; + int x, y, pen_down; + int z1, z2, rt = 0; + int ret; + + pm860x_mask_irq(chip, irq); + ret = pm860x_bulk_read(touch->i2c, MEAS_TSIX_1, MEAS_LEN, buf); + if (ret < 0) + goto out; + + pen_down = buf[1] & (1 << 6); + x = ((buf[0] & 0xFF) << 4) | (buf[1] & 0x0F); + y = ((buf[2] & 0xFF) << 4) | (buf[3] & 0x0F); + z1 = ((buf[4] & 0xFF) << 4) | (buf[5] & 0x0F); + z2 = ((buf[6] & 0xFF) << 4) | (buf[7] & 0x0F); + + if (pen_down) { + if ((x != 0) && (z1 != 0) && (touch->res_x != 0)) { + rt = z2 / z1 - 1; + rt = (rt * touch->res_x * x) >> ACCURATE_BIT; + dev_dbg(chip->dev, "z1:%d, z2:%d, rt:%d\n", + z1, z2, rt); + } + input_report_abs(touch->idev, ABS_X, x); + input_report_abs(touch->idev, ABS_Y, y); + input_report_abs(touch->idev, ABS_PRESSURE, rt); + input_report_key(touch->idev, BTN_TOUCH, 1); + dev_dbg(chip->dev, "pen down at [%d, %d].\n", x, y); + } else { + input_report_abs(touch->idev, ABS_PRESSURE, 0); + input_report_key(touch->idev, BTN_TOUCH, 0); + dev_dbg(chip->dev, "pen release\n"); + } + input_sync(touch->idev); + pm860x_unmask_irq(chip, irq); + +out: + return IRQ_HANDLED; +} + +static int pm860x_touch_open(struct input_dev *dev) +{ + struct pm860x_touch *touch = input_get_drvdata(dev); + struct pm860x_chip *chip = touch->chip; + int data, ret; + + data = MEAS_PD_EN | MEAS_TSIX_EN | MEAS_TSIY_EN + | MEAS_TSIZ1_EN | MEAS_TSIZ2_EN; + ret = pm860x_set_bits(touch->i2c, MEAS_EN3, data, data); + if (ret < 0) + goto out; + pm860x_unmask_irq(chip, touch->irq); + return 0; +out: + return ret; +} + +static void pm860x_touch_close(struct input_dev *dev) +{ + struct pm860x_touch *touch = input_get_drvdata(dev); + struct pm860x_chip *chip = touch->chip; + int data; + + data = MEAS_PD_EN | MEAS_TSIX_EN | MEAS_TSIY_EN + | MEAS_TSIZ1_EN | MEAS_TSIZ2_EN; + pm860x_set_bits(touch->i2c, MEAS_EN3, data, 0); + pm860x_mask_irq(chip, touch->irq); +} + +static int __devinit pm860x_touch_probe(struct platform_device *pdev) +{ + struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct pm860x_platform_data *pm860x_pdata = \ + pdev->dev.parent->platform_data; + struct pm860x_touch_pdata *pdata = NULL; + struct pm860x_touch *touch; + int irq, ret; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "No IRQ resource!\n"); + return -EINVAL; + } + + if (!pm860x_pdata) { + dev_err(&pdev->dev, "platform data is missing\n"); + return -EINVAL; + } + + pdata = pm860x_pdata->touch; + if (!pdata) { + dev_err(&pdev->dev, "touchscreen data is missing\n"); + return -EINVAL; + } + + touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL); + if (touch == NULL) + return -ENOMEM; + dev_set_drvdata(&pdev->dev, touch); + + touch->idev = input_allocate_device(); + if (touch->idev == NULL) { + dev_err(&pdev->dev, "Failed to allocate input device!\n"); + ret = -ENOMEM; + goto out; + } + + touch->idev->name = "88pm860x-touch"; + touch->idev->phys = "88pm860x/input0"; + touch->idev->id.bustype = BUS_I2C; + touch->idev->dev.parent = &pdev->dev; + touch->idev->open = pm860x_touch_open; + touch->idev->close = pm860x_touch_close; + touch->chip = chip; + touch->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; + touch->irq = irq; + touch->res_x = pdata->res_x; + input_set_drvdata(touch->idev, touch); + + ret = pm860x_request_irq(chip, irq, pm860x_touch_handler, touch); + if (ret < 0) + goto out_irq; + + __set_bit(EV_ABS, touch->idev->evbit); + __set_bit(ABS_X, touch->idev->absbit); + __set_bit(ABS_Y, touch->idev->absbit); + __set_bit(ABS_PRESSURE, touch->idev->absbit); + __set_bit(EV_SYN, touch->idev->evbit); + __set_bit(EV_KEY, touch->idev->evbit); + __set_bit(BTN_TOUCH, touch->idev->keybit); + + input_set_abs_params(touch->idev, ABS_X, 0, 1 << ACCURATE_BIT, 0, 0); + input_set_abs_params(touch->idev, ABS_Y, 0, 1 << ACCURATE_BIT, 0, 0); + input_set_abs_params(touch->idev, ABS_PRESSURE, 0, 1 << ACCURATE_BIT, + 0, 0); + + ret = input_register_device(touch->idev); + if (ret < 0) { + dev_err(chip->dev, "Failed to register touch!\n"); + goto out_rg; + } + + platform_set_drvdata(pdev, touch); + return 0; +out_rg: + pm860x_free_irq(chip, irq); +out_irq: + input_free_device(touch->idev); +out: + kfree(touch); + return ret; +} + +static int __devexit pm860x_touch_remove(struct platform_device *pdev) +{ + struct pm860x_touch *touch = platform_get_drvdata(pdev); + + input_unregister_device(touch->idev); + pm860x_free_irq(touch->chip, touch->irq); + platform_set_drvdata(pdev, NULL); + kfree(touch); + return 0; +} + +static struct platform_driver pm860x_touch_driver = { + .driver = { + .name = "88pm860x-touch", + .owner = THIS_MODULE, + }, + .probe = pm860x_touch_probe, + .remove = __devexit_p(pm860x_touch_remove), +}; + +static int __init pm860x_touch_init(void) +{ + return platform_driver_register(&pm860x_touch_driver); +} +module_init(pm860x_touch_init); + +static void __exit pm860x_touch_exit(void) +{ + platform_driver_unregister(&pm860x_touch_driver); +} +module_exit(pm860x_touch_exit); + +MODULE_DESCRIPTION("Touchscreen driver for Marvell Semiconductor 88PM860x"); +MODULE_AUTHOR("Haojian Zhuang "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:88pm860x-touch"); + diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 6457e06..7208654 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -11,6 +11,18 @@ menuconfig INPUT_TOUCHSCREEN if INPUT_TOUCHSCREEN +config TOUCHSCREEN_88PM860X + tristate "Marvell 88PM860x touchscreen" + depends on MFD_88PM860X + help + Say Y here if you have a 88PM860x PMIC and want to enable + support for the built-in touchscreen. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called 88pm860x-ts. + config TOUCHSCREEN_ADS7846 tristate "ADS7846/TSC2046 and ADS7843 based touchscreens" depends on SPI_MASTER diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index d61a3b4..7fef7d5 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -6,6 +6,7 @@ wm97xx-ts-y := wm97xx-core.o +obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h index d7edf11..80bc82a 100644 --- a/include/linux/mfd/88pm860x.h +++ b/include/linux/mfd/88pm860x.h @@ -343,6 +343,7 @@ struct pm860x_touch_pdata { int tsi_prebias; /* time, slot */ int pen_prebias; /* time, slot */ int pen_prechg; /* time, slot */ + int res_x; /* resistor of Xplate */ unsigned long flags; }; -- cgit v0.10.2 From 34a4b2391e9fbd12de9817de4ae409528bd7d7b6 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Thu, 10 Dec 2009 06:06:17 -0500 Subject: regulator: Unsupport 88pm8607 A0 and A1 Remove the support 88PM8607 A0/A1 stepping. There's some register definition changes in B0 stepping. It can make software more efficient. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 97897a6..5fb83e2 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -48,7 +48,6 @@ static inline int check_range(struct pm8607_regulator_info *info, static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - uint8_t chip_id = info->chip->chip_version; int ret = -EINVAL; switch (info->desc.id) { @@ -90,79 +89,29 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) case PM8607_ID_LDO2: case PM8607_ID_LDO3: case PM8607_ID_LDO9: - switch (chip_id) { - case PM8607_CHIP_A0: - case PM8607_CHIP_A1: - ret = (index < 3) ? (index * 50000 + 1800000) : - ((index < 8) ? (index * 50000 + 2550000) : - -EINVAL); - break; - case PM8607_CHIP_B0: - ret = (index < 3) ? (index * 50000 + 1800000) : - ((index < 7) ? (index * 50000 + 2550000) : - 3300000); - break; - } + ret = (index < 3) ? (index * 50000 + 1800000) : + ((index < 7) ? (index * 50000 + 2550000) : + 3300000); break; case PM8607_ID_LDO4: - switch (chip_id) { - case PM8607_CHIP_A0: - case PM8607_CHIP_A1: - ret = (index < 3) ? (index * 50000 + 1800000) : - ((index < 8) ? (index * 50000 + 2550000) : - -EINVAL); - break; - case PM8607_CHIP_B0: - ret = (index < 3) ? (index * 50000 + 1800000) : - ((index < 6) ? (index * 50000 + 2550000) : - ((index == 6) ? 2900000 : 3300000)); - break; - } + ret = (index < 3) ? (index * 50000 + 1800000) : + ((index < 6) ? (index * 50000 + 2550000) : + ((index == 6) ? 2900000 : 3300000)); break; case PM8607_ID_LDO6: - switch (chip_id) { - case PM8607_CHIP_A0: - case PM8607_CHIP_A1: - ret = (index < 3) ? (index * 50000 + 1800000) : - ((index < 8) ? (index * 50000 + 2450000) : - -EINVAL); - break; - case PM8607_CHIP_B0: - ret = (index < 2) ? (index * 50000 + 1800000) : - ((index < 7) ? (index * 50000 + 2500000) : - 3300000); - break; - } + ret = (index < 2) ? (index * 50000 + 1800000) : + ((index < 7) ? (index * 50000 + 2500000) : + 3300000); break; case PM8607_ID_LDO10: - switch (chip_id) { - case PM8607_CHIP_A0: - case PM8607_CHIP_A1: - ret = (index < 3) ? (index * 50000 + 1800000) : - ((index < 8) ? (index * 50000 + 2550000) : - 1200000); - break; - case PM8607_CHIP_B0: - ret = (index < 3) ? (index * 50000 + 1800000) : - ((index < 7) ? (index * 50000 + 2550000) : - ((index == 7) ? 3300000 : 1200000)); - break; - } + ret = (index < 3) ? (index * 50000 + 1800000) : + ((index < 7) ? (index * 50000 + 2550000) : + ((index == 7) ? 3300000 : 1200000)); break; case PM8607_ID_LDO14: - switch (chip_id) { - case PM8607_CHIP_A0: - case PM8607_CHIP_A1: - ret = (index < 3) ? (index * 50000 + 1800000) : - ((index < 8) ? (index * 50000 + 2550000) : - -EINVAL); - break; - case PM8607_CHIP_B0: - ret = (index < 2) ? (index * 50000 + 1800000) : - ((index < 7) ? (index * 50000 + 2600000) : - 3300000); - break; - } + ret = (index < 2) ? (index * 50000 + 1800000) : + ((index < 7) ? (index * 50000 + 2600000) : + 3300000); break; } return ret; @@ -171,7 +120,6 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - uint8_t chip_id = info->chip->chip_version; int val = -ENOENT; int ret; @@ -256,161 +204,77 @@ static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) case PM8607_ID_LDO2: case PM8607_ID_LDO3: case PM8607_ID_LDO9: - switch (chip_id) { - case PM8607_CHIP_A0: - case PM8607_CHIP_A1: - if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */ - if (min_uV <= 1800000) - val = 0; - else if (min_uV <= 1900000) - val = (min_uV - 1750001) / 50000; - else - val = 3; /* 2700mV */ - else { /* 2700mV ~ 2900mV / 50mV */ - if (min_uV <= 2900000) { - val = (min_uV - 2650001) / 50000; - val += 3; - } else - val = -EINVAL; - } - break; - case PM8607_CHIP_B0: - if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ - if (min_uV <= 1800000) - val = 0; - else if (min_uV <= 1900000) - val = (min_uV - 1750001) / 50000; - else - val = 3; /* 2700mV */ - } else { /* 2700mV ~ 2850mV / 50mV */ - if (min_uV <= 2850000) { - val = (min_uV - 2650001) / 50000; - val += 3; - } else if (min_uV <= 3300000) - val = 7; - else - val = -EINVAL; - } - break; + if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ + if (min_uV <= 1800000) + val = 0; + else if (min_uV <= 1900000) + val = (min_uV - 1750001) / 50000; + else + val = 3; /* 2700mV */ + } else { /* 2700mV ~ 2850mV / 50mV */ + if (min_uV <= 2850000) { + val = (min_uV - 2650001) / 50000; + val += 3; + } else if (min_uV <= 3300000) + val = 7; + else + val = -EINVAL; } break; case PM8607_ID_LDO4: - switch (chip_id) { - case PM8607_CHIP_A0: - case PM8607_CHIP_A1: - if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */ - if (min_uV <= 1800000) - val = 0; - else if (min_uV <= 1900000) - val = (min_uV - 1750001) / 50000; - else - val = 3; /* 2700mV */ - else { /* 2700mV ~ 2900mV / 50mV */ - if (min_uV <= 2900000) { - val = (min_uV - 2650001) / 50000; - val += 3; - } else - val = -EINVAL; - } - break; - case PM8607_CHIP_B0: - if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ - if (min_uV <= 1800000) - val = 0; - else if (min_uV <= 1900000) - val = (min_uV - 1750001) / 50000; - else - val = 3; /* 2700mV */ - } else { /* 2700mV ~ 2800mV / 50mV */ - if (min_uV <= 2850000) { - val = (min_uV - 2650001) / 50000; - val += 3; - } else if (min_uV <= 2900000) - val = 6; - else if (min_uV <= 3300000) - val = 7; - else - val = -EINVAL; - } - break; + if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ + if (min_uV <= 1800000) + val = 0; + else if (min_uV <= 1900000) + val = (min_uV - 1750001) / 50000; + else + val = 3; /* 2700mV */ + } else { /* 2700mV ~ 2800mV / 50mV */ + if (min_uV <= 2850000) { + val = (min_uV - 2650001) / 50000; + val += 3; + } else if (min_uV <= 2900000) + val = 6; + else if (min_uV <= 3300000) + val = 7; + else + val = -EINVAL; } break; case PM8607_ID_LDO6: - switch (chip_id) { - case PM8607_CHIP_A0: - case PM8607_CHIP_A1: - if (min_uV < 2600000) { /* 1800mV ~ 1900mV / 50mV */ - if (min_uV <= 1800000) - val = 0; - else if (min_uV <= 1900000) - val = (min_uV - 1750001) / 50000; - else - val = 3; /* 2600mV */ - } else { /* 2600mV ~ 2800mV / 50mV */ - if (min_uV <= 2800000) { - val = (min_uV - 2550001) / 50000; - val += 3; - } else - val = -EINVAL; - } - break; - case PM8607_CHIP_B0: - if (min_uV < 2600000) { /* 1800mV ~ 1850mV / 50mV */ - if (min_uV <= 1800000) - val = 0; - else if (min_uV <= 1850000) - val = (min_uV - 1750001) / 50000; - else - val = 2; /* 2600mV */ - } else { /* 2600mV ~ 2800mV / 50mV */ - if (min_uV <= 2800000) { - val = (min_uV - 2550001) / 50000; - val += 2; - } else if (min_uV <= 3300000) - val = 7; - else - val = -EINVAL; - } - break; + if (min_uV < 2600000) { /* 1800mV ~ 1850mV / 50mV */ + if (min_uV <= 1800000) + val = 0; + else if (min_uV <= 1850000) + val = (min_uV - 1750001) / 50000; + else + val = 2; /* 2600mV */ + } else { /* 2600mV ~ 2800mV / 50mV */ + if (min_uV <= 2800000) { + val = (min_uV - 2550001) / 50000; + val += 2; + } else if (min_uV <= 3300000) + val = 7; + else + val = -EINVAL; } break; case PM8607_ID_LDO14: - switch (chip_id) { - case PM8607_CHIP_A0: - case PM8607_CHIP_A1: - if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ - if (min_uV <= 1800000) - val = 0; - else if (min_uV <= 1900000) - val = (min_uV - 1750001) / 50000; - else - val = 3; /* 2700mV */ - } else { /* 2700mV ~ 2900mV / 50mV */ - if (min_uV <= 2900000) { - val = (min_uV - 2650001) / 50000; - val += 3; - } else - val = -EINVAL; - } - break; - case PM8607_CHIP_B0: - if (min_uV < 2700000) { /* 1800mV ~ 1850mV / 50mV */ - if (min_uV <= 1800000) - val = 0; - else if (min_uV <= 1850000) - val = (min_uV - 1750001) / 50000; - else - val = 2; /* 2700mV */ - } else { /* 2700mV ~ 2900mV / 50mV */ - if (min_uV <= 2900000) { - val = (min_uV - 2650001) / 50000; - val += 2; - } else if (min_uV <= 3300000) - val = 7; - else - val = -EINVAL; - } - break; + if (min_uV < 2700000) { /* 1800mV ~ 1850mV / 50mV */ + if (min_uV <= 1800000) + val = 0; + else if (min_uV <= 1850000) + val = (min_uV - 1750001) / 50000; + else + val = 2; /* 2700mV */ + } else { /* 2700mV ~ 2900mV / 50mV */ + if (min_uV <= 2900000) { + val = (min_uV - 2650001) / 50000; + val += 2; + } else if (min_uV <= 3300000) + val = 7; + else + val = -EINVAL; } break; } -- cgit v0.10.2 From d50f8f339f6901fccc9d4292b65ce8b69d7413d4 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 8 Jan 2010 12:29:23 +0100 Subject: mfd: Initial max8925 support Basic Max8925 support, which is a power management IC from Maxim Semiconductor. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 815907e..ee416ee 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -194,6 +194,15 @@ config PMIC_ADP5520 individual components like LCD backlight, LEDs, GPIOs and Kepad under the corresponding menus. +config MFD_MAX8925 + tristate "Maxim Semiconductor MAX8925 PMIC Support" + depends on I2C + help + Say yes here to support for Maxim Semiconductor MAX8925. This is + a Power Management IC. This driver provies common support for + accessing the device, additional drivers must be enabled in order + to use the functionality of the device. + config MFD_WM8400 tristate "Support Wolfson Microelectronics WM8400" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 1e3ae06..2616357 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -49,6 +49,8 @@ endif obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o obj-$(CONFIG_PMIC_DA903X) += da903x.o +max8925-objs := max8925-core.o max8925-i2c.o +obj-$(CONFIG_MFD_MAX8925) += max8925.o obj-$(CONFIG_MFD_PCF50633) += pcf50633-core.o obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c new file mode 100644 index 0000000..3e26267 --- /dev/null +++ b/drivers/mfd/max8925-core.c @@ -0,0 +1,262 @@ +/* + * Base driver for Maxim MAX8925 + * + * Copyright (C) 2009 Marvell International Ltd. + * Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define IRQ_MODE_STATUS 0 +#define IRQ_MODE_MASK 1 + +static int __get_irq_offset(struct max8925_chip *chip, int irq, int mode, + int *offset, int *bit) +{ + if (!offset || !bit) + return -EINVAL; + + switch (chip->chip_id) { + case MAX8925_GPM: + *bit = irq % BITS_PER_BYTE; + if (irq < (BITS_PER_BYTE << 1)) { /* irq = [0,15] */ + *offset = (mode) ? MAX8925_CHG_IRQ1_MASK + : MAX8925_CHG_IRQ1; + if (irq >= BITS_PER_BYTE) + (*offset)++; + } else { /* irq = [16,31] */ + *offset = (mode) ? MAX8925_ON_OFF_IRQ1_MASK + : MAX8925_ON_OFF_IRQ1; + if (irq >= (BITS_PER_BYTE * 3)) + (*offset)++; + } + break; + case MAX8925_ADC: + *bit = irq % BITS_PER_BYTE; + *offset = (mode) ? MAX8925_TSC_IRQ_MASK : MAX8925_TSC_IRQ; + break; + default: + goto out; + } + return 0; +out: + dev_err(chip->dev, "Wrong irq #%d is assigned\n", irq); + return -EINVAL; +} + +static int __check_irq(int irq) +{ + if ((irq < 0) || (irq >= MAX8925_NUM_IRQ)) + return -EINVAL; + return 0; +} + +int max8925_mask_irq(struct max8925_chip *chip, int irq) +{ + int offset, bit, ret; + + ret = __get_irq_offset(chip, irq, IRQ_MODE_MASK, &offset, &bit); + if (ret < 0) + return ret; + ret = max8925_set_bits(chip->i2c, offset, 1 << bit, 1 << bit); + return ret; +} + +int max8925_unmask_irq(struct max8925_chip *chip, int irq) +{ + int offset, bit, ret; + + ret = __get_irq_offset(chip, irq, IRQ_MODE_MASK, &offset, &bit); + if (ret < 0) + return ret; + ret = max8925_set_bits(chip->i2c, offset, 1 << bit, 0); + return ret; +} + +#define INT_STATUS_NUM (MAX8925_NUM_IRQ / BITS_PER_BYTE) + +static irqreturn_t max8925_irq_thread(int irq, void *data) +{ + struct max8925_chip *chip = data; + unsigned long irq_status[INT_STATUS_NUM]; + unsigned char status_buf[INT_STATUS_NUM << 1]; + int i, ret; + + memset(irq_status, 0, sizeof(unsigned long) * INT_STATUS_NUM); + + /* all these interrupt status registers are read-only */ + switch (chip->chip_id) { + case MAX8925_GPM: + ret = max8925_bulk_read(chip->i2c, MAX8925_CHG_IRQ1, + 4, status_buf); + if (ret < 0) + goto out; + ret = max8925_bulk_read(chip->i2c, MAX8925_ON_OFF_IRQ1, + 2, &status_buf[4]); + if (ret < 0) + goto out; + ret = max8925_bulk_read(chip->i2c, MAX8925_ON_OFF_IRQ2, + 2, &status_buf[6]); + if (ret < 0) + goto out; + /* clear masked interrupt status */ + status_buf[0] &= (~status_buf[2] & CHG_IRQ1_MASK); + irq_status[0] |= status_buf[0]; + status_buf[1] &= (~status_buf[3] & CHG_IRQ2_MASK); + irq_status[0] |= (status_buf[1] << BITS_PER_BYTE); + status_buf[4] &= (~status_buf[5] & ON_OFF_IRQ1_MASK); + irq_status[0] |= (status_buf[4] << (BITS_PER_BYTE * 2)); + status_buf[6] &= (~status_buf[7] & ON_OFF_IRQ2_MASK); + irq_status[0] |= (status_buf[6] << (BITS_PER_BYTE * 3)); + break; + case MAX8925_ADC: + ret = max8925_bulk_read(chip->i2c, MAX8925_TSC_IRQ, + 2, status_buf); + if (ret < 0) + goto out; + /* clear masked interrupt status */ + status_buf[0] &= (~status_buf[1] & TSC_IRQ_MASK); + irq_status[0] |= status_buf[0]; + break; + default: + goto out; + } + + for_each_bit(i, &irq_status[0], MAX8925_NUM_IRQ) { + clear_bit(i, irq_status); + dev_dbg(chip->dev, "Servicing IRQ #%d in %s\n", i, chip->name); + + mutex_lock(&chip->irq_lock); + if (chip->irq[i].handler) + chip->irq[i].handler(i, chip->irq[i].data); + else { + max8925_mask_irq(chip, i); + dev_err(chip->dev, "Noboday cares IRQ #%d in %s. " + "Now mask it.\n", i, chip->name); + } + mutex_unlock(&chip->irq_lock); + } +out: + return IRQ_HANDLED; +} + +int max8925_request_irq(struct max8925_chip *chip, int irq, + irq_handler_t handler, void *data) +{ + if ((__check_irq(irq) < 0) || !handler) + return -EINVAL; + + mutex_lock(&chip->irq_lock); + chip->irq[irq].handler = handler; + chip->irq[irq].data = data; + mutex_unlock(&chip->irq_lock); + return 0; +} +EXPORT_SYMBOL(max8925_request_irq); + +int max8925_free_irq(struct max8925_chip *chip, int irq) +{ + if (__check_irq(irq) < 0) + return -EINVAL; + + mutex_lock(&chip->irq_lock); + chip->irq[irq].handler = NULL; + chip->irq[irq].data = NULL; + mutex_unlock(&chip->irq_lock); + return 0; +} +EXPORT_SYMBOL(max8925_free_irq); + +static int __devinit device_gpm_init(struct max8925_chip *chip, + struct i2c_client *i2c, + struct max8925_platform_data *pdata) +{ + int ret; + + /* mask all IRQs */ + ret = max8925_set_bits(i2c, MAX8925_CHG_IRQ1_MASK, 0x7, 0x7); + if (ret < 0) + goto out; + ret = max8925_set_bits(i2c, MAX8925_CHG_IRQ2_MASK, 0xff, 0xff); + if (ret < 0) + goto out; + ret = max8925_set_bits(i2c, MAX8925_ON_OFF_IRQ1_MASK, 0xff, 0xff); + if (ret < 0) + goto out; + ret = max8925_set_bits(i2c, MAX8925_ON_OFF_IRQ2_MASK, 0x3, 0x3); + if (ret < 0) + goto out; + + chip->name = "GPM"; + memset(chip->irq, 0, sizeof(struct max8925_irq) * MAX8925_NUM_IRQ); + ret = request_threaded_irq(i2c->irq, NULL, max8925_irq_thread, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "max8925-gpm", chip); + if (ret < 0) { + dev_err(chip->dev, "Failed to request IRQ #%d.\n", i2c->irq); + goto out; + } + chip->chip_irq = i2c->irq; + + /* enable hard-reset for ONKEY power-off */ + max8925_set_bits(i2c, MAX8925_SYSENSEL, 0x80, 0x80); +out: + return ret; +} + +static int __devinit device_adc_init(struct max8925_chip *chip, + struct i2c_client *i2c, + struct max8925_platform_data *pdata) +{ + int ret; + + /* mask all IRQs */ + ret = max8925_set_bits(i2c, MAX8925_TSC_IRQ_MASK, 3, 3); + + chip->name = "ADC"; + memset(chip->irq, 0, sizeof(struct max8925_irq) * MAX8925_NUM_IRQ); + ret = request_threaded_irq(i2c->irq, NULL, max8925_irq_thread, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "max8925-adc", chip); + if (ret < 0) { + dev_err(chip->dev, "Failed to request IRQ #%d.\n", i2c->irq); + goto out; + } + chip->chip_irq = i2c->irq; +out: + return ret; +} + +int __devinit max8925_device_init(struct max8925_chip *chip, + struct max8925_platform_data *pdata) +{ + switch (chip->chip_id) { + case MAX8925_GPM: + device_gpm_init(chip, chip->i2c, pdata); + break; + case MAX8925_ADC: + device_adc_init(chip, chip->i2c, pdata); + break; + } + return 0; +} + +void max8925_device_exit(struct max8925_chip *chip) +{ + if (chip->chip_irq >= 0) + free_irq(chip->chip_irq, chip); +} + +MODULE_DESCRIPTION("PMIC Driver for Maxim MAX8925"); +MODULE_AUTHOR("Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include + +static inline int max8925_read_device(struct i2c_client *i2c, + int reg, int bytes, void *dest) +{ + unsigned char data; + unsigned char *buf; + int ret; + + buf = kzalloc(bytes + 1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + data = (unsigned char)reg; + ret = i2c_master_send(i2c, &data, 1); + if (ret < 0) + return ret; + + ret = i2c_master_recv(i2c, buf, bytes + 1); + if (ret < 0) + return ret; + memcpy(dest, buf, bytes); + return 0; +} + +static inline int max8925_write_device(struct i2c_client *i2c, + int reg, int bytes, void *src) +{ + unsigned char buf[bytes + 1]; + int ret; + + buf[0] = (unsigned char)reg; + memcpy(&buf[1], src, bytes); + + ret = i2c_master_send(i2c, buf, bytes + 1); + if (ret < 0) + return ret; + return 0; +} + +int max8925_reg_read(struct i2c_client *i2c, int reg) +{ + struct max8925_chip *chip = i2c_get_clientdata(i2c); + unsigned char data; + int ret; + + mutex_lock(&chip->io_lock); + ret = max8925_read_device(i2c, reg, 1, &data); + mutex_unlock(&chip->io_lock); + + if (ret < 0) + return ret; + else + return (int)data; +} +EXPORT_SYMBOL(max8925_reg_read); + +int max8925_reg_write(struct i2c_client *i2c, int reg, + unsigned char data) +{ + struct max8925_chip *chip = i2c_get_clientdata(i2c); + int ret; + + mutex_lock(&chip->io_lock); + ret = max8925_write_device(i2c, reg, 1, &data); + mutex_unlock(&chip->io_lock); + + return ret; +} +EXPORT_SYMBOL(max8925_reg_write); + +int max8925_bulk_read(struct i2c_client *i2c, int reg, + int count, unsigned char *buf) +{ + struct max8925_chip *chip = i2c_get_clientdata(i2c); + int ret; + + mutex_lock(&chip->io_lock); + ret = max8925_read_device(i2c, reg, count, buf); + mutex_unlock(&chip->io_lock); + + return ret; +} +EXPORT_SYMBOL(max8925_bulk_read); + +int max8925_bulk_write(struct i2c_client *i2c, int reg, + int count, unsigned char *buf) +{ + struct max8925_chip *chip = i2c_get_clientdata(i2c); + int ret; + + mutex_lock(&chip->io_lock); + ret = max8925_write_device(i2c, reg, count, buf); + mutex_unlock(&chip->io_lock); + + return ret; +} +EXPORT_SYMBOL(max8925_bulk_write); + +int max8925_set_bits(struct i2c_client *i2c, int reg, + unsigned char mask, unsigned char data) +{ + struct max8925_chip *chip = i2c_get_clientdata(i2c); + unsigned char value; + int ret; + + mutex_lock(&chip->io_lock); + ret = max8925_read_device(i2c, reg, 1, &value); + if (ret < 0) + goto out; + value &= ~mask; + value |= data; + ret = max8925_write_device(i2c, reg, 1, &value); +out: + mutex_unlock(&chip->io_lock); + return ret; +} +EXPORT_SYMBOL(max8925_set_bits); + + +static const struct i2c_device_id max8925_id_table[] = { + { "max8925", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, max8925_id_table); + +static int __devinit max8925_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct max8925_platform_data *pdata = client->dev.platform_data; + struct max8925_chip *chip; + + if (!pdata) { + pr_info("%s: platform data is missing\n", __func__); + return -EINVAL; + } + if ((pdata->chip_id <= MAX8925_INVALID) + || (pdata->chip_id >= MAX8925_MAX)) { + pr_info("#%s: wrong chip identification\n", __func__); + return -EINVAL; + } + + chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + chip->i2c = client; + chip->chip_id = pdata->chip_id; + i2c_set_clientdata(client, chip); + chip->dev = &client->dev; + mutex_init(&chip->io_lock); + dev_set_drvdata(chip->dev, chip); + max8925_device_init(chip, pdata); + + return 0; +} + +static int __devexit max8925_remove(struct i2c_client *client) +{ + struct max8925_chip *chip = i2c_get_clientdata(client); + + max8925_device_exit(chip); + i2c_set_clientdata(client, NULL); + kfree(chip); + return 0; +} + +static struct i2c_driver max8925_driver = { + .driver = { + .name = "max8925", + .owner = THIS_MODULE, + }, + .probe = max8925_probe, + .remove = __devexit_p(max8925_remove), + .id_table = max8925_id_table, +}; + +static int __init max8925_i2c_init(void) +{ + int ret; + + ret = i2c_add_driver(&max8925_driver); + if (ret != 0) + pr_err("Failed to register MAX8925 I2C driver: %d\n", ret); + return ret; +} +subsys_initcall(max8925_i2c_init); + +static void __exit max8925_i2c_exit(void) +{ + i2c_del_driver(&max8925_driver); +} +module_exit(max8925_i2c_exit); + +MODULE_DESCRIPTION("I2C Driver for Maxim 8925"); +MODULE_AUTHOR("Haojian Zhuang "); +MODULE_LICENSE("GPL"); diff --git a/include/linux/mfd/max8925.h b/include/linux/mfd/max8925.h new file mode 100644 index 0000000..2326246 --- /dev/null +++ b/include/linux/mfd/max8925.h @@ -0,0 +1,119 @@ +/* + * Maxim8925 Interface + * + * Copyright (C) 2009 Marvell International Ltd. + * Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_MFD_MAX8925_H +#define __LINUX_MFD_MAX8925_H + +#include + +/* Charger registers */ +#define MAX8925_CHG_IRQ1 (0x7e) +#define MAX8925_CHG_IRQ2 (0x7f) +#define MAX8925_CHG_IRQ1_MASK (0x80) +#define MAX8925_CHG_IRQ2_MASK (0x81) + +/* GPM registers */ +#define MAX8925_SYSENSEL (0x00) +#define MAX8925_ON_OFF_IRQ1 (0x01) +#define MAX8925_ON_OFF_IRQ1_MASK (0x02) +#define MAX8925_ON_OFF_STAT (0x03) +#define MAX8925_ON_OFF_IRQ2 (0x0d) +#define MAX8925_ON_OFF_IRQ2_MASK (0x0e) +#define MAX8925_RESET_CNFG (0x0f) + +/* Touch registers */ +#define MAX8925_TSC_IRQ (0x00) +#define MAX8925_TSC_IRQ_MASK (0x01) + +/* RTC registers */ +#define MAX8925_RTC_STATUS (0x1a) +#define MAX8925_RTC_IRQ (0x1c) +#define MAX8925_RTC_IRQ_MASK (0x1d) + +/* bit definitions */ +#define CHG_IRQ1_MASK (0x07) +#define CHG_IRQ2_MASK (0xff) +#define ON_OFF_IRQ1_MASK (0xff) +#define ON_OFF_IRQ2_MASK (0x03) +#define TSC_IRQ_MASK (0x03) +#define RTC_IRQ_MASK (0x0c) + +#define MAX8925_NUM_IRQ (32) + +#define MAX8925_NAME_SIZE (32) + +enum { + MAX8925_INVALID = 0, + MAX8925_RTC, + MAX8925_ADC, + MAX8925_GPM, /* general power management */ + MAX8925_MAX, +}; + +#define MAX8925_IRQ_VCHG_OVP (0) +#define MAX8925_IRQ_VCHG_F (1) +#define MAX8925_IRQ_VCHG_R (2) +#define MAX8925_IRQ_VCHG_THM_OK_R (8) +#define MAX8925_IRQ_VCHG_THM_OK_F (9) +#define MAX8925_IRQ_VCHG_BATTLOW_F (10) +#define MAX8925_IRQ_VCHG_BATTLOW_R (11) +#define MAX8925_IRQ_VCHG_RST (12) +#define MAX8925_IRQ_VCHG_DONE (13) +#define MAX8925_IRQ_VCHG_TOPOFF (14) +#define MAX8925_IRQ_VCHG_TMR_FAULT (15) +#define MAX8925_IRQ_GPM_RSTIN (16) +#define MAX8925_IRQ_GPM_MPL (17) +#define MAX8925_IRQ_GPM_SW_3SEC (18) +#define MAX8925_IRQ_GPM_EXTON_F (19) +#define MAX8925_IRQ_GPM_EXTON_R (20) +#define MAX8925_IRQ_GPM_SW_1SEC (21) +#define MAX8925_IRQ_GPM_SW_F (22) +#define MAX8925_IRQ_GPM_SW_R (23) +#define MAX8925_IRQ_GPM_SYSCKEN_F (24) +#define MAX8925_IRQ_GPM_SYSCKEN_R (25) + +#define MAX8925_IRQ_TSC_STICK (0) +#define MAX8925_IRQ_TSC_NSTICK (1) + +struct max8925_irq { + irq_handler_t handler; + void *data; +}; + +struct max8925_chip { + struct device *dev; + struct mutex io_lock; + struct mutex irq_lock; + struct i2c_client *i2c; + struct max8925_irq irq[MAX8925_NUM_IRQ]; + + const char *name; + int chip_id; + int chip_irq; +}; + +struct max8925_platform_data { + int chip_id; + int chip_irq; +}; + +extern int max8925_reg_read(struct i2c_client *, int); +extern int max8925_reg_write(struct i2c_client *, int, unsigned char); +extern int max8925_bulk_read(struct i2c_client *, int, int, unsigned char *); +extern int max8925_bulk_write(struct i2c_client *, int, int, unsigned char *); +extern int max8925_set_bits(struct i2c_client *, int, unsigned char, + unsigned char); + +extern int max8925_device_init(struct max8925_chip *, + struct max8925_platform_data *); +extern void max8925_device_exit(struct max8925_chip *); +#endif /* __LINUX_MFD_MAX8925_H */ + -- cgit v0.10.2 From 1ad998934e9c6cbae91662a05e0cb8772b1f4f75 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 8 Jan 2010 12:43:29 -0500 Subject: mfd: Add subdevs in max8925 Add subdevs in MAX8925. MAX8925 includes regulator, backlight and touch components. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ee416ee..d63ab2e 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -197,6 +197,7 @@ config PMIC_ADP5520 config MFD_MAX8925 tristate "Maxim Semiconductor MAX8925 PMIC Support" depends on I2C + select MFD_CORE help Say yes here to support for Maxim Semiconductor MAX8925. This is a Power Management IC. This driver provies common support for diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 3e26267..f36c494 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -20,6 +20,109 @@ #define IRQ_MODE_STATUS 0 #define IRQ_MODE_MASK 1 +static struct resource backlight_resources[] = { + { + .name = "max8925-backlight", + .start = MAX8925_WLED_MODE_CNTL, + .end = MAX8925_WLED_CNTL, + .flags = IORESOURCE_IO, + }, +}; + +static struct mfd_cell backlight_devs[] = { + { + .name = "max8925-backlight", + .num_resources = 1, + .resources = &backlight_resources[0], + .id = -1, + }, +}; + +static struct resource touch_resources[] = { + { + .name = "max8925-tsc", + .start = MAX8925_TSC_IRQ, + .end = MAX8925_ADC_RES_END, + .flags = IORESOURCE_IO, + }, +}; + +static struct mfd_cell touch_devs[] = { + { + .name = "max8925-touch", + .num_resources = 1, + .resources = &touch_resources[0], + .id = -1, + }, +}; + +#define MAX8925_REG_RESOURCE(_start, _end) \ +{ \ + .start = MAX8925_##_start, \ + .end = MAX8925_##_end, \ + .flags = IORESOURCE_IO, \ +} + +static struct resource regulator_resources[] = { + MAX8925_REG_RESOURCE(SDCTL1, SDCTL1), + MAX8925_REG_RESOURCE(SDCTL2, SDCTL2), + MAX8925_REG_RESOURCE(SDCTL3, SDCTL3), + MAX8925_REG_RESOURCE(LDOCTL1, LDOCTL1), + MAX8925_REG_RESOURCE(LDOCTL2, LDOCTL2), + MAX8925_REG_RESOURCE(LDOCTL3, LDOCTL3), + MAX8925_REG_RESOURCE(LDOCTL4, LDOCTL4), + MAX8925_REG_RESOURCE(LDOCTL5, LDOCTL5), + MAX8925_REG_RESOURCE(LDOCTL6, LDOCTL6), + MAX8925_REG_RESOURCE(LDOCTL7, LDOCTL7), + MAX8925_REG_RESOURCE(LDOCTL8, LDOCTL8), + MAX8925_REG_RESOURCE(LDOCTL9, LDOCTL9), + MAX8925_REG_RESOURCE(LDOCTL10, LDOCTL10), + MAX8925_REG_RESOURCE(LDOCTL11, LDOCTL11), + MAX8925_REG_RESOURCE(LDOCTL12, LDOCTL12), + MAX8925_REG_RESOURCE(LDOCTL13, LDOCTL13), + MAX8925_REG_RESOURCE(LDOCTL14, LDOCTL14), + MAX8925_REG_RESOURCE(LDOCTL15, LDOCTL15), + MAX8925_REG_RESOURCE(LDOCTL16, LDOCTL16), + MAX8925_REG_RESOURCE(LDOCTL17, LDOCTL17), + MAX8925_REG_RESOURCE(LDOCTL18, LDOCTL18), + MAX8925_REG_RESOURCE(LDOCTL19, LDOCTL19), + MAX8925_REG_RESOURCE(LDOCTL20, LDOCTL20), +}; + +#define MAX8925_REG_DEVS(_id) \ +{ \ + .name = "max8925-regulator", \ + .num_resources = 1, \ + .resources = ®ulator_resources[MAX8925_ID_##_id], \ + .id = MAX8925_ID_##_id, \ +} + +static struct mfd_cell regulator_devs[] = { + MAX8925_REG_DEVS(SD1), + MAX8925_REG_DEVS(SD2), + MAX8925_REG_DEVS(SD3), + MAX8925_REG_DEVS(LDO1), + MAX8925_REG_DEVS(LDO2), + MAX8925_REG_DEVS(LDO3), + MAX8925_REG_DEVS(LDO4), + MAX8925_REG_DEVS(LDO5), + MAX8925_REG_DEVS(LDO6), + MAX8925_REG_DEVS(LDO7), + MAX8925_REG_DEVS(LDO8), + MAX8925_REG_DEVS(LDO9), + MAX8925_REG_DEVS(LDO10), + MAX8925_REG_DEVS(LDO11), + MAX8925_REG_DEVS(LDO12), + MAX8925_REG_DEVS(LDO13), + MAX8925_REG_DEVS(LDO14), + MAX8925_REG_DEVS(LDO15), + MAX8925_REG_DEVS(LDO16), + MAX8925_REG_DEVS(LDO17), + MAX8925_REG_DEVS(LDO18), + MAX8925_REG_DEVS(LDO19), + MAX8925_REG_DEVS(LDO20), +}; + static int __get_irq_offset(struct max8925_chip *chip, int irq, int mode, int *offset, int *bit) { @@ -210,6 +313,30 @@ static int __devinit device_gpm_init(struct max8925_chip *chip, /* enable hard-reset for ONKEY power-off */ max8925_set_bits(i2c, MAX8925_SYSENSEL, 0x80, 0x80); + + ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], + ARRAY_SIZE(regulator_devs), + ®ulator_resources[0], 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add regulator subdev\n"); + goto out_irq; + } + + if (pdata && pdata->backlight) { + ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0], + ARRAY_SIZE(backlight_devs), + &backlight_resources[0], 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add backlight subdev\n"); + goto out_dev; + } + } + return 0; +out_dev: + mfd_remove_devices(chip->dev); +out_irq: + if (chip->chip_irq) + free_irq(chip->chip_irq, chip); out: return ret; } @@ -233,6 +360,20 @@ static int __devinit device_adc_init(struct max8925_chip *chip, goto out; } chip->chip_irq = i2c->irq; + + if (pdata && pdata->touch) { + ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], + ARRAY_SIZE(touch_devs), + &touch_resources[0], 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add touch subdev\n"); + goto out_irq; + } + } + return 0; +out_irq: + if (chip->chip_irq) + free_irq(chip->chip_irq, chip); out: return ret; } @@ -255,6 +396,7 @@ void max8925_device_exit(struct max8925_chip *chip) { if (chip->chip_irq >= 0) free_irq(chip->chip_irq, chip); + mfd_remove_devices(chip->dev); } MODULE_DESCRIPTION("PMIC Driver for Maxim MAX8925"); diff --git a/include/linux/mfd/max8925.h b/include/linux/mfd/max8925.h index 2326246..b72dbe1 100644 --- a/include/linux/mfd/max8925.h +++ b/include/linux/mfd/max8925.h @@ -14,6 +14,33 @@ #include +/* Unified sub device IDs for MAX8925 */ +enum { + MAX8925_ID_SD1, + MAX8925_ID_SD2, + MAX8925_ID_SD3, + MAX8925_ID_LDO1, + MAX8925_ID_LDO2, + MAX8925_ID_LDO3, + MAX8925_ID_LDO4, + MAX8925_ID_LDO5, + MAX8925_ID_LDO6, + MAX8925_ID_LDO7, + MAX8925_ID_LDO8, + MAX8925_ID_LDO9, + MAX8925_ID_LDO10, + MAX8925_ID_LDO11, + MAX8925_ID_LDO12, + MAX8925_ID_LDO13, + MAX8925_ID_LDO14, + MAX8925_ID_LDO15, + MAX8925_ID_LDO16, + MAX8925_ID_LDO17, + MAX8925_ID_LDO18, + MAX8925_ID_LDO19, + MAX8925_ID_LDO20, +}; + /* Charger registers */ #define MAX8925_CHG_IRQ1 (0x7e) #define MAX8925_CHG_IRQ2 (0x7f) @@ -32,12 +59,65 @@ /* Touch registers */ #define MAX8925_TSC_IRQ (0x00) #define MAX8925_TSC_IRQ_MASK (0x01) +#define MAX8925_ADC_RES_END (0x6f) /* RTC registers */ #define MAX8925_RTC_STATUS (0x1a) #define MAX8925_RTC_IRQ (0x1c) #define MAX8925_RTC_IRQ_MASK (0x1d) +/* WLED registers */ +#define MAX8925_WLED_MODE_CNTL (0x84) +#define MAX8925_WLED_CNTL (0x85) + +/* MAX8925 Registers */ +#define MAX8925_SDCTL1 (0x04) +#define MAX8925_SDCTL2 (0x07) +#define MAX8925_SDCTL3 (0x0A) +#define MAX8925_SDV1 (0x06) +#define MAX8925_SDV2 (0x09) +#define MAX8925_SDV3 (0x0C) +#define MAX8925_LDOCTL1 (0x18) +#define MAX8925_LDOCTL2 (0x1C) +#define MAX8925_LDOCTL3 (0x20) +#define MAX8925_LDOCTL4 (0x24) +#define MAX8925_LDOCTL5 (0x28) +#define MAX8925_LDOCTL6 (0x2C) +#define MAX8925_LDOCTL7 (0x30) +#define MAX8925_LDOCTL8 (0x34) +#define MAX8925_LDOCTL9 (0x38) +#define MAX8925_LDOCTL10 (0x3C) +#define MAX8925_LDOCTL11 (0x40) +#define MAX8925_LDOCTL12 (0x44) +#define MAX8925_LDOCTL13 (0x48) +#define MAX8925_LDOCTL14 (0x4C) +#define MAX8925_LDOCTL15 (0x50) +#define MAX8925_LDOCTL16 (0x10) +#define MAX8925_LDOCTL17 (0x14) +#define MAX8925_LDOCTL18 (0x72) +#define MAX8925_LDOCTL19 (0x5C) +#define MAX8925_LDOCTL20 (0x9C) +#define MAX8925_LDOVOUT1 (0x1A) +#define MAX8925_LDOVOUT2 (0x1E) +#define MAX8925_LDOVOUT3 (0x22) +#define MAX8925_LDOVOUT4 (0x26) +#define MAX8925_LDOVOUT5 (0x2A) +#define MAX8925_LDOVOUT6 (0x2E) +#define MAX8925_LDOVOUT7 (0x32) +#define MAX8925_LDOVOUT8 (0x36) +#define MAX8925_LDOVOUT9 (0x3A) +#define MAX8925_LDOVOUT10 (0x3E) +#define MAX8925_LDOVOUT11 (0x42) +#define MAX8925_LDOVOUT12 (0x46) +#define MAX8925_LDOVOUT13 (0x4A) +#define MAX8925_LDOVOUT14 (0x4E) +#define MAX8925_LDOVOUT15 (0x52) +#define MAX8925_LDOVOUT16 (0x12) +#define MAX8925_LDOVOUT17 (0x16) +#define MAX8925_LDOVOUT18 (0x74) +#define MAX8925_LDOVOUT19 (0x5E) +#define MAX8925_LDOVOUT20 (0x9E) + /* bit definitions */ #define CHG_IRQ1_MASK (0x07) #define CHG_IRQ2_MASK (0xff) @@ -83,6 +163,8 @@ enum { #define MAX8925_IRQ_TSC_STICK (0) #define MAX8925_IRQ_TSC_NSTICK (1) +#define MAX8925_MAX_REGULATOR (23) + struct max8925_irq { irq_handler_t handler; void *data; @@ -100,7 +182,21 @@ struct max8925_chip { int chip_irq; }; +struct max8925_backlight_pdata { + int lxw_scl; /* 0/1 -- 0.8Ohm/0.4Ohm */ + int lxw_freq; /* 700KHz ~ 1400KHz */ + int dual_string; /* 0/1 -- single/dual string */ +}; + +struct max8925_touch_pdata { + unsigned int flags; +}; + struct max8925_platform_data { + struct max8925_backlight_pdata *backlight; + struct max8925_touch_pdata *touch; + struct regulator_init_data *regulator[MAX8925_MAX_REGULATOR]; + int chip_id; int chip_irq; }; -- cgit v0.10.2 From 4f811ef0d40048ae80b6ea77080b814725bffc58 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 18 Dec 2009 10:01:45 -0500 Subject: backlight: Enable max8925 backlight Enable max8925 backlight sub device. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 96a6b30..0c77fc6 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -212,6 +212,13 @@ config BACKLIGHT_DA903X If you have a LCD backlight connected to the WLED output of DA9030 or DA9034 WLED output, say Y here to enable this driver. +config BACKLIGHT_MAX8925 + tristate "Backlight driver for MAX8925" + depends on BACKLIGHT_CLASS_DEVICE && MFD_MAX8925 + help + If you have a LCD backlight connected to the WLED output of MAX8925 + WLED output, say Y here to enable this driver. + config BACKLIGHT_MBP_NVIDIA tristate "MacBook Pro Nvidia Backlight Driver" depends on BACKLIGHT_CLASS_DEVICE && X86 diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 802d467..6c704d4 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o +obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o obj-$(CONFIG_BACKLIGHT_MBP_NVIDIA) += mbp_nvidia_bl.o obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c new file mode 100644 index 0000000..c267069 --- /dev/null +++ b/drivers/video/backlight/max8925_bl.c @@ -0,0 +1,200 @@ +/* + * Backlight driver for Maxim MAX8925 + * + * Copyright (C) 2009 Marvell International Ltd. + * Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_BRIGHTNESS (0xff) +#define MIN_BRIGHTNESS (0) + +#define LWX_FREQ(x) (((x - 601) / 100) & 0x7) + +struct max8925_backlight_data { + struct max8925_chip *chip; + + int current_brightness; +}; + +static int max8925_backlight_set(struct backlight_device *bl, int brightness) +{ + struct max8925_backlight_data *data = bl_get_data(bl); + struct max8925_chip *chip = data->chip; + unsigned char value; + int ret; + + if (brightness > MAX_BRIGHTNESS) + value = MAX_BRIGHTNESS; + else + value = brightness; + + ret = max8925_reg_write(chip->i2c, MAX8925_WLED_CNTL, value); + if (ret < 0) + goto out; + + if (!data->current_brightness && brightness) + /* enable WLED output */ + ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 1, 1); + else if (!brightness) + /* disable WLED output */ + ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 1, 0); + if (ret < 0) + goto out; + dev_dbg(chip->dev, "set brightness %d\n", value); + data->current_brightness = value; + return 0; +out: + dev_dbg(chip->dev, "set brightness %d failure with return value:%d\n", + value, ret); + return ret; +} + +static int max8925_backlight_update_status(struct backlight_device *bl) +{ + int brightness = bl->props.brightness; + + if (bl->props.power != FB_BLANK_UNBLANK) + brightness = 0; + + if (bl->props.fb_blank != FB_BLANK_UNBLANK) + brightness = 0; + + if (bl->props.state & BL_CORE_SUSPENDED) + brightness = 0; + + return max8925_backlight_set(bl, brightness); +} + +static int max8925_backlight_get_brightness(struct backlight_device *bl) +{ + struct max8925_backlight_data *data = bl_get_data(bl); + struct max8925_chip *chip = data->chip; + int ret; + + ret = max8925_reg_read(chip->i2c, MAX8925_WLED_CNTL); + if (ret < 0) + return -EINVAL; + data->current_brightness = ret; + dev_dbg(chip->dev, "get brightness %d\n", data->current_brightness); + return ret; +} + +static struct backlight_ops max8925_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = max8925_backlight_update_status, + .get_brightness = max8925_backlight_get_brightness, +}; + +static int __devinit max8925_backlight_probe(struct platform_device *pdev) +{ + struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct max8925_platform_data *max8925_pdata; + struct max8925_backlight_pdata *pdata = NULL; + struct max8925_backlight_data *data; + struct backlight_device *bl; + struct resource *res; + char name[MAX8925_NAME_SIZE]; + unsigned char value; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (res == NULL) { + dev_err(&pdev->dev, "No I/O resource!\n"); + return -EINVAL; + } + + if (pdev->dev.parent->platform_data) { + max8925_pdata = pdev->dev.parent->platform_data; + pdata = max8925_pdata->backlight; + } + + if (!pdata) { + dev_err(&pdev->dev, "platform data isn't assigned to " + "backlight\n"); + return -EINVAL; + } + + data = kzalloc(sizeof(struct max8925_backlight_data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + strncpy(name, res->name, MAX8925_NAME_SIZE); + data->chip = chip; + data->current_brightness = 0; + + bl = backlight_device_register(name, &pdev->dev, data, + &max8925_backlight_ops); + if (IS_ERR(bl)) { + dev_err(&pdev->dev, "failed to register backlight\n"); + kfree(data); + return PTR_ERR(bl); + } + bl->props.max_brightness = MAX_BRIGHTNESS; + bl->props.brightness = MAX_BRIGHTNESS; + + platform_set_drvdata(pdev, bl); + + value = 0; + if (pdata->lxw_scl) + value |= (1 << 7); + if (pdata->lxw_freq) + value |= (LWX_FREQ(pdata->lxw_freq) << 4); + if (pdata->dual_string) + value |= (1 << 1); + ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 0xfe, value); + if (ret < 0) + goto out; + + backlight_update_status(bl); + return 0; +out: + kfree(data); + return ret; +} + +static int __devexit max8925_backlight_remove(struct platform_device *pdev) +{ + struct backlight_device *bl = platform_get_drvdata(pdev); + struct max8925_backlight_data *data = bl_get_data(bl); + + backlight_device_unregister(bl); + kfree(data); + return 0; +} + +static struct platform_driver max8925_backlight_driver = { + .driver = { + .name = "max8925-backlight", + .owner = THIS_MODULE, + }, + .probe = max8925_backlight_probe, + .remove = __devexit_p(max8925_backlight_remove), +}; + +static int __init max8925_backlight_init(void) +{ + return platform_driver_register(&max8925_backlight_driver); +} +module_init(max8925_backlight_init); + +static void __exit max8925_backlight_exit(void) +{ + platform_driver_unregister(&max8925_backlight_driver); +}; +module_exit(max8925_backlight_exit); + +MODULE_DESCRIPTION("Backlight Driver for Maxim MAX8925"); +MODULE_AUTHOR("Haojian Zhuang "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:max8925-backlight"); -- cgit v0.10.2 From 08ff6f2a9908c87b0adffe6453291be22db3a62f Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 11 Jan 2010 13:10:08 +0100 Subject: regulator: Add max8925 support MAX8925 contains 3 Buck and 20 LDO regulator. Signed-off-by: Haojian Zhuang Acked-by: Mark Brown Signed-off-by: Samuel Ortiz diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index dbfe31a..04f2e08 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -94,6 +94,12 @@ config REGULATOR_MAX8660 This driver controls a Maxim 8660/8661 voltage output regulator via I2C bus. +config REGULATOR_MAX8925 + tristate "Maxim MAX8925 Power Management IC" + depends on MFD_MAX8925 + help + Say y here to support the voltage regulaltor of Maxim MAX8925 PMIC. + config REGULATOR_TWL4030 bool "TI TWL4030/TWL5030/TWL6030/TPS695x0 PMIC" depends on TWL4030_CORE diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index e845b66..4e7feec 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o +obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c new file mode 100644 index 0000000..67873f0 --- /dev/null +++ b/drivers/regulator/max8925-regulator.c @@ -0,0 +1,306 @@ +/* + * Regulators driver for Maxim max8925 + * + * Copyright (C) 2009 Marvell International Ltd. + * Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define SD1_DVM_VMIN 850000 +#define SD1_DVM_VMAX 1000000 +#define SD1_DVM_STEP 50000 +#define SD1_DVM_SHIFT 5 /* SDCTL1 bit5 */ +#define SD1_DVM_EN 6 /* SDV1 bit 6 */ + +struct max8925_regulator_info { + struct regulator_desc desc; + struct regulator_dev *regulator; + struct i2c_client *i2c; + struct max8925_chip *chip; + + int min_uV; + int max_uV; + int step_uV; + int vol_reg; + int vol_shift; + int vol_nbits; + int enable_bit; + int enable_reg; +}; + +static inline int check_range(struct max8925_regulator_info *info, + int min_uV, int max_uV) +{ + if (min_uV < info->min_uV || min_uV > info->max_uV) + return -EINVAL; + + return 0; +} + +static int max8925_list_voltage(struct regulator_dev *rdev, unsigned index) +{ + struct max8925_regulator_info *info = rdev_get_drvdata(rdev); + return info->min_uV + index * info->step_uV; +} + +static int max8925_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + struct max8925_regulator_info *info = rdev_get_drvdata(rdev); + unsigned char data, mask; + + if (check_range(info, min_uV, max_uV)) { + dev_err(info->chip->dev, "invalid voltage range (%d, %d) uV\n", + min_uV, max_uV); + return -EINVAL; + } + data = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + data <<= info->vol_shift; + mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; + + return max8925_set_bits(info->i2c, info->vol_reg, mask, data); +} + +static int max8925_get_voltage(struct regulator_dev *rdev) +{ + struct max8925_regulator_info *info = rdev_get_drvdata(rdev); + unsigned char data, mask; + int ret; + + ret = max8925_reg_read(info->i2c, info->vol_reg); + if (ret < 0) + return ret; + mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; + data = (ret & mask) >> info->vol_shift; + + return max8925_list_voltage(rdev, data); +} + +static int max8925_enable(struct regulator_dev *rdev) +{ + struct max8925_regulator_info *info = rdev_get_drvdata(rdev); + + return max8925_set_bits(info->i2c, info->enable_reg, + 1 << info->enable_bit, + 1 << info->enable_bit); +} + +static int max8925_disable(struct regulator_dev *rdev) +{ + struct max8925_regulator_info *info = rdev_get_drvdata(rdev); + + return max8925_set_bits(info->i2c, info->enable_reg, + 1 << info->enable_bit, 0); +} + +static int max8925_is_enabled(struct regulator_dev *rdev) +{ + struct max8925_regulator_info *info = rdev_get_drvdata(rdev); + int ret; + + ret = max8925_reg_read(info->i2c, info->vol_reg); + if (ret < 0) + return ret; + + return ret & (1 << info->enable_bit); +} + +static int max8925_set_dvm_voltage(struct regulator_dev *rdev, int uV) +{ + struct max8925_regulator_info *info = rdev_get_drvdata(rdev); + unsigned char data, mask; + + if (uV < SD1_DVM_VMIN || uV > SD1_DVM_VMAX) + return -EINVAL; + + data = (uV - SD1_DVM_VMIN + SD1_DVM_STEP - 1) / SD1_DVM_STEP; + data <<= SD1_DVM_SHIFT; + mask = 3 << SD1_DVM_SHIFT; + + return max8925_set_bits(info->i2c, info->enable_reg, mask, data); +} + +static int max8925_set_dvm_enable(struct regulator_dev *rdev) +{ + struct max8925_regulator_info *info = rdev_get_drvdata(rdev); + + return max8925_set_bits(info->i2c, info->vol_reg, 1 << SD1_DVM_EN, + 1 << SD1_DVM_EN); +} + +static int max8925_set_dvm_disable(struct regulator_dev *rdev) +{ + struct max8925_regulator_info *info = rdev_get_drvdata(rdev); + + return max8925_set_bits(info->i2c, info->vol_reg, 1 << SD1_DVM_EN, 0); +} + +static struct regulator_ops max8925_regulator_sdv_ops = { + .set_voltage = max8925_set_voltage, + .get_voltage = max8925_get_voltage, + .enable = max8925_enable, + .disable = max8925_disable, + .is_enabled = max8925_is_enabled, + .set_suspend_voltage = max8925_set_dvm_voltage, + .set_suspend_enable = max8925_set_dvm_enable, + .set_suspend_disable = max8925_set_dvm_disable, +}; + +static struct regulator_ops max8925_regulator_ldo_ops = { + .set_voltage = max8925_set_voltage, + .get_voltage = max8925_get_voltage, + .enable = max8925_enable, + .disable = max8925_disable, + .is_enabled = max8925_is_enabled, +}; + +#define MAX8925_SDV(_id, min, max, step) \ +{ \ + .desc = { \ + .name = "SDV" #_id, \ + .ops = &max8925_regulator_sdv_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MAX8925_ID_SD##_id, \ + .owner = THIS_MODULE, \ + }, \ + .min_uV = min * 1000, \ + .max_uV = max * 1000, \ + .step_uV = step * 1000, \ + .vol_reg = MAX8925_SDV##_id, \ + .vol_shift = 0, \ + .vol_nbits = 6, \ + .enable_reg = MAX8925_SDCTL##_id, \ + .enable_bit = 0, \ +} + +#define MAX8925_LDO(_id, min, max, step) \ +{ \ + .desc = { \ + .name = "LDO" #_id, \ + .ops = &max8925_regulator_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MAX8925_ID_LDO##_id, \ + .owner = THIS_MODULE, \ + }, \ + .min_uV = min * 1000, \ + .max_uV = max * 1000, \ + .step_uV = step * 1000, \ + .vol_reg = MAX8925_LDOVOUT##_id, \ + .vol_shift = 0, \ + .vol_nbits = 6, \ + .enable_reg = MAX8925_LDOCTL##_id, \ + .enable_bit = 0, \ +} + +static struct max8925_regulator_info max8925_regulator_info[] = { + MAX8925_SDV(1, 637.5, 1425, 12.5), + MAX8925_SDV(2, 650, 2225, 25), + MAX8925_SDV(3, 750, 3900, 50), + + MAX8925_LDO(1, 750, 3900, 50), + MAX8925_LDO(2, 650, 2250, 25), + MAX8925_LDO(3, 650, 2250, 25), + MAX8925_LDO(4, 750, 3900, 50), + MAX8925_LDO(5, 750, 3900, 50), + MAX8925_LDO(6, 750, 3900, 50), + MAX8925_LDO(7, 750, 3900, 50), + MAX8925_LDO(8, 750, 3900, 50), + MAX8925_LDO(9, 750, 3900, 50), + MAX8925_LDO(10, 750, 3900, 50), + MAX8925_LDO(11, 750, 3900, 50), + MAX8925_LDO(12, 750, 3900, 50), + MAX8925_LDO(13, 750, 3900, 50), + MAX8925_LDO(14, 750, 3900, 50), + MAX8925_LDO(15, 750, 3900, 50), + MAX8925_LDO(16, 750, 3900, 50), + MAX8925_LDO(17, 650, 2250, 25), + MAX8925_LDO(18, 650, 2250, 25), + MAX8925_LDO(19, 750, 3900, 50), + MAX8925_LDO(20, 750, 3900, 50), +}; + +static inline struct max8925_regulator_info *find_regulator_info(int id) +{ + struct max8925_regulator_info *ri; + int i; + + for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) { + ri = &max8925_regulator_info[i]; + if (ri->desc.id == id) + return ri; + } + return NULL; +} + +static int __devinit max8925_regulator_probe(struct platform_device *pdev) +{ + struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct max8925_platform_data *pdata = chip->dev->platform_data; + struct max8925_regulator_info *ri = NULL; + struct regulator_dev *rdev; + + ri = find_regulator_info(pdev->id); + if (ri == NULL) { + dev_err(&pdev->dev, "invalid regulator ID specified\n"); + return -EINVAL; + } + ri->i2c = chip->i2c; + ri->chip = chip; + + rdev = regulator_register(&ri->desc, &pdev->dev, + pdata->regulator[pdev->id], ri); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register regulator %s\n", + ri->desc.name); + return PTR_ERR(rdev); + } + + platform_set_drvdata(pdev, rdev); + return 0; +} + +static int __devexit max8925_regulator_remove(struct platform_device *pdev) +{ + struct regulator_dev *rdev = platform_get_drvdata(pdev); + + regulator_unregister(rdev); + return 0; +} + +static struct platform_driver max8925_regulator_driver = { + .driver = { + .name = "max8925-regulator", + .owner = THIS_MODULE, + }, + .probe = max8925_regulator_probe, + .remove = __devexit_p(max8925_regulator_remove), +}; + +static int __init max8925_regulator_init(void) +{ + return platform_driver_register(&max8925_regulator_driver); +} +subsys_initcall(max8925_regulator_init); + +static void __exit max8925_regulator_exit(void) +{ + platform_driver_unregister(&max8925_regulator_driver); +} +module_exit(max8925_regulator_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Haojian Zhuang "); +MODULE_DESCRIPTION("Regulator Driver for Maxim 8925 PMIC"); +MODULE_ALIAS("platform:max8925-regulator"); + -- cgit v0.10.2 From 6048a3dd2371c58611ea0ab8b306f8f1469399ae Mon Sep 17 00:00:00 2001 From: Cory Maccarrone Date: Tue, 19 Jan 2010 11:22:45 +0100 Subject: mfd: Add HTCPLD driver This change introduces a driver for the HTC PLD chip found on some smartphones, such as the HTC Wizard and HTC Herald. It works through the I2C bus and acts as a GPIO extender. Specifically: * it can have several sub-devices, each with its own I2C address * Each sub-device provides 8 output and 8 input pins * The chip attaches to one GPIO to signal when any of the input GPIOs change -- at which point all chips must be scanned for changes This driver implements the GPIOs throught the kernel's GPIO and IRQ framework. This allows any GPIO-servicing drivers to operate on htcpld pins, such as the gpio-keys and gpio-leds drivers. Signed-off-by: Cory Maccarrone Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d63ab2e..9bcd447 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -78,6 +78,15 @@ config HTC_PASIC3 HTC Magician devices, respectively. Actual functionality is handled by the leds-pasic3 and ds1wm drivers. +config HTC_I2CPLD + bool "HTC I2C PLD chip support" + depends on I2C=y + help + If you say yes here you get support for the supposed CPLD + found on omap850 HTC devices like the HTC Wizard and HTC Herald. + This device provides input and output GPIOs through an I2C + interface to one or more sub-chips. + config UCB1400_CORE tristate "Philips UCB1400 Core driver" depends on AC97_BUS diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 2616357..142d312 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_MFD_SH_MOBILE_SDHI) += sh_mobile_sdhi.o obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o +obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c new file mode 100644 index 0000000..37b9fda --- /dev/null +++ b/drivers/mfd/htc-i2cpld.c @@ -0,0 +1,710 @@ +/* + * htc-i2cpld.c + * Chip driver for an unknown CPLD chip found on omap850 HTC devices like + * the HTC Wizard and HTC Herald. + * The cpld is located on the i2c bus and acts as an input/output GPIO + * extender. + * + * Copyright (C) 2009 Cory Maccarrone + * + * Based on work done in the linwizard project + * Copyright (C) 2008-2009 Angelo Arrifano + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct htcpld_chip { + spinlock_t lock; + + /* chip info */ + u8 reset; + u8 addr; + struct device *dev; + struct i2c_client *client; + + /* Output details */ + u8 cache_out; + struct gpio_chip chip_out; + + /* Input details */ + u8 cache_in; + struct gpio_chip chip_in; + + u16 irqs_enabled; + uint irq_start; + int nirqs; + + /* + * Work structure to allow for setting values outside of any + * possible interrupt context + */ + struct work_struct set_val_work; +}; + +struct htcpld_data { + /* irq info */ + u16 irqs_enabled; + uint irq_start; + int nirqs; + uint chained_irq; + unsigned int int_reset_gpio_hi; + unsigned int int_reset_gpio_lo; + + /* htcpld info */ + struct htcpld_chip *chip; + unsigned int nchips; +}; + +/* There does not appear to be a way to proactively mask interrupts + * on the htcpld chip itself. So, we simply ignore interrupts that + * aren't desired. */ +static void htcpld_mask(unsigned int irq) +{ + struct htcpld_chip *chip = get_irq_chip_data(irq); + chip->irqs_enabled &= ~(1 << (irq - chip->irq_start)); + pr_debug("HTCPLD mask %d %04x\n", irq, chip->irqs_enabled); +} +static void htcpld_unmask(unsigned int irq) +{ + struct htcpld_chip *chip = get_irq_chip_data(irq); + chip->irqs_enabled |= 1 << (irq - chip->irq_start); + pr_debug("HTCPLD unmask %d %04x\n", irq, chip->irqs_enabled); +} + +static int htcpld_set_type(unsigned int irq, unsigned int flags) +{ + struct irq_desc *d = irq_to_desc(irq); + + if (!d) { + pr_err("HTCPLD invalid IRQ: %d\n", irq); + return -EINVAL; + } + + if (flags & ~IRQ_TYPE_SENSE_MASK) + return -EINVAL; + + /* We only allow edge triggering */ + if (flags & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)) + return -EINVAL; + + d->status &= ~IRQ_TYPE_SENSE_MASK; + d->status |= flags; + + return 0; +} + +static struct irq_chip htcpld_muxed_chip = { + .name = "htcpld", + .mask = htcpld_mask, + .unmask = htcpld_unmask, + .set_type = htcpld_set_type, +}; + +/* To properly dispatch IRQ events, we need to read from the + * chip. This is an I2C action that could possibly sleep + * (which is bad in interrupt context) -- so we use a threaded + * interrupt handler to get around that. + */ +static irqreturn_t htcpld_handler(int irq, void *dev) +{ + struct htcpld_data *htcpld = dev; + unsigned int i; + unsigned long flags; + int irqpin; + struct irq_desc *desc; + + if (!htcpld) { + pr_debug("htcpld is null in ISR\n"); + return IRQ_HANDLED; + } + + /* + * For each chip, do a read of the chip and trigger any interrupts + * desired. The interrupts will be triggered from LSB to MSB (i.e. + * bit 0 first, then bit 1, etc.) + * + * For chips that have no interrupt range specified, just skip 'em. + */ + for (i = 0; i < htcpld->nchips; i++) { + struct htcpld_chip *chip = &htcpld->chip[i]; + struct i2c_client *client; + int val; + unsigned long uval, old_val; + + if (!chip) { + pr_debug("chip %d is null in ISR\n", i); + continue; + } + + if (chip->nirqs == 0) + continue; + + client = chip->client; + if (!client) { + pr_debug("client %d is null in ISR\n", i); + continue; + } + + /* Scan the chip */ + val = i2c_smbus_read_byte_data(client, chip->cache_out); + if (val < 0) { + /* Throw a warning and skip this chip */ + dev_warn(chip->dev, "Unable to read from chip: %d\n", + val); + continue; + } + + uval = (unsigned long)val; + + spin_lock_irqsave(&chip->lock, flags); + + /* Save away the old value so we can compare it */ + old_val = chip->cache_in; + + /* Write the new value */ + chip->cache_in = uval; + + spin_unlock_irqrestore(&chip->lock, flags); + + /* + * For each bit in the data (starting at bit 0), trigger + * associated interrupts. + */ + for (irqpin = 0; irqpin < chip->nirqs; irqpin++) { + unsigned oldb, newb; + int flags; + + irq = chip->irq_start + irqpin; + desc = irq_to_desc(irq); + flags = desc->status; + + /* Run the IRQ handler, but only if the bit value + * changed, and the proper flags are set */ + oldb = (old_val >> irqpin) & 1; + newb = (uval >> irqpin) & 1; + + if ((!oldb && newb && (flags & IRQ_TYPE_EDGE_RISING)) || + (oldb && !newb && + (flags & IRQ_TYPE_EDGE_FALLING))) { + pr_debug("fire IRQ %d\n", irqpin); + desc->handle_irq(irq, desc); + } + } + } + + /* + * In order to continue receiving interrupts, the int_reset_gpio must + * be asserted. + */ + if (htcpld->int_reset_gpio_hi) + gpio_set_value(htcpld->int_reset_gpio_hi, 1); + if (htcpld->int_reset_gpio_lo) + gpio_set_value(htcpld->int_reset_gpio_lo, 0); + + return IRQ_HANDLED; +} + +/* + * The GPIO set routines can be called from interrupt context, especially if, + * for example they're attached to the led-gpio framework and a trigger is + * enabled. As such, we declared work above in the htcpld_chip structure, + * and that work is scheduled in the set routine. The kernel can then run + * the I2C functions, which will sleep, in process context. + */ +void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val) +{ + struct i2c_client *client; + struct htcpld_chip *chip_data; + unsigned long flags; + + chip_data = container_of(chip, struct htcpld_chip, chip_out); + if (!chip_data) + return; + + client = chip_data->client; + if (client == NULL) + return; + + spin_lock_irqsave(&chip_data->lock, flags); + if (val) + chip_data->cache_out |= (1 << offset); + else + chip_data->cache_out &= ~(1 << offset); + spin_unlock_irqrestore(&chip_data->lock, flags); + + schedule_work(&(chip_data->set_val_work)); +} + +void htcpld_chip_set_ni(struct work_struct *work) +{ + struct htcpld_chip *chip_data; + struct i2c_client *client; + + chip_data = container_of(work, struct htcpld_chip, set_val_work); + client = chip_data->client; + i2c_smbus_read_byte_data(client, chip_data->cache_out); +} + +int htcpld_chip_get(struct gpio_chip *chip, unsigned offset) +{ + struct htcpld_chip *chip_data; + int val = 0; + int is_input = 0; + + /* Try out first */ + chip_data = container_of(chip, struct htcpld_chip, chip_out); + if (!chip_data) { + /* Try in */ + is_input = 1; + chip_data = container_of(chip, struct htcpld_chip, chip_in); + if (!chip_data) + return -EINVAL; + } + + /* Determine if this is an input or output GPIO */ + if (!is_input) + /* Use the output cache */ + val = (chip_data->cache_out >> offset) & 1; + else + /* Use the input cache */ + val = (chip_data->cache_in >> offset) & 1; + + if (val) + return 1; + else + return 0; +} + +static int htcpld_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + htcpld_chip_set(chip, offset, value); + return 0; +} + +static int htcpld_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + /* + * No-op: this function can only be called on the input chip. + * We do however make sure the offset is within range. + */ + return (offset < chip->ngpio) ? 0 : -EINVAL; +} + +int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct htcpld_chip *chip_data; + + chip_data = container_of(chip, struct htcpld_chip, chip_in); + + if (offset < chip_data->nirqs) + return chip_data->irq_start + offset; + else + return -EINVAL; +} + +void htcpld_chip_reset(struct i2c_client *client) +{ + struct htcpld_chip *chip_data = i2c_get_clientdata(client); + if (!chip_data) + return; + + i2c_smbus_read_byte_data( + client, (chip_data->cache_out = chip_data->reset)); +} + +static int __devinit htcpld_setup_chip_irq( + struct platform_device *pdev, + int chip_index) +{ + struct htcpld_data *htcpld; + struct device *dev = &pdev->dev; + struct htcpld_core_platform_data *pdata; + struct htcpld_chip *chip; + struct htcpld_chip_platform_data *plat_chip_data; + unsigned int irq, irq_end; + int ret = 0; + + /* Get the platform and driver data */ + pdata = dev->platform_data; + htcpld = platform_get_drvdata(pdev); + chip = &htcpld->chip[chip_index]; + plat_chip_data = &pdata->chip[chip_index]; + + /* Setup irq handlers */ + irq_end = chip->irq_start + chip->nirqs; + for (irq = chip->irq_start; irq < irq_end; irq++) { + set_irq_chip(irq, &htcpld_muxed_chip); + set_irq_chip_data(irq, chip); + set_irq_handler(irq, handle_simple_irq); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); +#else + set_irq_probe(irq); +#endif + } + + return ret; +} + +static int __devinit htcpld_register_chip_i2c( + struct platform_device *pdev, + int chip_index) +{ + struct htcpld_data *htcpld; + struct device *dev = &pdev->dev; + struct htcpld_core_platform_data *pdata; + struct htcpld_chip *chip; + struct htcpld_chip_platform_data *plat_chip_data; + struct i2c_adapter *adapter; + struct i2c_client *client; + struct i2c_board_info info; + + /* Get the platform and driver data */ + pdata = dev->platform_data; + htcpld = platform_get_drvdata(pdev); + chip = &htcpld->chip[chip_index]; + plat_chip_data = &pdata->chip[chip_index]; + + adapter = i2c_get_adapter(pdata->i2c_adapter_id); + if (adapter == NULL) { + /* Eek, no such I2C adapter! Bail out. */ + dev_warn(dev, "Chip at i2c address 0x%x: Invalid i2c adapter %d\n", + plat_chip_data->addr, pdata->i2c_adapter_id); + return -ENODEV; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) { + dev_warn(dev, "i2c adapter %d non-functional\n", + pdata->i2c_adapter_id); + return -EINVAL; + } + + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = plat_chip_data->addr; + strlcpy(info.type, "htcpld-chip", I2C_NAME_SIZE); + info.platform_data = chip; + + /* Add the I2C device. This calls the probe() function. */ + client = i2c_new_device(adapter, &info); + if (!client) { + /* I2C device registration failed, contineu with the next */ + dev_warn(dev, "Unable to add I2C device for 0x%x\n", + plat_chip_data->addr); + return -ENODEV; + } + + i2c_set_clientdata(client, chip); + snprintf(client->name, I2C_NAME_SIZE, "Chip_0x%d", client->addr); + chip->client = client; + + /* Reset the chip */ + htcpld_chip_reset(client); + chip->cache_in = i2c_smbus_read_byte_data(client, chip->cache_out); + + return 0; +} + +static void __devinit htcpld_unregister_chip_i2c( + struct platform_device *pdev, + int chip_index) +{ + struct htcpld_data *htcpld; + struct htcpld_chip *chip; + + /* Get the platform and driver data */ + htcpld = platform_get_drvdata(pdev); + chip = &htcpld->chip[chip_index]; + + if (chip->client) + i2c_unregister_device(chip->client); +} + +static int __devinit htcpld_register_chip_gpio( + struct platform_device *pdev, + int chip_index) +{ + struct htcpld_data *htcpld; + struct device *dev = &pdev->dev; + struct htcpld_core_platform_data *pdata; + struct htcpld_chip *chip; + struct htcpld_chip_platform_data *plat_chip_data; + struct gpio_chip *gpio_chip; + int ret = 0; + + /* Get the platform and driver data */ + pdata = dev->platform_data; + htcpld = platform_get_drvdata(pdev); + chip = &htcpld->chip[chip_index]; + plat_chip_data = &pdata->chip[chip_index]; + + /* Setup the GPIO chips */ + gpio_chip = &(chip->chip_out); + gpio_chip->label = "htcpld-out"; + gpio_chip->dev = dev; + gpio_chip->owner = THIS_MODULE; + gpio_chip->get = htcpld_chip_get; + gpio_chip->set = htcpld_chip_set; + gpio_chip->direction_input = NULL; + gpio_chip->direction_output = htcpld_direction_output; + gpio_chip->base = plat_chip_data->gpio_out_base; + gpio_chip->ngpio = plat_chip_data->num_gpios; + + gpio_chip = &(chip->chip_in); + gpio_chip->label = "htcpld-in"; + gpio_chip->dev = dev; + gpio_chip->owner = THIS_MODULE; + gpio_chip->get = htcpld_chip_get; + gpio_chip->set = NULL; + gpio_chip->direction_input = htcpld_direction_input; + gpio_chip->direction_output = NULL; + gpio_chip->to_irq = htcpld_chip_to_irq; + gpio_chip->base = plat_chip_data->gpio_in_base; + gpio_chip->ngpio = plat_chip_data->num_gpios; + + /* Add the GPIO chips */ + ret = gpiochip_add(&(chip->chip_out)); + if (ret) { + dev_warn(dev, "Unable to register output GPIOs for 0x%x: %d\n", + plat_chip_data->addr, ret); + return ret; + } + + ret = gpiochip_add(&(chip->chip_in)); + if (ret) { + int error; + + dev_warn(dev, "Unable to register input GPIOs for 0x%x: %d\n", + plat_chip_data->addr, ret); + + error = gpiochip_remove(&(chip->chip_out)); + if (error) + dev_warn(dev, "Error while trying to unregister gpio chip: %d\n", error); + + return ret; + } + + return 0; +} + +static int __devinit htcpld_setup_chips(struct platform_device *pdev) +{ + struct htcpld_data *htcpld; + struct device *dev = &pdev->dev; + struct htcpld_core_platform_data *pdata; + int i; + + /* Get the platform and driver data */ + pdata = dev->platform_data; + htcpld = platform_get_drvdata(pdev); + + /* Setup each chip's output GPIOs */ + htcpld->nchips = pdata->num_chip; + htcpld->chip = kzalloc(sizeof(struct htcpld_chip) * htcpld->nchips, + GFP_KERNEL); + if (!htcpld->chip) { + dev_warn(dev, "Unable to allocate memory for chips\n"); + return -ENOMEM; + } + + /* Add the chips as best we can */ + for (i = 0; i < htcpld->nchips; i++) { + int ret; + + /* Setup the HTCPLD chips */ + htcpld->chip[i].reset = pdata->chip[i].reset; + htcpld->chip[i].cache_out = pdata->chip[i].reset; + htcpld->chip[i].cache_in = 0; + htcpld->chip[i].dev = dev; + htcpld->chip[i].irq_start = pdata->chip[i].irq_base; + htcpld->chip[i].nirqs = pdata->chip[i].num_irqs; + + INIT_WORK(&(htcpld->chip[i].set_val_work), &htcpld_chip_set_ni); + spin_lock_init(&(htcpld->chip[i].lock)); + + /* Setup the interrupts for the chip */ + if (htcpld->chained_irq) { + ret = htcpld_setup_chip_irq(pdev, i); + if (ret) + continue; + } + + /* Register the chip with I2C */ + ret = htcpld_register_chip_i2c(pdev, i); + if (ret) + continue; + + + /* Register the chips with the GPIO subsystem */ + ret = htcpld_register_chip_gpio(pdev, i); + if (ret) { + /* Unregister the chip from i2c and continue */ + htcpld_unregister_chip_i2c(pdev, i); + continue; + } + + dev_info(dev, "Registered chip at 0x%x\n", pdata->chip[i].addr); + } + + return 0; +} + +static int __devinit htcpld_core_probe(struct platform_device *pdev) +{ + struct htcpld_data *htcpld; + struct device *dev = &pdev->dev; + struct htcpld_core_platform_data *pdata; + struct resource *res; + int ret = 0; + + if (!dev) + return -ENODEV; + + pdata = dev->platform_data; + if (!pdata) { + dev_warn(dev, "Platform data not found for htcpld core!\n"); + return -ENXIO; + } + + htcpld = kzalloc(sizeof(struct htcpld_data), GFP_KERNEL); + if (!htcpld) + return -ENOMEM; + + /* Find chained irq */ + ret = -EINVAL; + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res) { + int flags; + htcpld->chained_irq = res->start; + + /* Setup the chained interrupt handler */ + flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING; + ret = request_threaded_irq(htcpld->chained_irq, + NULL, htcpld_handler, + flags, pdev->name, htcpld); + if (ret) { + dev_warn(dev, "Unable to setup chained irq handler: %d\n", ret); + goto fail; + } else + device_init_wakeup(dev, 0); + } + + /* Set the driver data */ + platform_set_drvdata(pdev, htcpld); + + /* Setup the htcpld chips */ + ret = htcpld_setup_chips(pdev); + if (ret) + goto fail; + + /* Request the GPIO(s) for the int reset and set them up */ + if (pdata->int_reset_gpio_hi) { + ret = gpio_request(pdata->int_reset_gpio_hi, "htcpld-core"); + if (ret) { + /* + * If it failed, that sucks, but we can probably + * continue on without it. + */ + dev_warn(dev, "Unable to request int_reset_gpio_hi -- interrupts may not work\n"); + htcpld->int_reset_gpio_hi = 0; + } else { + htcpld->int_reset_gpio_hi = pdata->int_reset_gpio_hi; + gpio_set_value(htcpld->int_reset_gpio_hi, 1); + } + } + + if (pdata->int_reset_gpio_lo) { + ret = gpio_request(pdata->int_reset_gpio_lo, "htcpld-core"); + if (ret) { + /* + * If it failed, that sucks, but we can probably + * continue on without it. + */ + dev_warn(dev, "Unable to request int_reset_gpio_lo -- interrupts may not work\n"); + htcpld->int_reset_gpio_lo = 0; + } else { + htcpld->int_reset_gpio_lo = pdata->int_reset_gpio_lo; + gpio_set_value(htcpld->int_reset_gpio_lo, 0); + } + } + + dev_info(dev, "Initialized successfully\n"); + return 0; + +fail: + kfree(htcpld); + return ret; +} + +/* The I2C Driver -- used internally */ +static const struct i2c_device_id htcpld_chip_id[] = { + { "htcpld-chip", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, htcpld_chip_id); + + +static struct i2c_driver htcpld_chip_driver = { + .driver = { + .name = "htcpld-chip", + }, + .id_table = htcpld_chip_id, +}; + +/* The Core Driver */ +static struct platform_driver htcpld_core_driver = { + .driver = { + .name = "i2c-htcpld", + }, +}; + +static int __init htcpld_core_init(void) +{ + int ret; + + /* Register the I2C Chip driver */ + ret = i2c_add_driver(&htcpld_chip_driver); + if (ret) + return ret; + + /* Probe for our chips */ + return platform_driver_probe(&htcpld_core_driver, htcpld_core_probe); +} + +static void __exit htcpld_core_exit(void) +{ + i2c_del_driver(&htcpld_chip_driver); + platform_driver_unregister(&htcpld_core_driver); +} + +module_init(htcpld_core_init); +module_exit(htcpld_core_exit); + +MODULE_AUTHOR("Cory Maccarrone "); +MODULE_DESCRIPTION("I2C HTC PLD Driver"); +MODULE_LICENSE("GPL"); + diff --git a/include/linux/htcpld.h b/include/linux/htcpld.h new file mode 100644 index 0000000..ab3f6cb4 --- /dev/null +++ b/include/linux/htcpld.h @@ -0,0 +1,24 @@ +#ifndef __LINUX_HTCPLD_H +#define __LINUX_HTCPLD_H + +struct htcpld_chip_platform_data { + unsigned int addr; + unsigned int reset; + unsigned int num_gpios; + unsigned int gpio_out_base; + unsigned int gpio_in_base; + unsigned int irq_base; + unsigned int num_irqs; +}; + +struct htcpld_core_platform_data { + unsigned int int_reset_gpio_hi; + unsigned int int_reset_gpio_lo; + unsigned int i2c_adapter_id; + + struct htcpld_chip_platform_data *chip; + unsigned int num_chip; +}; + +#endif /* __LINUX_HTCPLD_H */ + -- cgit v0.10.2 From 2071db4848ea809887e97248dd3dec02a2e3dd6b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 19 Jan 2010 11:41:52 +0100 Subject: mfd: Use AB3100 MFD core IRQ for interrupt randomness This reintroduces the entropy sampling of the AB3100 IRQ as the IRQF_SAMPLE_RANDOM is going out according to the feature removal schedule. I'm trying to do this the right way then, so CC:ing some random people for a quick review. We add entropy for interrupt events in the AB3100 which are truly random in nature, like external cables being connected, voltages on batteries dropping below certain ranges, ADC triggers or overheating. Signed-off-by: Linus Walleij Cc: Robin Getz Acked-by: Matt Mackall Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 9bcd447..ea2557b 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -329,8 +329,8 @@ config PCF50633_GPIO the PCF50633 chip. config AB3100_CORE - tristate "ST-Ericsson AB3100 Mixed Signal Circuit core functions" - depends on I2C + bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" + depends on I2C=y default y if ARCH_U300 help Select this to enable the AB3100 Mixed Signal IC core diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index aa3824a..a2ce3b6 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2009 ST-Ericsson + * Copyright (C) 2007-2010 ST-Ericsson * License terms: GNU General Public License (GPL) version 2 * Low-level core for exclusive access to the AB3100 IC on the I2C bus * and some basic chip-configuration. @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -376,6 +377,8 @@ static irqreturn_t ab3100_irq_handler(int irq, void *data) u32 fatevent; int err; + add_interrupt_randomness(irq); + err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1, event_regs, 3); if (err) @@ -720,10 +723,7 @@ static struct platform_device ab3100_##devname##_device = { \ .id = -1, \ } -/* - * This lists all the subdevices and corresponding register - * ranges. - */ +/* This lists all the subdevices */ AB3100_DEVICE(dac, "ab3100-dac"); AB3100_DEVICE(leds, "ab3100-leds"); AB3100_DEVICE(power, "ab3100-power"); @@ -889,10 +889,11 @@ static int __init ab3100_probe(struct i2c_client *client, if (err) goto exit_no_setup; - /* This real unpredictable IRQ is of course sampled for entropy */ err = request_threaded_irq(client->irq, NULL, ab3100_irq_handler, - IRQF_ONESHOT, - "ab3100-core", ab3100); + IRQF_ONESHOT, "ab3100-core", ab3100); + /* This real unpredictable IRQ is of course sampled for entropy */ + rand_initialize_irq(client->irq); + if (err) goto exit_no_irq; -- cgit v0.10.2 From ca229f1b624a72a1c9eb1d94bbca7a0c094a1b8b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 17 Jan 2010 20:57:43 +0100 Subject: mfd: Fix debugfs code in AB3100 OTP driver This fixes the aged and unreachable debugfs code in the AB3100 OTP driver so that it's (A) reachable and (B) works. Bug detected in parallell by Christoph Egger using VAMOS and Robert P. J. Day by his kernel scanning script. Signed-off-by: Linus Walleij Cc: Christoph Egger Cc: Robert P. J. Day Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/ab3100-otp.c b/drivers/mfd/ab3100-otp.c index 0499b20..b603469 100644 --- a/drivers/mfd/ab3100-otp.c +++ b/drivers/mfd/ab3100-otp.c @@ -13,6 +13,7 @@ #include #include #include +#include /* The OTP registers */ #define AB3100_OTP0 0xb0 @@ -95,11 +96,10 @@ static int __init ab3100_otp_read(struct ab3100_otp *otp) * This is a simple debugfs human-readable file that dumps out * the contents of the OTP. */ -#ifdef CONFIG_DEBUGFS -static int show_otp(struct seq_file *s, void *v) +#ifdef CONFIG_DEBUG_FS +static int ab3100_show_otp(struct seq_file *s, void *v) { struct ab3100_otp *otp = s->private; - int err; seq_printf(s, "OTP is %s\n", otp->locked ? "LOCKED" : "UNLOCKED"); seq_printf(s, "OTP clock switch startup is %uHz\n", otp->freq); @@ -113,7 +113,7 @@ static int show_otp(struct seq_file *s, void *v) static int ab3100_otp_open(struct inode *inode, struct file *file) { - return single_open(file, ab3100_otp_show, inode->i_private); + return single_open(file, ab3100_show_otp, inode->i_private); } static const struct file_operations ab3100_otp_operations = { @@ -131,13 +131,14 @@ static int __init ab3100_otp_init_debugfs(struct device *dev, &ab3100_otp_operations); if (!otp->debugfs) { dev_err(dev, "AB3100 debugfs OTP file registration failed!\n"); - return err; + return -ENOENT; } + return 0; } static void __exit ab3100_otp_exit_debugfs(struct ab3100_otp *otp) { - debugfs_remove_file(otp->debugfs); + debugfs_remove(otp->debugfs); } #else /* Compile this out if debugfs not selected */ -- cgit v0.10.2 From f7ea2dc59ed46dcd0f1cfaccda02211f4507207b Mon Sep 17 00:00:00 2001 From: Christoph Egger Date: Fri, 15 Jan 2010 15:33:46 +0100 Subject: mfd: Remove leftover from discontinued TWL4030 battery patch The TWL4030_BCI_BATTERY config option originates from a patch to the omap git tree. However inclusion in linux was seemingly rejected and the functionality nears inclusion under a different name so this removes the bits of the old version that made it into the mainline kernel again. Signed-off-by: Christoph Egger Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 19a930d..d81003f 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -58,13 +58,6 @@ #define DRIVER_NAME "twl" -#if defined(CONFIG_TWL4030_BCI_BATTERY) || \ - defined(CONFIG_TWL4030_BCI_BATTERY_MODULE) -#define twl_has_bci() true -#else -#define twl_has_bci() false -#endif - #if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE) #define twl_has_keypad() true #else @@ -588,18 +581,6 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) struct device *child; unsigned sub_chip_id; - if (twl_has_bci() && pdata->bci && - !(features & (TPS_SUBSET | TWL5031))) { - child = add_child(3, "twl4030_bci", - pdata->bci, sizeof(*pdata->bci), - false, - /* irq0 = CHG_PRES, irq1 = BCI */ - pdata->irq_base + BCI_PRES_INTR_OFFSET, - pdata->irq_base + BCI_INTR_OFFSET); - if (IS_ERR(child)) - return PTR_ERR(child); - } - if (twl_has_gpio() && pdata->gpio) { child = add_child(SUB_CHIP_ID1, "twl4030_gpio", pdata->gpio, sizeof(*pdata->gpio), diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index 7897f30..9733e9e 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -605,12 +605,7 @@ int twl4030_sih_setup(int module); #define TWL4030_VAUX3_DEV_GRP 0x1F #define TWL4030_VAUX3_DEDICATED 0x22 -#if defined(CONFIG_TWL4030_BCI_BATTERY) || \ - defined(CONFIG_TWL4030_BCI_BATTERY_MODULE) - extern int twl4030charger_usb_en(int enable); -#else - static inline int twl4030charger_usb_en(int enable) { return 0; } -#endif +static inline int twl4030charger_usb_en(int enable) { return 0; } /*----------------------------------------------------------------------*/ -- cgit v0.10.2 From bef3e20c9f8ce5cb8809cf33494d95a78db07857 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 20 Jan 2010 19:55:34 -0800 Subject: mfd: htc-i2cpld depends on GPIOLIB htc-i2cpld should depend on GPIOLIB, otherwise there are many build errors: drivers/mfd/htc-i2cpld.c:50: error: field 'chip_out' has incomplete type drivers/mfd/htc-i2cpld.c:54: error: field 'chip_in' has incomplete type drivers/mfd/htc-i2cpld.c:243: warning: type defaults to 'int' in declaration of '__mptr' drivers/mfd/htc-i2cpld.c:243: warning: initialization from incompatible pointer type drivers/mfd/htc-i2cpld.c:278: warning: type defaults to 'int' in declaration of '__mptr' drivers/mfd/htc-i2cpld.c:278: warning: initialization from incompatible pointer type drivers/mfd/htc-i2cpld.c:282: warning: type defaults to 'int' in declaration of '__mptr' drivers/mfd/htc-i2cpld.c:282: warning: initialization from incompatible pointer type drivers/mfd/htc-i2cpld.c:315: error: dereferencing pointer to incomplete type drivers/mfd/htc-i2cpld.c:322: warning: type defaults to 'int' in declaration of '__mptr' drivers/mfd/htc-i2cpld.c:322: warning: initialization from incompatible pointer type drivers/mfd/htc-i2cpld.c:467+: error: dereferencing pointer to incomplete type [19X] drivers/mfd/htc-i2cpld.c:490: error: implicit declaration of function 'gpiochip_add' drivers/mfd/htc-i2cpld.c:504: error: implicit declaration of function 'gpiochip_remove' Signed-off-by: Randy Dunlap Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ea2557b..a760dbe 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -80,7 +80,7 @@ config HTC_PASIC3 config HTC_I2CPLD bool "HTC I2C PLD chip support" - depends on I2C=y + depends on I2C=y && GPIOLIB help If you say yes here you get support for the supposed CPLD found on omap850 HTC devices like the HTC Wizard and HTC Herald. -- cgit v0.10.2 From 1c4d3b70a40c666331052adf77933e6994590b74 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Jan 2010 18:20:28 +0000 Subject: mfd: Add WM8994 register definitions As a separate patch due to the large size. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz diff --git a/include/linux/mfd/wm8994/registers.h b/include/linux/mfd/wm8994/registers.h new file mode 100644 index 0000000..967f62f --- /dev/null +++ b/include/linux/mfd/wm8994/registers.h @@ -0,0 +1,4292 @@ +/* + * include/linux/mfd/wm8994/registers.h -- Register definitions for WM8994 + * + * Copyright 2009 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MFD_WM8994_REGISTERS_H__ +#define __MFD_WM8994_REGISTERS_H__ + +/* + * Register values. + */ +#define WM8994_SOFTWARE_RESET 0x00 +#define WM8994_POWER_MANAGEMENT_1 0x01 +#define WM8994_POWER_MANAGEMENT_2 0x02 +#define WM8994_POWER_MANAGEMENT_3 0x03 +#define WM8994_POWER_MANAGEMENT_4 0x04 +#define WM8994_POWER_MANAGEMENT_5 0x05 +#define WM8994_POWER_MANAGEMENT_6 0x06 +#define WM8994_INPUT_MIXER_1 0x15 +#define WM8994_LEFT_LINE_INPUT_1_2_VOLUME 0x18 +#define WM8994_LEFT_LINE_INPUT_3_4_VOLUME 0x19 +#define WM8994_RIGHT_LINE_INPUT_1_2_VOLUME 0x1A +#define WM8994_RIGHT_LINE_INPUT_3_4_VOLUME 0x1B +#define WM8994_LEFT_OUTPUT_VOLUME 0x1C +#define WM8994_RIGHT_OUTPUT_VOLUME 0x1D +#define WM8994_LINE_OUTPUTS_VOLUME 0x1E +#define WM8994_HPOUT2_VOLUME 0x1F +#define WM8994_LEFT_OPGA_VOLUME 0x20 +#define WM8994_RIGHT_OPGA_VOLUME 0x21 +#define WM8994_SPKMIXL_ATTENUATION 0x22 +#define WM8994_SPKMIXR_ATTENUATION 0x23 +#define WM8994_SPKOUT_MIXERS 0x24 +#define WM8994_CLASSD 0x25 +#define WM8994_SPEAKER_VOLUME_LEFT 0x26 +#define WM8994_SPEAKER_VOLUME_RIGHT 0x27 +#define WM8994_INPUT_MIXER_2 0x28 +#define WM8994_INPUT_MIXER_3 0x29 +#define WM8994_INPUT_MIXER_4 0x2A +#define WM8994_INPUT_MIXER_5 0x2B +#define WM8994_INPUT_MIXER_6 0x2C +#define WM8994_OUTPUT_MIXER_1 0x2D +#define WM8994_OUTPUT_MIXER_2 0x2E +#define WM8994_OUTPUT_MIXER_3 0x2F +#define WM8994_OUTPUT_MIXER_4 0x30 +#define WM8994_OUTPUT_MIXER_5 0x31 +#define WM8994_OUTPUT_MIXER_6 0x32 +#define WM8994_HPOUT2_MIXER 0x33 +#define WM8994_LINE_MIXER_1 0x34 +#define WM8994_LINE_MIXER_2 0x35 +#define WM8994_SPEAKER_MIXER 0x36 +#define WM8994_ADDITIONAL_CONTROL 0x37 +#define WM8994_ANTIPOP_1 0x38 +#define WM8994_ANTIPOP_2 0x39 +#define WM8994_MICBIAS 0x3A +#define WM8994_LDO_1 0x3B +#define WM8994_LDO_2 0x3C +#define WM8994_CHARGE_PUMP_1 0x4C +#define WM8994_CLASS_W_1 0x51 +#define WM8994_DC_SERVO_1 0x54 +#define WM8994_DC_SERVO_2 0x55 +#define WM8994_DC_SERVO_4 0x57 +#define WM8994_DC_SERVO_READBACK 0x58 +#define WM8994_ANALOGUE_HP_1 0x60 +#define WM8994_CHIP_REVISION 0x100 +#define WM8994_CONTROL_INTERFACE 0x101 +#define WM8994_WRITE_SEQUENCER_CTRL_1 0x110 +#define WM8994_WRITE_SEQUENCER_CTRL_2 0x111 +#define WM8994_AIF1_CLOCKING_1 0x200 +#define WM8994_AIF1_CLOCKING_2 0x201 +#define WM8994_AIF2_CLOCKING_1 0x204 +#define WM8994_AIF2_CLOCKING_2 0x205 +#define WM8994_CLOCKING_1 0x208 +#define WM8994_CLOCKING_2 0x209 +#define WM8994_AIF1_RATE 0x210 +#define WM8994_AIF2_RATE 0x211 +#define WM8994_RATE_STATUS 0x212 +#define WM8994_FLL1_CONTROL_1 0x220 +#define WM8994_FLL1_CONTROL_2 0x221 +#define WM8994_FLL1_CONTROL_3 0x222 +#define WM8994_FLL1_CONTROL_4 0x223 +#define WM8994_FLL1_CONTROL_5 0x224 +#define WM8994_FLL2_CONTROL_1 0x240 +#define WM8994_FLL2_CONTROL_2 0x241 +#define WM8994_FLL2_CONTROL_3 0x242 +#define WM8994_FLL2_CONTROL_4 0x243 +#define WM8994_FLL2_CONTROL_5 0x244 +#define WM8994_AIF1_CONTROL_1 0x300 +#define WM8994_AIF1_CONTROL_2 0x301 +#define WM8994_AIF1_MASTER_SLAVE 0x302 +#define WM8994_AIF1_BCLK 0x303 +#define WM8994_AIF1ADC_LRCLK 0x304 +#define WM8994_AIF1DAC_LRCLK 0x305 +#define WM8994_AIF1DAC_DATA 0x306 +#define WM8994_AIF1ADC_DATA 0x307 +#define WM8994_AIF2_CONTROL_1 0x310 +#define WM8994_AIF2_CONTROL_2 0x311 +#define WM8994_AIF2_MASTER_SLAVE 0x312 +#define WM8994_AIF2_BCLK 0x313 +#define WM8994_AIF2ADC_LRCLK 0x314 +#define WM8994_AIF2DAC_LRCLK 0x315 +#define WM8994_AIF2DAC_DATA 0x316 +#define WM8994_AIF2ADC_DATA 0x317 +#define WM8994_AIF1_ADC1_LEFT_VOLUME 0x400 +#define WM8994_AIF1_ADC1_RIGHT_VOLUME 0x401 +#define WM8994_AIF1_DAC1_LEFT_VOLUME 0x402 +#define WM8994_AIF1_DAC1_RIGHT_VOLUME 0x403 +#define WM8994_AIF1_ADC2_LEFT_VOLUME 0x404 +#define WM8994_AIF1_ADC2_RIGHT_VOLUME 0x405 +#define WM8994_AIF1_DAC2_LEFT_VOLUME 0x406 +#define WM8994_AIF1_DAC2_RIGHT_VOLUME 0x407 +#define WM8994_AIF1_ADC1_FILTERS 0x410 +#define WM8994_AIF1_ADC2_FILTERS 0x411 +#define WM8994_AIF1_DAC1_FILTERS_1 0x420 +#define WM8994_AIF1_DAC1_FILTERS_2 0x421 +#define WM8994_AIF1_DAC2_FILTERS_1 0x422 +#define WM8994_AIF1_DAC2_FILTERS_2 0x423 +#define WM8994_AIF1_DRC1_1 0x440 +#define WM8994_AIF1_DRC1_2 0x441 +#define WM8994_AIF1_DRC1_3 0x442 +#define WM8994_AIF1_DRC1_4 0x443 +#define WM8994_AIF1_DRC1_5 0x444 +#define WM8994_AIF1_DRC2_1 0x450 +#define WM8994_AIF1_DRC2_2 0x451 +#define WM8994_AIF1_DRC2_3 0x452 +#define WM8994_AIF1_DRC2_4 0x453 +#define WM8994_AIF1_DRC2_5 0x454 +#define WM8994_AIF1_DAC1_EQ_GAINS_1 0x480 +#define WM8994_AIF1_DAC1_EQ_GAINS_2 0x481 +#define WM8994_AIF1_DAC1_EQ_BAND_1_A 0x482 +#define WM8994_AIF1_DAC1_EQ_BAND_1_B 0x483 +#define WM8994_AIF1_DAC1_EQ_BAND_1_PG 0x484 +#define WM8994_AIF1_DAC1_EQ_BAND_2_A 0x485 +#define WM8994_AIF1_DAC1_EQ_BAND_2_B 0x486 +#define WM8994_AIF1_DAC1_EQ_BAND_2_C 0x487 +#define WM8994_AIF1_DAC1_EQ_BAND_2_PG 0x488 +#define WM8994_AIF1_DAC1_EQ_BAND_3_A 0x489 +#define WM8994_AIF1_DAC1_EQ_BAND_3_B 0x48A +#define WM8994_AIF1_DAC1_EQ_BAND_3_C 0x48B +#define WM8994_AIF1_DAC1_EQ_BAND_3_PG 0x48C +#define WM8994_AIF1_DAC1_EQ_BAND_4_A 0x48D +#define WM8994_AIF1_DAC1_EQ_BAND_4_B 0x48E +#define WM8994_AIF1_DAC1_EQ_BAND_4_C 0x48F +#define WM8994_AIF1_DAC1_EQ_BAND_4_PG 0x490 +#define WM8994_AIF1_DAC1_EQ_BAND_5_A 0x491 +#define WM8994_AIF1_DAC1_EQ_BAND_5_B 0x492 +#define WM8994_AIF1_DAC1_EQ_BAND_5_PG 0x493 +#define WM8994_AIF1_DAC2_EQ_GAINS_1 0x4A0 +#define WM8994_AIF1_DAC2_EQ_GAINS_2 0x4A1 +#define WM8994_AIF1_DAC2_EQ_BAND_1_A 0x4A2 +#define WM8994_AIF1_DAC2_EQ_BAND_1_B 0x4A3 +#define WM8994_AIF1_DAC2_EQ_BAND_1_PG 0x4A4 +#define WM8994_AIF1_DAC2_EQ_BAND_2_A 0x4A5 +#define WM8994_AIF1_DAC2_EQ_BAND_2_B 0x4A6 +#define WM8994_AIF1_DAC2_EQ_BAND_2_C 0x4A7 +#define WM8994_AIF1_DAC2_EQ_BAND_2_PG 0x4A8 +#define WM8994_AIF1_DAC2_EQ_BAND_3_A 0x4A9 +#define WM8994_AIF1_DAC2_EQ_BAND_3_B 0x4AA +#define WM8994_AIF1_DAC2_EQ_BAND_3_C 0x4AB +#define WM8994_AIF1_DAC2_EQ_BAND_3_PG 0x4AC +#define WM8994_AIF1_DAC2_EQ_BAND_4_A 0x4AD +#define WM8994_AIF1_DAC2_EQ_BAND_4_B 0x4AE +#define WM8994_AIF1_DAC2_EQ_BAND_4_C 0x4AF +#define WM8994_AIF1_DAC2_EQ_BAND_4_PG 0x4B0 +#define WM8994_AIF1_DAC2_EQ_BAND_5_A 0x4B1 +#define WM8994_AIF1_DAC2_EQ_BAND_5_B 0x4B2 +#define WM8994_AIF1_DAC2_EQ_BAND_5_PG 0x4B3 +#define WM8994_AIF2_ADC_LEFT_VOLUME 0x500 +#define WM8994_AIF2_ADC_RIGHT_VOLUME 0x501 +#define WM8994_AIF2_DAC_LEFT_VOLUME 0x502 +#define WM8994_AIF2_DAC_RIGHT_VOLUME 0x503 +#define WM8994_AIF2_ADC_FILTERS 0x510 +#define WM8994_AIF2_DAC_FILTERS_1 0x520 +#define WM8994_AIF2_DAC_FILTERS_2 0x521 +#define WM8994_AIF2_DRC_1 0x540 +#define WM8994_AIF2_DRC_2 0x541 +#define WM8994_AIF2_DRC_3 0x542 +#define WM8994_AIF2_DRC_4 0x543 +#define WM8994_AIF2_DRC_5 0x544 +#define WM8994_AIF2_EQ_GAINS_1 0x580 +#define WM8994_AIF2_EQ_GAINS_2 0x581 +#define WM8994_AIF2_EQ_BAND_1_A 0x582 +#define WM8994_AIF2_EQ_BAND_1_B 0x583 +#define WM8994_AIF2_EQ_BAND_1_PG 0x584 +#define WM8994_AIF2_EQ_BAND_2_A 0x585 +#define WM8994_AIF2_EQ_BAND_2_B 0x586 +#define WM8994_AIF2_EQ_BAND_2_C 0x587 +#define WM8994_AIF2_EQ_BAND_2_PG 0x588 +#define WM8994_AIF2_EQ_BAND_3_A 0x589 +#define WM8994_AIF2_EQ_BAND_3_B 0x58A +#define WM8994_AIF2_EQ_BAND_3_C 0x58B +#define WM8994_AIF2_EQ_BAND_3_PG 0x58C +#define WM8994_AIF2_EQ_BAND_4_A 0x58D +#define WM8994_AIF2_EQ_BAND_4_B 0x58E +#define WM8994_AIF2_EQ_BAND_4_C 0x58F +#define WM8994_AIF2_EQ_BAND_4_PG 0x590 +#define WM8994_AIF2_EQ_BAND_5_A 0x591 +#define WM8994_AIF2_EQ_BAND_5_B 0x592 +#define WM8994_AIF2_EQ_BAND_5_PG 0x593 +#define WM8994_DAC1_MIXER_VOLUMES 0x600 +#define WM8994_DAC1_LEFT_MIXER_ROUTING 0x601 +#define WM8994_DAC1_RIGHT_MIXER_ROUTING 0x602 +#define WM8994_DAC2_MIXER_VOLUMES 0x603 +#define WM8994_DAC2_LEFT_MIXER_ROUTING 0x604 +#define WM8994_DAC2_RIGHT_MIXER_ROUTING 0x605 +#define WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING 0x606 +#define WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING 0x607 +#define WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING 0x608 +#define WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING 0x609 +#define WM8994_DAC1_LEFT_VOLUME 0x610 +#define WM8994_DAC1_RIGHT_VOLUME 0x611 +#define WM8994_DAC2_LEFT_VOLUME 0x612 +#define WM8994_DAC2_RIGHT_VOLUME 0x613 +#define WM8994_DAC_SOFTMUTE 0x614 +#define WM8994_OVERSAMPLING 0x620 +#define WM8994_SIDETONE 0x621 +#define WM8994_GPIO_1 0x700 +#define WM8994_GPIO_2 0x701 +#define WM8994_GPIO_3 0x702 +#define WM8994_GPIO_4 0x703 +#define WM8994_GPIO_5 0x704 +#define WM8994_GPIO_6 0x705 +#define WM8994_GPIO_7 0x706 +#define WM8994_GPIO_8 0x707 +#define WM8994_GPIO_9 0x708 +#define WM8994_GPIO_10 0x709 +#define WM8994_GPIO_11 0x70A +#define WM8994_PULL_CONTROL_1 0x720 +#define WM8994_PULL_CONTROL_2 0x721 +#define WM8994_INTERRUPT_STATUS_1 0x730 +#define WM8994_INTERRUPT_STATUS_2 0x731 +#define WM8994_INTERRUPT_RAW_STATUS_2 0x732 +#define WM8994_INTERRUPT_STATUS_1_MASK 0x738 +#define WM8994_INTERRUPT_STATUS_2_MASK 0x739 +#define WM8994_INTERRUPT_CONTROL 0x740 +#define WM8994_IRQ_DEBOUNCE 0x748 +#define WM8994_WRITE_SEQUENCER_0 0x3000 +#define WM8994_WRITE_SEQUENCER_1 0x3001 +#define WM8994_WRITE_SEQUENCER_2 0x3002 +#define WM8994_WRITE_SEQUENCER_3 0x3003 +#define WM8994_WRITE_SEQUENCER_4 0x3004 +#define WM8994_WRITE_SEQUENCER_5 0x3005 +#define WM8994_WRITE_SEQUENCER_6 0x3006 +#define WM8994_WRITE_SEQUENCER_7 0x3007 +#define WM8994_WRITE_SEQUENCER_8 0x3008 +#define WM8994_WRITE_SEQUENCER_9 0x3009 +#define WM8994_WRITE_SEQUENCER_10 0x300A +#define WM8994_WRITE_SEQUENCER_11 0x300B +#define WM8994_WRITE_SEQUENCER_12 0x300C +#define WM8994_WRITE_SEQUENCER_13 0x300D +#define WM8994_WRITE_SEQUENCER_14 0x300E +#define WM8994_WRITE_SEQUENCER_15 0x300F +#define WM8994_WRITE_SEQUENCER_16 0x3010 +#define WM8994_WRITE_SEQUENCER_17 0x3011 +#define WM8994_WRITE_SEQUENCER_18 0x3012 +#define WM8994_WRITE_SEQUENCER_19 0x3013 +#define WM8994_WRITE_SEQUENCER_20 0x3014 +#define WM8994_WRITE_SEQUENCER_21 0x3015 +#define WM8994_WRITE_SEQUENCER_22 0x3016 +#define WM8994_WRITE_SEQUENCER_23 0x3017 +#define WM8994_WRITE_SEQUENCER_24 0x3018 +#define WM8994_WRITE_SEQUENCER_25 0x3019 +#define WM8994_WRITE_SEQUENCER_26 0x301A +#define WM8994_WRITE_SEQUENCER_27 0x301B +#define WM8994_WRITE_SEQUENCER_28 0x301C +#define WM8994_WRITE_SEQUENCER_29 0x301D +#define WM8994_WRITE_SEQUENCER_30 0x301E +#define WM8994_WRITE_SEQUENCER_31 0x301F +#define WM8994_WRITE_SEQUENCER_32 0x3020 +#define WM8994_WRITE_SEQUENCER_33 0x3021 +#define WM8994_WRITE_SEQUENCER_34 0x3022 +#define WM8994_WRITE_SEQUENCER_35 0x3023 +#define WM8994_WRITE_SEQUENCER_36 0x3024 +#define WM8994_WRITE_SEQUENCER_37 0x3025 +#define WM8994_WRITE_SEQUENCER_38 0x3026 +#define WM8994_WRITE_SEQUENCER_39 0x3027 +#define WM8994_WRITE_SEQUENCER_40 0x3028 +#define WM8994_WRITE_SEQUENCER_41 0x3029 +#define WM8994_WRITE_SEQUENCER_42 0x302A +#define WM8994_WRITE_SEQUENCER_43 0x302B +#define WM8994_WRITE_SEQUENCER_44 0x302C +#define WM8994_WRITE_SEQUENCER_45 0x302D +#define WM8994_WRITE_SEQUENCER_46 0x302E +#define WM8994_WRITE_SEQUENCER_47 0x302F +#define WM8994_WRITE_SEQUENCER_48 0x3030 +#define WM8994_WRITE_SEQUENCER_49 0x3031 +#define WM8994_WRITE_SEQUENCER_50 0x3032 +#define WM8994_WRITE_SEQUENCER_51 0x3033 +#define WM8994_WRITE_SEQUENCER_52 0x3034 +#define WM8994_WRITE_SEQUENCER_53 0x3035 +#define WM8994_WRITE_SEQUENCER_54 0x3036 +#define WM8994_WRITE_SEQUENCER_55 0x3037 +#define WM8994_WRITE_SEQUENCER_56 0x3038 +#define WM8994_WRITE_SEQUENCER_57 0x3039 +#define WM8994_WRITE_SEQUENCER_58 0x303A +#define WM8994_WRITE_SEQUENCER_59 0x303B +#define WM8994_WRITE_SEQUENCER_60 0x303C +#define WM8994_WRITE_SEQUENCER_61 0x303D +#define WM8994_WRITE_SEQUENCER_62 0x303E +#define WM8994_WRITE_SEQUENCER_63 0x303F +#define WM8994_WRITE_SEQUENCER_64 0x3040 +#define WM8994_WRITE_SEQUENCER_65 0x3041 +#define WM8994_WRITE_SEQUENCER_66 0x3042 +#define WM8994_WRITE_SEQUENCER_67 0x3043 +#define WM8994_WRITE_SEQUENCER_68 0x3044 +#define WM8994_WRITE_SEQUENCER_69 0x3045 +#define WM8994_WRITE_SEQUENCER_70 0x3046 +#define WM8994_WRITE_SEQUENCER_71 0x3047 +#define WM8994_WRITE_SEQUENCER_72 0x3048 +#define WM8994_WRITE_SEQUENCER_73 0x3049 +#define WM8994_WRITE_SEQUENCER_74 0x304A +#define WM8994_WRITE_SEQUENCER_75 0x304B +#define WM8994_WRITE_SEQUENCER_76 0x304C +#define WM8994_WRITE_SEQUENCER_77 0x304D +#define WM8994_WRITE_SEQUENCER_78 0x304E +#define WM8994_WRITE_SEQUENCER_79 0x304F +#define WM8994_WRITE_SEQUENCER_80 0x3050 +#define WM8994_WRITE_SEQUENCER_81 0x3051 +#define WM8994_WRITE_SEQUENCER_82 0x3052 +#define WM8994_WRITE_SEQUENCER_83 0x3053 +#define WM8994_WRITE_SEQUENCER_84 0x3054 +#define WM8994_WRITE_SEQUENCER_85 0x3055 +#define WM8994_WRITE_SEQUENCER_86 0x3056 +#define WM8994_WRITE_SEQUENCER_87 0x3057 +#define WM8994_WRITE_SEQUENCER_88 0x3058 +#define WM8994_WRITE_SEQUENCER_89 0x3059 +#define WM8994_WRITE_SEQUENCER_90 0x305A +#define WM8994_WRITE_SEQUENCER_91 0x305B +#define WM8994_WRITE_SEQUENCER_92 0x305C +#define WM8994_WRITE_SEQUENCER_93 0x305D +#define WM8994_WRITE_SEQUENCER_94 0x305E +#define WM8994_WRITE_SEQUENCER_95 0x305F +#define WM8994_WRITE_SEQUENCER_96 0x3060 +#define WM8994_WRITE_SEQUENCER_97 0x3061 +#define WM8994_WRITE_SEQUENCER_98 0x3062 +#define WM8994_WRITE_SEQUENCER_99 0x3063 +#define WM8994_WRITE_SEQUENCER_100 0x3064 +#define WM8994_WRITE_SEQUENCER_101 0x3065 +#define WM8994_WRITE_SEQUENCER_102 0x3066 +#define WM8994_WRITE_SEQUENCER_103 0x3067 +#define WM8994_WRITE_SEQUENCER_104 0x3068 +#define WM8994_WRITE_SEQUENCER_105 0x3069 +#define WM8994_WRITE_SEQUENCER_106 0x306A +#define WM8994_WRITE_SEQUENCER_107 0x306B +#define WM8994_WRITE_SEQUENCER_108 0x306C +#define WM8994_WRITE_SEQUENCER_109 0x306D +#define WM8994_WRITE_SEQUENCER_110 0x306E +#define WM8994_WRITE_SEQUENCER_111 0x306F +#define WM8994_WRITE_SEQUENCER_112 0x3070 +#define WM8994_WRITE_SEQUENCER_113 0x3071 +#define WM8994_WRITE_SEQUENCER_114 0x3072 +#define WM8994_WRITE_SEQUENCER_115 0x3073 +#define WM8994_WRITE_SEQUENCER_116 0x3074 +#define WM8994_WRITE_SEQUENCER_117 0x3075 +#define WM8994_WRITE_SEQUENCER_118 0x3076 +#define WM8994_WRITE_SEQUENCER_119 0x3077 +#define WM8994_WRITE_SEQUENCER_120 0x3078 +#define WM8994_WRITE_SEQUENCER_121 0x3079 +#define WM8994_WRITE_SEQUENCER_122 0x307A +#define WM8994_WRITE_SEQUENCER_123 0x307B +#define WM8994_WRITE_SEQUENCER_124 0x307C +#define WM8994_WRITE_SEQUENCER_125 0x307D +#define WM8994_WRITE_SEQUENCER_126 0x307E +#define WM8994_WRITE_SEQUENCER_127 0x307F +#define WM8994_WRITE_SEQUENCER_128 0x3080 +#define WM8994_WRITE_SEQUENCER_129 0x3081 +#define WM8994_WRITE_SEQUENCER_130 0x3082 +#define WM8994_WRITE_SEQUENCER_131 0x3083 +#define WM8994_WRITE_SEQUENCER_132 0x3084 +#define WM8994_WRITE_SEQUENCER_133 0x3085 +#define WM8994_WRITE_SEQUENCER_134 0x3086 +#define WM8994_WRITE_SEQUENCER_135 0x3087 +#define WM8994_WRITE_SEQUENCER_136 0x3088 +#define WM8994_WRITE_SEQUENCER_137 0x3089 +#define WM8994_WRITE_SEQUENCER_138 0x308A +#define WM8994_WRITE_SEQUENCER_139 0x308B +#define WM8994_WRITE_SEQUENCER_140 0x308C +#define WM8994_WRITE_SEQUENCER_141 0x308D +#define WM8994_WRITE_SEQUENCER_142 0x308E +#define WM8994_WRITE_SEQUENCER_143 0x308F +#define WM8994_WRITE_SEQUENCER_144 0x3090 +#define WM8994_WRITE_SEQUENCER_145 0x3091 +#define WM8994_WRITE_SEQUENCER_146 0x3092 +#define WM8994_WRITE_SEQUENCER_147 0x3093 +#define WM8994_WRITE_SEQUENCER_148 0x3094 +#define WM8994_WRITE_SEQUENCER_149 0x3095 +#define WM8994_WRITE_SEQUENCER_150 0x3096 +#define WM8994_WRITE_SEQUENCER_151 0x3097 +#define WM8994_WRITE_SEQUENCER_152 0x3098 +#define WM8994_WRITE_SEQUENCER_153 0x3099 +#define WM8994_WRITE_SEQUENCER_154 0x309A +#define WM8994_WRITE_SEQUENCER_155 0x309B +#define WM8994_WRITE_SEQUENCER_156 0x309C +#define WM8994_WRITE_SEQUENCER_157 0x309D +#define WM8994_WRITE_SEQUENCER_158 0x309E +#define WM8994_WRITE_SEQUENCER_159 0x309F +#define WM8994_WRITE_SEQUENCER_160 0x30A0 +#define WM8994_WRITE_SEQUENCER_161 0x30A1 +#define WM8994_WRITE_SEQUENCER_162 0x30A2 +#define WM8994_WRITE_SEQUENCER_163 0x30A3 +#define WM8994_WRITE_SEQUENCER_164 0x30A4 +#define WM8994_WRITE_SEQUENCER_165 0x30A5 +#define WM8994_WRITE_SEQUENCER_166 0x30A6 +#define WM8994_WRITE_SEQUENCER_167 0x30A7 +#define WM8994_WRITE_SEQUENCER_168 0x30A8 +#define WM8994_WRITE_SEQUENCER_169 0x30A9 +#define WM8994_WRITE_SEQUENCER_170 0x30AA +#define WM8994_WRITE_SEQUENCER_171 0x30AB +#define WM8994_WRITE_SEQUENCER_172 0x30AC +#define WM8994_WRITE_SEQUENCER_173 0x30AD +#define WM8994_WRITE_SEQUENCER_174 0x30AE +#define WM8994_WRITE_SEQUENCER_175 0x30AF +#define WM8994_WRITE_SEQUENCER_176 0x30B0 +#define WM8994_WRITE_SEQUENCER_177 0x30B1 +#define WM8994_WRITE_SEQUENCER_178 0x30B2 +#define WM8994_WRITE_SEQUENCER_179 0x30B3 +#define WM8994_WRITE_SEQUENCER_180 0x30B4 +#define WM8994_WRITE_SEQUENCER_181 0x30B5 +#define WM8994_WRITE_SEQUENCER_182 0x30B6 +#define WM8994_WRITE_SEQUENCER_183 0x30B7 +#define WM8994_WRITE_SEQUENCER_184 0x30B8 +#define WM8994_WRITE_SEQUENCER_185 0x30B9 +#define WM8994_WRITE_SEQUENCER_186 0x30BA +#define WM8994_WRITE_SEQUENCER_187 0x30BB +#define WM8994_WRITE_SEQUENCER_188 0x30BC +#define WM8994_WRITE_SEQUENCER_189 0x30BD +#define WM8994_WRITE_SEQUENCER_190 0x30BE +#define WM8994_WRITE_SEQUENCER_191 0x30BF +#define WM8994_WRITE_SEQUENCER_192 0x30C0 +#define WM8994_WRITE_SEQUENCER_193 0x30C1 +#define WM8994_WRITE_SEQUENCER_194 0x30C2 +#define WM8994_WRITE_SEQUENCER_195 0x30C3 +#define WM8994_WRITE_SEQUENCER_196 0x30C4 +#define WM8994_WRITE_SEQUENCER_197 0x30C5 +#define WM8994_WRITE_SEQUENCER_198 0x30C6 +#define WM8994_WRITE_SEQUENCER_199 0x30C7 +#define WM8994_WRITE_SEQUENCER_200 0x30C8 +#define WM8994_WRITE_SEQUENCER_201 0x30C9 +#define WM8994_WRITE_SEQUENCER_202 0x30CA +#define WM8994_WRITE_SEQUENCER_203 0x30CB +#define WM8994_WRITE_SEQUENCER_204 0x30CC +#define WM8994_WRITE_SEQUENCER_205 0x30CD +#define WM8994_WRITE_SEQUENCER_206 0x30CE +#define WM8994_WRITE_SEQUENCER_207 0x30CF +#define WM8994_WRITE_SEQUENCER_208 0x30D0 +#define WM8994_WRITE_SEQUENCER_209 0x30D1 +#define WM8994_WRITE_SEQUENCER_210 0x30D2 +#define WM8994_WRITE_SEQUENCER_211 0x30D3 +#define WM8994_WRITE_SEQUENCER_212 0x30D4 +#define WM8994_WRITE_SEQUENCER_213 0x30D5 +#define WM8994_WRITE_SEQUENCER_214 0x30D6 +#define WM8994_WRITE_SEQUENCER_215 0x30D7 +#define WM8994_WRITE_SEQUENCER_216 0x30D8 +#define WM8994_WRITE_SEQUENCER_217 0x30D9 +#define WM8994_WRITE_SEQUENCER_218 0x30DA +#define WM8994_WRITE_SEQUENCER_219 0x30DB +#define WM8994_WRITE_SEQUENCER_220 0x30DC +#define WM8994_WRITE_SEQUENCER_221 0x30DD +#define WM8994_WRITE_SEQUENCER_222 0x30DE +#define WM8994_WRITE_SEQUENCER_223 0x30DF +#define WM8994_WRITE_SEQUENCER_224 0x30E0 +#define WM8994_WRITE_SEQUENCER_225 0x30E1 +#define WM8994_WRITE_SEQUENCER_226 0x30E2 +#define WM8994_WRITE_SEQUENCER_227 0x30E3 +#define WM8994_WRITE_SEQUENCER_228 0x30E4 +#define WM8994_WRITE_SEQUENCER_229 0x30E5 +#define WM8994_WRITE_SEQUENCER_230 0x30E6 +#define WM8994_WRITE_SEQUENCER_231 0x30E7 +#define WM8994_WRITE_SEQUENCER_232 0x30E8 +#define WM8994_WRITE_SEQUENCER_233 0x30E9 +#define WM8994_WRITE_SEQUENCER_234 0x30EA +#define WM8994_WRITE_SEQUENCER_235 0x30EB +#define WM8994_WRITE_SEQUENCER_236 0x30EC +#define WM8994_WRITE_SEQUENCER_237 0x30ED +#define WM8994_WRITE_SEQUENCER_238 0x30EE +#define WM8994_WRITE_SEQUENCER_239 0x30EF +#define WM8994_WRITE_SEQUENCER_240 0x30F0 +#define WM8994_WRITE_SEQUENCER_241 0x30F1 +#define WM8994_WRITE_SEQUENCER_242 0x30F2 +#define WM8994_WRITE_SEQUENCER_243 0x30F3 +#define WM8994_WRITE_SEQUENCER_244 0x30F4 +#define WM8994_WRITE_SEQUENCER_245 0x30F5 +#define WM8994_WRITE_SEQUENCER_246 0x30F6 +#define WM8994_WRITE_SEQUENCER_247 0x30F7 +#define WM8994_WRITE_SEQUENCER_248 0x30F8 +#define WM8994_WRITE_SEQUENCER_249 0x30F9 +#define WM8994_WRITE_SEQUENCER_250 0x30FA +#define WM8994_WRITE_SEQUENCER_251 0x30FB +#define WM8994_WRITE_SEQUENCER_252 0x30FC +#define WM8994_WRITE_SEQUENCER_253 0x30FD +#define WM8994_WRITE_SEQUENCER_254 0x30FE +#define WM8994_WRITE_SEQUENCER_255 0x30FF +#define WM8994_WRITE_SEQUENCER_256 0x3100 +#define WM8994_WRITE_SEQUENCER_257 0x3101 +#define WM8994_WRITE_SEQUENCER_258 0x3102 +#define WM8994_WRITE_SEQUENCER_259 0x3103 +#define WM8994_WRITE_SEQUENCER_260 0x3104 +#define WM8994_WRITE_SEQUENCER_261 0x3105 +#define WM8994_WRITE_SEQUENCER_262 0x3106 +#define WM8994_WRITE_SEQUENCER_263 0x3107 +#define WM8994_WRITE_SEQUENCER_264 0x3108 +#define WM8994_WRITE_SEQUENCER_265 0x3109 +#define WM8994_WRITE_SEQUENCER_266 0x310A +#define WM8994_WRITE_SEQUENCER_267 0x310B +#define WM8994_WRITE_SEQUENCER_268 0x310C +#define WM8994_WRITE_SEQUENCER_269 0x310D +#define WM8994_WRITE_SEQUENCER_270 0x310E +#define WM8994_WRITE_SEQUENCER_271 0x310F +#define WM8994_WRITE_SEQUENCER_272 0x3110 +#define WM8994_WRITE_SEQUENCER_273 0x3111 +#define WM8994_WRITE_SEQUENCER_274 0x3112 +#define WM8994_WRITE_SEQUENCER_275 0x3113 +#define WM8994_WRITE_SEQUENCER_276 0x3114 +#define WM8994_WRITE_SEQUENCER_277 0x3115 +#define WM8994_WRITE_SEQUENCER_278 0x3116 +#define WM8994_WRITE_SEQUENCER_279 0x3117 +#define WM8994_WRITE_SEQUENCER_280 0x3118 +#define WM8994_WRITE_SEQUENCER_281 0x3119 +#define WM8994_WRITE_SEQUENCER_282 0x311A +#define WM8994_WRITE_SEQUENCER_283 0x311B +#define WM8994_WRITE_SEQUENCER_284 0x311C +#define WM8994_WRITE_SEQUENCER_285 0x311D +#define WM8994_WRITE_SEQUENCER_286 0x311E +#define WM8994_WRITE_SEQUENCER_287 0x311F +#define WM8994_WRITE_SEQUENCER_288 0x3120 +#define WM8994_WRITE_SEQUENCER_289 0x3121 +#define WM8994_WRITE_SEQUENCER_290 0x3122 +#define WM8994_WRITE_SEQUENCER_291 0x3123 +#define WM8994_WRITE_SEQUENCER_292 0x3124 +#define WM8994_WRITE_SEQUENCER_293 0x3125 +#define WM8994_WRITE_SEQUENCER_294 0x3126 +#define WM8994_WRITE_SEQUENCER_295 0x3127 +#define WM8994_WRITE_SEQUENCER_296 0x3128 +#define WM8994_WRITE_SEQUENCER_297 0x3129 +#define WM8994_WRITE_SEQUENCER_298 0x312A +#define WM8994_WRITE_SEQUENCER_299 0x312B +#define WM8994_WRITE_SEQUENCER_300 0x312C +#define WM8994_WRITE_SEQUENCER_301 0x312D +#define WM8994_WRITE_SEQUENCER_302 0x312E +#define WM8994_WRITE_SEQUENCER_303 0x312F +#define WM8994_WRITE_SEQUENCER_304 0x3130 +#define WM8994_WRITE_SEQUENCER_305 0x3131 +#define WM8994_WRITE_SEQUENCER_306 0x3132 +#define WM8994_WRITE_SEQUENCER_307 0x3133 +#define WM8994_WRITE_SEQUENCER_308 0x3134 +#define WM8994_WRITE_SEQUENCER_309 0x3135 +#define WM8994_WRITE_SEQUENCER_310 0x3136 +#define WM8994_WRITE_SEQUENCER_311 0x3137 +#define WM8994_WRITE_SEQUENCER_312 0x3138 +#define WM8994_WRITE_SEQUENCER_313 0x3139 +#define WM8994_WRITE_SEQUENCER_314 0x313A +#define WM8994_WRITE_SEQUENCER_315 0x313B +#define WM8994_WRITE_SEQUENCER_316 0x313C +#define WM8994_WRITE_SEQUENCER_317 0x313D +#define WM8994_WRITE_SEQUENCER_318 0x313E +#define WM8994_WRITE_SEQUENCER_319 0x313F +#define WM8994_WRITE_SEQUENCER_320 0x3140 +#define WM8994_WRITE_SEQUENCER_321 0x3141 +#define WM8994_WRITE_SEQUENCER_322 0x3142 +#define WM8994_WRITE_SEQUENCER_323 0x3143 +#define WM8994_WRITE_SEQUENCER_324 0x3144 +#define WM8994_WRITE_SEQUENCER_325 0x3145 +#define WM8994_WRITE_SEQUENCER_326 0x3146 +#define WM8994_WRITE_SEQUENCER_327 0x3147 +#define WM8994_WRITE_SEQUENCER_328 0x3148 +#define WM8994_WRITE_SEQUENCER_329 0x3149 +#define WM8994_WRITE_SEQUENCER_330 0x314A +#define WM8994_WRITE_SEQUENCER_331 0x314B +#define WM8994_WRITE_SEQUENCER_332 0x314C +#define WM8994_WRITE_SEQUENCER_333 0x314D +#define WM8994_WRITE_SEQUENCER_334 0x314E +#define WM8994_WRITE_SEQUENCER_335 0x314F +#define WM8994_WRITE_SEQUENCER_336 0x3150 +#define WM8994_WRITE_SEQUENCER_337 0x3151 +#define WM8994_WRITE_SEQUENCER_338 0x3152 +#define WM8994_WRITE_SEQUENCER_339 0x3153 +#define WM8994_WRITE_SEQUENCER_340 0x3154 +#define WM8994_WRITE_SEQUENCER_341 0x3155 +#define WM8994_WRITE_SEQUENCER_342 0x3156 +#define WM8994_WRITE_SEQUENCER_343 0x3157 +#define WM8994_WRITE_SEQUENCER_344 0x3158 +#define WM8994_WRITE_SEQUENCER_345 0x3159 +#define WM8994_WRITE_SEQUENCER_346 0x315A +#define WM8994_WRITE_SEQUENCER_347 0x315B +#define WM8994_WRITE_SEQUENCER_348 0x315C +#define WM8994_WRITE_SEQUENCER_349 0x315D +#define WM8994_WRITE_SEQUENCER_350 0x315E +#define WM8994_WRITE_SEQUENCER_351 0x315F +#define WM8994_WRITE_SEQUENCER_352 0x3160 +#define WM8994_WRITE_SEQUENCER_353 0x3161 +#define WM8994_WRITE_SEQUENCER_354 0x3162 +#define WM8994_WRITE_SEQUENCER_355 0x3163 +#define WM8994_WRITE_SEQUENCER_356 0x3164 +#define WM8994_WRITE_SEQUENCER_357 0x3165 +#define WM8994_WRITE_SEQUENCER_358 0x3166 +#define WM8994_WRITE_SEQUENCER_359 0x3167 +#define WM8994_WRITE_SEQUENCER_360 0x3168 +#define WM8994_WRITE_SEQUENCER_361 0x3169 +#define WM8994_WRITE_SEQUENCER_362 0x316A +#define WM8994_WRITE_SEQUENCER_363 0x316B +#define WM8994_WRITE_SEQUENCER_364 0x316C +#define WM8994_WRITE_SEQUENCER_365 0x316D +#define WM8994_WRITE_SEQUENCER_366 0x316E +#define WM8994_WRITE_SEQUENCER_367 0x316F +#define WM8994_WRITE_SEQUENCER_368 0x3170 +#define WM8994_WRITE_SEQUENCER_369 0x3171 +#define WM8994_WRITE_SEQUENCER_370 0x3172 +#define WM8994_WRITE_SEQUENCER_371 0x3173 +#define WM8994_WRITE_SEQUENCER_372 0x3174 +#define WM8994_WRITE_SEQUENCER_373 0x3175 +#define WM8994_WRITE_SEQUENCER_374 0x3176 +#define WM8994_WRITE_SEQUENCER_375 0x3177 +#define WM8994_WRITE_SEQUENCER_376 0x3178 +#define WM8994_WRITE_SEQUENCER_377 0x3179 +#define WM8994_WRITE_SEQUENCER_378 0x317A +#define WM8994_WRITE_SEQUENCER_379 0x317B +#define WM8994_WRITE_SEQUENCER_380 0x317C +#define WM8994_WRITE_SEQUENCER_381 0x317D +#define WM8994_WRITE_SEQUENCER_382 0x317E +#define WM8994_WRITE_SEQUENCER_383 0x317F +#define WM8994_WRITE_SEQUENCER_384 0x3180 +#define WM8994_WRITE_SEQUENCER_385 0x3181 +#define WM8994_WRITE_SEQUENCER_386 0x3182 +#define WM8994_WRITE_SEQUENCER_387 0x3183 +#define WM8994_WRITE_SEQUENCER_388 0x3184 +#define WM8994_WRITE_SEQUENCER_389 0x3185 +#define WM8994_WRITE_SEQUENCER_390 0x3186 +#define WM8994_WRITE_SEQUENCER_391 0x3187 +#define WM8994_WRITE_SEQUENCER_392 0x3188 +#define WM8994_WRITE_SEQUENCER_393 0x3189 +#define WM8994_WRITE_SEQUENCER_394 0x318A +#define WM8994_WRITE_SEQUENCER_395 0x318B +#define WM8994_WRITE_SEQUENCER_396 0x318C +#define WM8994_WRITE_SEQUENCER_397 0x318D +#define WM8994_WRITE_SEQUENCER_398 0x318E +#define WM8994_WRITE_SEQUENCER_399 0x318F +#define WM8994_WRITE_SEQUENCER_400 0x3190 +#define WM8994_WRITE_SEQUENCER_401 0x3191 +#define WM8994_WRITE_SEQUENCER_402 0x3192 +#define WM8994_WRITE_SEQUENCER_403 0x3193 +#define WM8994_WRITE_SEQUENCER_404 0x3194 +#define WM8994_WRITE_SEQUENCER_405 0x3195 +#define WM8994_WRITE_SEQUENCER_406 0x3196 +#define WM8994_WRITE_SEQUENCER_407 0x3197 +#define WM8994_WRITE_SEQUENCER_408 0x3198 +#define WM8994_WRITE_SEQUENCER_409 0x3199 +#define WM8994_WRITE_SEQUENCER_410 0x319A +#define WM8994_WRITE_SEQUENCER_411 0x319B +#define WM8994_WRITE_SEQUENCER_412 0x319C +#define WM8994_WRITE_SEQUENCER_413 0x319D +#define WM8994_WRITE_SEQUENCER_414 0x319E +#define WM8994_WRITE_SEQUENCER_415 0x319F +#define WM8994_WRITE_SEQUENCER_416 0x31A0 +#define WM8994_WRITE_SEQUENCER_417 0x31A1 +#define WM8994_WRITE_SEQUENCER_418 0x31A2 +#define WM8994_WRITE_SEQUENCER_419 0x31A3 +#define WM8994_WRITE_SEQUENCER_420 0x31A4 +#define WM8994_WRITE_SEQUENCER_421 0x31A5 +#define WM8994_WRITE_SEQUENCER_422 0x31A6 +#define WM8994_WRITE_SEQUENCER_423 0x31A7 +#define WM8994_WRITE_SEQUENCER_424 0x31A8 +#define WM8994_WRITE_SEQUENCER_425 0x31A9 +#define WM8994_WRITE_SEQUENCER_426 0x31AA +#define WM8994_WRITE_SEQUENCER_427 0x31AB +#define WM8994_WRITE_SEQUENCER_428 0x31AC +#define WM8994_WRITE_SEQUENCER_429 0x31AD +#define WM8994_WRITE_SEQUENCER_430 0x31AE +#define WM8994_WRITE_SEQUENCER_431 0x31AF +#define WM8994_WRITE_SEQUENCER_432 0x31B0 +#define WM8994_WRITE_SEQUENCER_433 0x31B1 +#define WM8994_WRITE_SEQUENCER_434 0x31B2 +#define WM8994_WRITE_SEQUENCER_435 0x31B3 +#define WM8994_WRITE_SEQUENCER_436 0x31B4 +#define WM8994_WRITE_SEQUENCER_437 0x31B5 +#define WM8994_WRITE_SEQUENCER_438 0x31B6 +#define WM8994_WRITE_SEQUENCER_439 0x31B7 +#define WM8994_WRITE_SEQUENCER_440 0x31B8 +#define WM8994_WRITE_SEQUENCER_441 0x31B9 +#define WM8994_WRITE_SEQUENCER_442 0x31BA +#define WM8994_WRITE_SEQUENCER_443 0x31BB +#define WM8994_WRITE_SEQUENCER_444 0x31BC +#define WM8994_WRITE_SEQUENCER_445 0x31BD +#define WM8994_WRITE_SEQUENCER_446 0x31BE +#define WM8994_WRITE_SEQUENCER_447 0x31BF +#define WM8994_WRITE_SEQUENCER_448 0x31C0 +#define WM8994_WRITE_SEQUENCER_449 0x31C1 +#define WM8994_WRITE_SEQUENCER_450 0x31C2 +#define WM8994_WRITE_SEQUENCER_451 0x31C3 +#define WM8994_WRITE_SEQUENCER_452 0x31C4 +#define WM8994_WRITE_SEQUENCER_453 0x31C5 +#define WM8994_WRITE_SEQUENCER_454 0x31C6 +#define WM8994_WRITE_SEQUENCER_455 0x31C7 +#define WM8994_WRITE_SEQUENCER_456 0x31C8 +#define WM8994_WRITE_SEQUENCER_457 0x31C9 +#define WM8994_WRITE_SEQUENCER_458 0x31CA +#define WM8994_WRITE_SEQUENCER_459 0x31CB +#define WM8994_WRITE_SEQUENCER_460 0x31CC +#define WM8994_WRITE_SEQUENCER_461 0x31CD +#define WM8994_WRITE_SEQUENCER_462 0x31CE +#define WM8994_WRITE_SEQUENCER_463 0x31CF +#define WM8994_WRITE_SEQUENCER_464 0x31D0 +#define WM8994_WRITE_SEQUENCER_465 0x31D1 +#define WM8994_WRITE_SEQUENCER_466 0x31D2 +#define WM8994_WRITE_SEQUENCER_467 0x31D3 +#define WM8994_WRITE_SEQUENCER_468 0x31D4 +#define WM8994_WRITE_SEQUENCER_469 0x31D5 +#define WM8994_WRITE_SEQUENCER_470 0x31D6 +#define WM8994_WRITE_SEQUENCER_471 0x31D7 +#define WM8994_WRITE_SEQUENCER_472 0x31D8 +#define WM8994_WRITE_SEQUENCER_473 0x31D9 +#define WM8994_WRITE_SEQUENCER_474 0x31DA +#define WM8994_WRITE_SEQUENCER_475 0x31DB +#define WM8994_WRITE_SEQUENCER_476 0x31DC +#define WM8994_WRITE_SEQUENCER_477 0x31DD +#define WM8994_WRITE_SEQUENCER_478 0x31DE +#define WM8994_WRITE_SEQUENCER_479 0x31DF +#define WM8994_WRITE_SEQUENCER_480 0x31E0 +#define WM8994_WRITE_SEQUENCER_481 0x31E1 +#define WM8994_WRITE_SEQUENCER_482 0x31E2 +#define WM8994_WRITE_SEQUENCER_483 0x31E3 +#define WM8994_WRITE_SEQUENCER_484 0x31E4 +#define WM8994_WRITE_SEQUENCER_485 0x31E5 +#define WM8994_WRITE_SEQUENCER_486 0x31E6 +#define WM8994_WRITE_SEQUENCER_487 0x31E7 +#define WM8994_WRITE_SEQUENCER_488 0x31E8 +#define WM8994_WRITE_SEQUENCER_489 0x31E9 +#define WM8994_WRITE_SEQUENCER_490 0x31EA +#define WM8994_WRITE_SEQUENCER_491 0x31EB +#define WM8994_WRITE_SEQUENCER_492 0x31EC +#define WM8994_WRITE_SEQUENCER_493 0x31ED +#define WM8994_WRITE_SEQUENCER_494 0x31EE +#define WM8994_WRITE_SEQUENCER_495 0x31EF +#define WM8994_WRITE_SEQUENCER_496 0x31F0 +#define WM8994_WRITE_SEQUENCER_497 0x31F1 +#define WM8994_WRITE_SEQUENCER_498 0x31F2 +#define WM8994_WRITE_SEQUENCER_499 0x31F3 +#define WM8994_WRITE_SEQUENCER_500 0x31F4 +#define WM8994_WRITE_SEQUENCER_501 0x31F5 +#define WM8994_WRITE_SEQUENCER_502 0x31F6 +#define WM8994_WRITE_SEQUENCER_503 0x31F7 +#define WM8994_WRITE_SEQUENCER_504 0x31F8 +#define WM8994_WRITE_SEQUENCER_505 0x31F9 +#define WM8994_WRITE_SEQUENCER_506 0x31FA +#define WM8994_WRITE_SEQUENCER_507 0x31FB +#define WM8994_WRITE_SEQUENCER_508 0x31FC +#define WM8994_WRITE_SEQUENCER_509 0x31FD +#define WM8994_WRITE_SEQUENCER_510 0x31FE +#define WM8994_WRITE_SEQUENCER_511 0x31FF + +#define WM8994_REGISTER_COUNT 736 +#define WM8994_MAX_REGISTER 0x31FF +#define WM8994_MAX_CACHED_REGISTER 0x749 + +/* + * Field Definitions. + */ + +/* + * R0 (0x00) - Software Reset + */ +#define WM8994_SW_RESET_MASK 0xFFFF /* SW_RESET - [15:0] */ +#define WM8994_SW_RESET_SHIFT 0 /* SW_RESET - [15:0] */ +#define WM8994_SW_RESET_WIDTH 16 /* SW_RESET - [15:0] */ + +/* + * R1 (0x01) - Power Management (1) + */ +#define WM8994_SPKOUTR_ENA 0x2000 /* SPKOUTR_ENA */ +#define WM8994_SPKOUTR_ENA_MASK 0x2000 /* SPKOUTR_ENA */ +#define WM8994_SPKOUTR_ENA_SHIFT 13 /* SPKOUTR_ENA */ +#define WM8994_SPKOUTR_ENA_WIDTH 1 /* SPKOUTR_ENA */ +#define WM8994_SPKOUTL_ENA 0x1000 /* SPKOUTL_ENA */ +#define WM8994_SPKOUTL_ENA_MASK 0x1000 /* SPKOUTL_ENA */ +#define WM8994_SPKOUTL_ENA_SHIFT 12 /* SPKOUTL_ENA */ +#define WM8994_SPKOUTL_ENA_WIDTH 1 /* SPKOUTL_ENA */ +#define WM8994_HPOUT2_ENA 0x0800 /* HPOUT2_ENA */ +#define WM8994_HPOUT2_ENA_MASK 0x0800 /* HPOUT2_ENA */ +#define WM8994_HPOUT2_ENA_SHIFT 11 /* HPOUT2_ENA */ +#define WM8994_HPOUT2_ENA_WIDTH 1 /* HPOUT2_ENA */ +#define WM8994_HPOUT1L_ENA 0x0200 /* HPOUT1L_ENA */ +#define WM8994_HPOUT1L_ENA_MASK 0x0200 /* HPOUT1L_ENA */ +#define WM8994_HPOUT1L_ENA_SHIFT 9 /* HPOUT1L_ENA */ +#define WM8994_HPOUT1L_ENA_WIDTH 1 /* HPOUT1L_ENA */ +#define WM8994_HPOUT1R_ENA 0x0100 /* HPOUT1R_ENA */ +#define WM8994_HPOUT1R_ENA_MASK 0x0100 /* HPOUT1R_ENA */ +#define WM8994_HPOUT1R_ENA_SHIFT 8 /* HPOUT1R_ENA */ +#define WM8994_HPOUT1R_ENA_WIDTH 1 /* HPOUT1R_ENA */ +#define WM8994_MICB2_ENA 0x0020 /* MICB2_ENA */ +#define WM8994_MICB2_ENA_MASK 0x0020 /* MICB2_ENA */ +#define WM8994_MICB2_ENA_SHIFT 5 /* MICB2_ENA */ +#define WM8994_MICB2_ENA_WIDTH 1 /* MICB2_ENA */ +#define WM8994_MICB1_ENA 0x0010 /* MICB1_ENA */ +#define WM8994_MICB1_ENA_MASK 0x0010 /* MICB1_ENA */ +#define WM8994_MICB1_ENA_SHIFT 4 /* MICB1_ENA */ +#define WM8994_MICB1_ENA_WIDTH 1 /* MICB1_ENA */ +#define WM8994_VMID_SEL_MASK 0x0006 /* VMID_SEL - [2:1] */ +#define WM8994_VMID_SEL_SHIFT 1 /* VMID_SEL - [2:1] */ +#define WM8994_VMID_SEL_WIDTH 2 /* VMID_SEL - [2:1] */ +#define WM8994_BIAS_ENA 0x0001 /* BIAS_ENA */ +#define WM8994_BIAS_ENA_MASK 0x0001 /* BIAS_ENA */ +#define WM8994_BIAS_ENA_SHIFT 0 /* BIAS_ENA */ +#define WM8994_BIAS_ENA_WIDTH 1 /* BIAS_ENA */ + +/* + * R2 (0x02) - Power Management (2) + */ +#define WM8994_TSHUT_ENA 0x4000 /* TSHUT_ENA */ +#define WM8994_TSHUT_ENA_MASK 0x4000 /* TSHUT_ENA */ +#define WM8994_TSHUT_ENA_SHIFT 14 /* TSHUT_ENA */ +#define WM8994_TSHUT_ENA_WIDTH 1 /* TSHUT_ENA */ +#define WM8994_TSHUT_OPDIS 0x2000 /* TSHUT_OPDIS */ +#define WM8994_TSHUT_OPDIS_MASK 0x2000 /* TSHUT_OPDIS */ +#define WM8994_TSHUT_OPDIS_SHIFT 13 /* TSHUT_OPDIS */ +#define WM8994_TSHUT_OPDIS_WIDTH 1 /* TSHUT_OPDIS */ +#define WM8994_OPCLK_ENA 0x0800 /* OPCLK_ENA */ +#define WM8994_OPCLK_ENA_MASK 0x0800 /* OPCLK_ENA */ +#define WM8994_OPCLK_ENA_SHIFT 11 /* OPCLK_ENA */ +#define WM8994_OPCLK_ENA_WIDTH 1 /* OPCLK_ENA */ +#define WM8994_MIXINL_ENA 0x0200 /* MIXINL_ENA */ +#define WM8994_MIXINL_ENA_MASK 0x0200 /* MIXINL_ENA */ +#define WM8994_MIXINL_ENA_SHIFT 9 /* MIXINL_ENA */ +#define WM8994_MIXINL_ENA_WIDTH 1 /* MIXINL_ENA */ +#define WM8994_MIXINR_ENA 0x0100 /* MIXINR_ENA */ +#define WM8994_MIXINR_ENA_MASK 0x0100 /* MIXINR_ENA */ +#define WM8994_MIXINR_ENA_SHIFT 8 /* MIXINR_ENA */ +#define WM8994_MIXINR_ENA_WIDTH 1 /* MIXINR_ENA */ +#define WM8994_IN2L_ENA 0x0080 /* IN2L_ENA */ +#define WM8994_IN2L_ENA_MASK 0x0080 /* IN2L_ENA */ +#define WM8994_IN2L_ENA_SHIFT 7 /* IN2L_ENA */ +#define WM8994_IN2L_ENA_WIDTH 1 /* IN2L_ENA */ +#define WM8994_IN1L_ENA 0x0040 /* IN1L_ENA */ +#define WM8994_IN1L_ENA_MASK 0x0040 /* IN1L_ENA */ +#define WM8994_IN1L_ENA_SHIFT 6 /* IN1L_ENA */ +#define WM8994_IN1L_ENA_WIDTH 1 /* IN1L_ENA */ +#define WM8994_IN2R_ENA 0x0020 /* IN2R_ENA */ +#define WM8994_IN2R_ENA_MASK 0x0020 /* IN2R_ENA */ +#define WM8994_IN2R_ENA_SHIFT 5 /* IN2R_ENA */ +#define WM8994_IN2R_ENA_WIDTH 1 /* IN2R_ENA */ +#define WM8994_IN1R_ENA 0x0010 /* IN1R_ENA */ +#define WM8994_IN1R_ENA_MASK 0x0010 /* IN1R_ENA */ +#define WM8994_IN1R_ENA_SHIFT 4 /* IN1R_ENA */ +#define WM8994_IN1R_ENA_WIDTH 1 /* IN1R_ENA */ + +/* + * R3 (0x03) - Power Management (3) + */ +#define WM8994_LINEOUT1N_ENA 0x2000 /* LINEOUT1N_ENA */ +#define WM8994_LINEOUT1N_ENA_MASK 0x2000 /* LINEOUT1N_ENA */ +#define WM8994_LINEOUT1N_ENA_SHIFT 13 /* LINEOUT1N_ENA */ +#define WM8994_LINEOUT1N_ENA_WIDTH 1 /* LINEOUT1N_ENA */ +#define WM8994_LINEOUT1P_ENA 0x1000 /* LINEOUT1P_ENA */ +#define WM8994_LINEOUT1P_ENA_MASK 0x1000 /* LINEOUT1P_ENA */ +#define WM8994_LINEOUT1P_ENA_SHIFT 12 /* LINEOUT1P_ENA */ +#define WM8994_LINEOUT1P_ENA_WIDTH 1 /* LINEOUT1P_ENA */ +#define WM8994_LINEOUT2N_ENA 0x0800 /* LINEOUT2N_ENA */ +#define WM8994_LINEOUT2N_ENA_MASK 0x0800 /* LINEOUT2N_ENA */ +#define WM8994_LINEOUT2N_ENA_SHIFT 11 /* LINEOUT2N_ENA */ +#define WM8994_LINEOUT2N_ENA_WIDTH 1 /* LINEOUT2N_ENA */ +#define WM8994_LINEOUT2P_ENA 0x0400 /* LINEOUT2P_ENA */ +#define WM8994_LINEOUT2P_ENA_MASK 0x0400 /* LINEOUT2P_ENA */ +#define WM8994_LINEOUT2P_ENA_SHIFT 10 /* LINEOUT2P_ENA */ +#define WM8994_LINEOUT2P_ENA_WIDTH 1 /* LINEOUT2P_ENA */ +#define WM8994_SPKRVOL_ENA 0x0200 /* SPKRVOL_ENA */ +#define WM8994_SPKRVOL_ENA_MASK 0x0200 /* SPKRVOL_ENA */ +#define WM8994_SPKRVOL_ENA_SHIFT 9 /* SPKRVOL_ENA */ +#define WM8994_SPKRVOL_ENA_WIDTH 1 /* SPKRVOL_ENA */ +#define WM8994_SPKLVOL_ENA 0x0100 /* SPKLVOL_ENA */ +#define WM8994_SPKLVOL_ENA_MASK 0x0100 /* SPKLVOL_ENA */ +#define WM8994_SPKLVOL_ENA_SHIFT 8 /* SPKLVOL_ENA */ +#define WM8994_SPKLVOL_ENA_WIDTH 1 /* SPKLVOL_ENA */ +#define WM8994_MIXOUTLVOL_ENA 0x0080 /* MIXOUTLVOL_ENA */ +#define WM8994_MIXOUTLVOL_ENA_MASK 0x0080 /* MIXOUTLVOL_ENA */ +#define WM8994_MIXOUTLVOL_ENA_SHIFT 7 /* MIXOUTLVOL_ENA */ +#define WM8994_MIXOUTLVOL_ENA_WIDTH 1 /* MIXOUTLVOL_ENA */ +#define WM8994_MIXOUTRVOL_ENA 0x0040 /* MIXOUTRVOL_ENA */ +#define WM8994_MIXOUTRVOL_ENA_MASK 0x0040 /* MIXOUTRVOL_ENA */ +#define WM8994_MIXOUTRVOL_ENA_SHIFT 6 /* MIXOUTRVOL_ENA */ +#define WM8994_MIXOUTRVOL_ENA_WIDTH 1 /* MIXOUTRVOL_ENA */ +#define WM8994_MIXOUTL_ENA 0x0020 /* MIXOUTL_ENA */ +#define WM8994_MIXOUTL_ENA_MASK 0x0020 /* MIXOUTL_ENA */ +#define WM8994_MIXOUTL_ENA_SHIFT 5 /* MIXOUTL_ENA */ +#define WM8994_MIXOUTL_ENA_WIDTH 1 /* MIXOUTL_ENA */ +#define WM8994_MIXOUTR_ENA 0x0010 /* MIXOUTR_ENA */ +#define WM8994_MIXOUTR_ENA_MASK 0x0010 /* MIXOUTR_ENA */ +#define WM8994_MIXOUTR_ENA_SHIFT 4 /* MIXOUTR_ENA */ +#define WM8994_MIXOUTR_ENA_WIDTH 1 /* MIXOUTR_ENA */ + +/* + * R4 (0x04) - Power Management (4) + */ +#define WM8994_AIF2ADCL_ENA 0x2000 /* AIF2ADCL_ENA */ +#define WM8994_AIF2ADCL_ENA_MASK 0x2000 /* AIF2ADCL_ENA */ +#define WM8994_AIF2ADCL_ENA_SHIFT 13 /* AIF2ADCL_ENA */ +#define WM8994_AIF2ADCL_ENA_WIDTH 1 /* AIF2ADCL_ENA */ +#define WM8994_AIF2ADCR_ENA 0x1000 /* AIF2ADCR_ENA */ +#define WM8994_AIF2ADCR_ENA_MASK 0x1000 /* AIF2ADCR_ENA */ +#define WM8994_AIF2ADCR_ENA_SHIFT 12 /* AIF2ADCR_ENA */ +#define WM8994_AIF2ADCR_ENA_WIDTH 1 /* AIF2ADCR_ENA */ +#define WM8994_AIF1ADC2L_ENA 0x0800 /* AIF1ADC2L_ENA */ +#define WM8994_AIF1ADC2L_ENA_MASK 0x0800 /* AIF1ADC2L_ENA */ +#define WM8994_AIF1ADC2L_ENA_SHIFT 11 /* AIF1ADC2L_ENA */ +#define WM8994_AIF1ADC2L_ENA_WIDTH 1 /* AIF1ADC2L_ENA */ +#define WM8994_AIF1ADC2R_ENA 0x0400 /* AIF1ADC2R_ENA */ +#define WM8994_AIF1ADC2R_ENA_MASK 0x0400 /* AIF1ADC2R_ENA */ +#define WM8994_AIF1ADC2R_ENA_SHIFT 10 /* AIF1ADC2R_ENA */ +#define WM8994_AIF1ADC2R_ENA_WIDTH 1 /* AIF1ADC2R_ENA */ +#define WM8994_AIF1ADC1L_ENA 0x0200 /* AIF1ADC1L_ENA */ +#define WM8994_AIF1ADC1L_ENA_MASK 0x0200 /* AIF1ADC1L_ENA */ +#define WM8994_AIF1ADC1L_ENA_SHIFT 9 /* AIF1ADC1L_ENA */ +#define WM8994_AIF1ADC1L_ENA_WIDTH 1 /* AIF1ADC1L_ENA */ +#define WM8994_AIF1ADC1R_ENA 0x0100 /* AIF1ADC1R_ENA */ +#define WM8994_AIF1ADC1R_ENA_MASK 0x0100 /* AIF1ADC1R_ENA */ +#define WM8994_AIF1ADC1R_ENA_SHIFT 8 /* AIF1ADC1R_ENA */ +#define WM8994_AIF1ADC1R_ENA_WIDTH 1 /* AIF1ADC1R_ENA */ +#define WM8994_DMIC2L_ENA 0x0020 /* DMIC2L_ENA */ +#define WM8994_DMIC2L_ENA_MASK 0x0020 /* DMIC2L_ENA */ +#define WM8994_DMIC2L_ENA_SHIFT 5 /* DMIC2L_ENA */ +#define WM8994_DMIC2L_ENA_WIDTH 1 /* DMIC2L_ENA */ +#define WM8994_DMIC2R_ENA 0x0010 /* DMIC2R_ENA */ +#define WM8994_DMIC2R_ENA_MASK 0x0010 /* DMIC2R_ENA */ +#define WM8994_DMIC2R_ENA_SHIFT 4 /* DMIC2R_ENA */ +#define WM8994_DMIC2R_ENA_WIDTH 1 /* DMIC2R_ENA */ +#define WM8994_DMIC1L_ENA 0x0008 /* DMIC1L_ENA */ +#define WM8994_DMIC1L_ENA_MASK 0x0008 /* DMIC1L_ENA */ +#define WM8994_DMIC1L_ENA_SHIFT 3 /* DMIC1L_ENA */ +#define WM8994_DMIC1L_ENA_WIDTH 1 /* DMIC1L_ENA */ +#define WM8994_DMIC1R_ENA 0x0004 /* DMIC1R_ENA */ +#define WM8994_DMIC1R_ENA_MASK 0x0004 /* DMIC1R_ENA */ +#define WM8994_DMIC1R_ENA_SHIFT 2 /* DMIC1R_ENA */ +#define WM8994_DMIC1R_ENA_WIDTH 1 /* DMIC1R_ENA */ +#define WM8994_ADCL_ENA 0x0002 /* ADCL_ENA */ +#define WM8994_ADCL_ENA_MASK 0x0002 /* ADCL_ENA */ +#define WM8994_ADCL_ENA_SHIFT 1 /* ADCL_ENA */ +#define WM8994_ADCL_ENA_WIDTH 1 /* ADCL_ENA */ +#define WM8994_ADCR_ENA 0x0001 /* ADCR_ENA */ +#define WM8994_ADCR_ENA_MASK 0x0001 /* ADCR_ENA */ +#define WM8994_ADCR_ENA_SHIFT 0 /* ADCR_ENA */ +#define WM8994_ADCR_ENA_WIDTH 1 /* ADCR_ENA */ + +/* + * R5 (0x05) - Power Management (5) + */ +#define WM8994_AIF2DACL_ENA 0x2000 /* AIF2DACL_ENA */ +#define WM8994_AIF2DACL_ENA_MASK 0x2000 /* AIF2DACL_ENA */ +#define WM8994_AIF2DACL_ENA_SHIFT 13 /* AIF2DACL_ENA */ +#define WM8994_AIF2DACL_ENA_WIDTH 1 /* AIF2DACL_ENA */ +#define WM8994_AIF2DACR_ENA 0x1000 /* AIF2DACR_ENA */ +#define WM8994_AIF2DACR_ENA_MASK 0x1000 /* AIF2DACR_ENA */ +#define WM8994_AIF2DACR_ENA_SHIFT 12 /* AIF2DACR_ENA */ +#define WM8994_AIF2DACR_ENA_WIDTH 1 /* AIF2DACR_ENA */ +#define WM8994_AIF1DAC2L_ENA 0x0800 /* AIF1DAC2L_ENA */ +#define WM8994_AIF1DAC2L_ENA_MASK 0x0800 /* AIF1DAC2L_ENA */ +#define WM8994_AIF1DAC2L_ENA_SHIFT 11 /* AIF1DAC2L_ENA */ +#define WM8994_AIF1DAC2L_ENA_WIDTH 1 /* AIF1DAC2L_ENA */ +#define WM8994_AIF1DAC2R_ENA 0x0400 /* AIF1DAC2R_ENA */ +#define WM8994_AIF1DAC2R_ENA_MASK 0x0400 /* AIF1DAC2R_ENA */ +#define WM8994_AIF1DAC2R_ENA_SHIFT 10 /* AIF1DAC2R_ENA */ +#define WM8994_AIF1DAC2R_ENA_WIDTH 1 /* AIF1DAC2R_ENA */ +#define WM8994_AIF1DAC1L_ENA 0x0200 /* AIF1DAC1L_ENA */ +#define WM8994_AIF1DAC1L_ENA_MASK 0x0200 /* AIF1DAC1L_ENA */ +#define WM8994_AIF1DAC1L_ENA_SHIFT 9 /* AIF1DAC1L_ENA */ +#define WM8994_AIF1DAC1L_ENA_WIDTH 1 /* AIF1DAC1L_ENA */ +#define WM8994_AIF1DAC1R_ENA 0x0100 /* AIF1DAC1R_ENA */ +#define WM8994_AIF1DAC1R_ENA_MASK 0x0100 /* AIF1DAC1R_ENA */ +#define WM8994_AIF1DAC1R_ENA_SHIFT 8 /* AIF1DAC1R_ENA */ +#define WM8994_AIF1DAC1R_ENA_WIDTH 1 /* AIF1DAC1R_ENA */ +#define WM8994_DAC2L_ENA 0x0008 /* DAC2L_ENA */ +#define WM8994_DAC2L_ENA_MASK 0x0008 /* DAC2L_ENA */ +#define WM8994_DAC2L_ENA_SHIFT 3 /* DAC2L_ENA */ +#define WM8994_DAC2L_ENA_WIDTH 1 /* DAC2L_ENA */ +#define WM8994_DAC2R_ENA 0x0004 /* DAC2R_ENA */ +#define WM8994_DAC2R_ENA_MASK 0x0004 /* DAC2R_ENA */ +#define WM8994_DAC2R_ENA_SHIFT 2 /* DAC2R_ENA */ +#define WM8994_DAC2R_ENA_WIDTH 1 /* DAC2R_ENA */ +#define WM8994_DAC1L_ENA 0x0002 /* DAC1L_ENA */ +#define WM8994_DAC1L_ENA_MASK 0x0002 /* DAC1L_ENA */ +#define WM8994_DAC1L_ENA_SHIFT 1 /* DAC1L_ENA */ +#define WM8994_DAC1L_ENA_WIDTH 1 /* DAC1L_ENA */ +#define WM8994_DAC1R_ENA 0x0001 /* DAC1R_ENA */ +#define WM8994_DAC1R_ENA_MASK 0x0001 /* DAC1R_ENA */ +#define WM8994_DAC1R_ENA_SHIFT 0 /* DAC1R_ENA */ +#define WM8994_DAC1R_ENA_WIDTH 1 /* DAC1R_ENA */ + +/* + * R6 (0x06) - Power Management (6) + */ +#define WM8994_AIF3_TRI 0x0020 /* AIF3_TRI */ +#define WM8994_AIF3_TRI_MASK 0x0020 /* AIF3_TRI */ +#define WM8994_AIF3_TRI_SHIFT 5 /* AIF3_TRI */ +#define WM8994_AIF3_TRI_WIDTH 1 /* AIF3_TRI */ +#define WM8994_AIF3_ADCDAT_SRC_MASK 0x0018 /* AIF3_ADCDAT_SRC - [4:3] */ +#define WM8994_AIF3_ADCDAT_SRC_SHIFT 3 /* AIF3_ADCDAT_SRC - [4:3] */ +#define WM8994_AIF3_ADCDAT_SRC_WIDTH 2 /* AIF3_ADCDAT_SRC - [4:3] */ +#define WM8994_AIF2_ADCDAT_SRC 0x0004 /* AIF2_ADCDAT_SRC */ +#define WM8994_AIF2_ADCDAT_SRC_MASK 0x0004 /* AIF2_ADCDAT_SRC */ +#define WM8994_AIF2_ADCDAT_SRC_SHIFT 2 /* AIF2_ADCDAT_SRC */ +#define WM8994_AIF2_ADCDAT_SRC_WIDTH 1 /* AIF2_ADCDAT_SRC */ +#define WM8994_AIF2_DACDAT_SRC 0x0002 /* AIF2_DACDAT_SRC */ +#define WM8994_AIF2_DACDAT_SRC_MASK 0x0002 /* AIF2_DACDAT_SRC */ +#define WM8994_AIF2_DACDAT_SRC_SHIFT 1 /* AIF2_DACDAT_SRC */ +#define WM8994_AIF2_DACDAT_SRC_WIDTH 1 /* AIF2_DACDAT_SRC */ +#define WM8994_AIF1_DACDAT_SRC 0x0001 /* AIF1_DACDAT_SRC */ +#define WM8994_AIF1_DACDAT_SRC_MASK 0x0001 /* AIF1_DACDAT_SRC */ +#define WM8994_AIF1_DACDAT_SRC_SHIFT 0 /* AIF1_DACDAT_SRC */ +#define WM8994_AIF1_DACDAT_SRC_WIDTH 1 /* AIF1_DACDAT_SRC */ + +/* + * R21 (0x15) - Input Mixer (1) + */ +#define WM8994_IN1RP_MIXINR_BOOST 0x0100 /* IN1RP_MIXINR_BOOST */ +#define WM8994_IN1RP_MIXINR_BOOST_MASK 0x0100 /* IN1RP_MIXINR_BOOST */ +#define WM8994_IN1RP_MIXINR_BOOST_SHIFT 8 /* IN1RP_MIXINR_BOOST */ +#define WM8994_IN1RP_MIXINR_BOOST_WIDTH 1 /* IN1RP_MIXINR_BOOST */ +#define WM8994_IN1LP_MIXINL_BOOST 0x0080 /* IN1LP_MIXINL_BOOST */ +#define WM8994_IN1LP_MIXINL_BOOST_MASK 0x0080 /* IN1LP_MIXINL_BOOST */ +#define WM8994_IN1LP_MIXINL_BOOST_SHIFT 7 /* IN1LP_MIXINL_BOOST */ +#define WM8994_IN1LP_MIXINL_BOOST_WIDTH 1 /* IN1LP_MIXINL_BOOST */ +#define WM8994_INPUTS_CLAMP 0x0040 /* INPUTS_CLAMP */ +#define WM8994_INPUTS_CLAMP_MASK 0x0040 /* INPUTS_CLAMP */ +#define WM8994_INPUTS_CLAMP_SHIFT 6 /* INPUTS_CLAMP */ +#define WM8994_INPUTS_CLAMP_WIDTH 1 /* INPUTS_CLAMP */ + +/* + * R24 (0x18) - Left Line Input 1&2 Volume + */ +#define WM8994_IN1_VU 0x0100 /* IN1_VU */ +#define WM8994_IN1_VU_MASK 0x0100 /* IN1_VU */ +#define WM8994_IN1_VU_SHIFT 8 /* IN1_VU */ +#define WM8994_IN1_VU_WIDTH 1 /* IN1_VU */ +#define WM8994_IN1L_MUTE 0x0080 /* IN1L_MUTE */ +#define WM8994_IN1L_MUTE_MASK 0x0080 /* IN1L_MUTE */ +#define WM8994_IN1L_MUTE_SHIFT 7 /* IN1L_MUTE */ +#define WM8994_IN1L_MUTE_WIDTH 1 /* IN1L_MUTE */ +#define WM8994_IN1L_ZC 0x0040 /* IN1L_ZC */ +#define WM8994_IN1L_ZC_MASK 0x0040 /* IN1L_ZC */ +#define WM8994_IN1L_ZC_SHIFT 6 /* IN1L_ZC */ +#define WM8994_IN1L_ZC_WIDTH 1 /* IN1L_ZC */ +#define WM8994_IN1L_VOL_MASK 0x001F /* IN1L_VOL - [4:0] */ +#define WM8994_IN1L_VOL_SHIFT 0 /* IN1L_VOL - [4:0] */ +#define WM8994_IN1L_VOL_WIDTH 5 /* IN1L_VOL - [4:0] */ + +/* + * R25 (0x19) - Left Line Input 3&4 Volume + */ +#define WM8994_IN2_VU 0x0100 /* IN2_VU */ +#define WM8994_IN2_VU_MASK 0x0100 /* IN2_VU */ +#define WM8994_IN2_VU_SHIFT 8 /* IN2_VU */ +#define WM8994_IN2_VU_WIDTH 1 /* IN2_VU */ +#define WM8994_IN2L_MUTE 0x0080 /* IN2L_MUTE */ +#define WM8994_IN2L_MUTE_MASK 0x0080 /* IN2L_MUTE */ +#define WM8994_IN2L_MUTE_SHIFT 7 /* IN2L_MUTE */ +#define WM8994_IN2L_MUTE_WIDTH 1 /* IN2L_MUTE */ +#define WM8994_IN2L_ZC 0x0040 /* IN2L_ZC */ +#define WM8994_IN2L_ZC_MASK 0x0040 /* IN2L_ZC */ +#define WM8994_IN2L_ZC_SHIFT 6 /* IN2L_ZC */ +#define WM8994_IN2L_ZC_WIDTH 1 /* IN2L_ZC */ +#define WM8994_IN2L_VOL_MASK 0x001F /* IN2L_VOL - [4:0] */ +#define WM8994_IN2L_VOL_SHIFT 0 /* IN2L_VOL - [4:0] */ +#define WM8994_IN2L_VOL_WIDTH 5 /* IN2L_VOL - [4:0] */ + +/* + * R26 (0x1A) - Right Line Input 1&2 Volume + */ +#define WM8994_IN1_VU 0x0100 /* IN1_VU */ +#define WM8994_IN1_VU_MASK 0x0100 /* IN1_VU */ +#define WM8994_IN1_VU_SHIFT 8 /* IN1_VU */ +#define WM8994_IN1_VU_WIDTH 1 /* IN1_VU */ +#define WM8994_IN1R_MUTE 0x0080 /* IN1R_MUTE */ +#define WM8994_IN1R_MUTE_MASK 0x0080 /* IN1R_MUTE */ +#define WM8994_IN1R_MUTE_SHIFT 7 /* IN1R_MUTE */ +#define WM8994_IN1R_MUTE_WIDTH 1 /* IN1R_MUTE */ +#define WM8994_IN1R_ZC 0x0040 /* IN1R_ZC */ +#define WM8994_IN1R_ZC_MASK 0x0040 /* IN1R_ZC */ +#define WM8994_IN1R_ZC_SHIFT 6 /* IN1R_ZC */ +#define WM8994_IN1R_ZC_WIDTH 1 /* IN1R_ZC */ +#define WM8994_IN1R_VOL_MASK 0x001F /* IN1R_VOL - [4:0] */ +#define WM8994_IN1R_VOL_SHIFT 0 /* IN1R_VOL - [4:0] */ +#define WM8994_IN1R_VOL_WIDTH 5 /* IN1R_VOL - [4:0] */ + +/* + * R27 (0x1B) - Right Line Input 3&4 Volume + */ +#define WM8994_IN2_VU 0x0100 /* IN2_VU */ +#define WM8994_IN2_VU_MASK 0x0100 /* IN2_VU */ +#define WM8994_IN2_VU_SHIFT 8 /* IN2_VU */ +#define WM8994_IN2_VU_WIDTH 1 /* IN2_VU */ +#define WM8994_IN2R_MUTE 0x0080 /* IN2R_MUTE */ +#define WM8994_IN2R_MUTE_MASK 0x0080 /* IN2R_MUTE */ +#define WM8994_IN2R_MUTE_SHIFT 7 /* IN2R_MUTE */ +#define WM8994_IN2R_MUTE_WIDTH 1 /* IN2R_MUTE */ +#define WM8994_IN2R_ZC 0x0040 /* IN2R_ZC */ +#define WM8994_IN2R_ZC_MASK 0x0040 /* IN2R_ZC */ +#define WM8994_IN2R_ZC_SHIFT 6 /* IN2R_ZC */ +#define WM8994_IN2R_ZC_WIDTH 1 /* IN2R_ZC */ +#define WM8994_IN2R_VOL_MASK 0x001F /* IN2R_VOL - [4:0] */ +#define WM8994_IN2R_VOL_SHIFT 0 /* IN2R_VOL - [4:0] */ +#define WM8994_IN2R_VOL_WIDTH 5 /* IN2R_VOL - [4:0] */ + +/* + * R28 (0x1C) - Left Output Volume + */ +#define WM8994_HPOUT1_VU 0x0100 /* HPOUT1_VU */ +#define WM8994_HPOUT1_VU_MASK 0x0100 /* HPOUT1_VU */ +#define WM8994_HPOUT1_VU_SHIFT 8 /* HPOUT1_VU */ +#define WM8994_HPOUT1_VU_WIDTH 1 /* HPOUT1_VU */ +#define WM8994_HPOUT1L_ZC 0x0080 /* HPOUT1L_ZC */ +#define WM8994_HPOUT1L_ZC_MASK 0x0080 /* HPOUT1L_ZC */ +#define WM8994_HPOUT1L_ZC_SHIFT 7 /* HPOUT1L_ZC */ +#define WM8994_HPOUT1L_ZC_WIDTH 1 /* HPOUT1L_ZC */ +#define WM8994_HPOUT1L_MUTE_N 0x0040 /* HPOUT1L_MUTE_N */ +#define WM8994_HPOUT1L_MUTE_N_MASK 0x0040 /* HPOUT1L_MUTE_N */ +#define WM8994_HPOUT1L_MUTE_N_SHIFT 6 /* HPOUT1L_MUTE_N */ +#define WM8994_HPOUT1L_MUTE_N_WIDTH 1 /* HPOUT1L_MUTE_N */ +#define WM8994_HPOUT1L_VOL_MASK 0x003F /* HPOUT1L_VOL - [5:0] */ +#define WM8994_HPOUT1L_VOL_SHIFT 0 /* HPOUT1L_VOL - [5:0] */ +#define WM8994_HPOUT1L_VOL_WIDTH 6 /* HPOUT1L_VOL - [5:0] */ + +/* + * R29 (0x1D) - Right Output Volume + */ +#define WM8994_HPOUT1_VU 0x0100 /* HPOUT1_VU */ +#define WM8994_HPOUT1_VU_MASK 0x0100 /* HPOUT1_VU */ +#define WM8994_HPOUT1_VU_SHIFT 8 /* HPOUT1_VU */ +#define WM8994_HPOUT1_VU_WIDTH 1 /* HPOUT1_VU */ +#define WM8994_HPOUT1R_ZC 0x0080 /* HPOUT1R_ZC */ +#define WM8994_HPOUT1R_ZC_MASK 0x0080 /* HPOUT1R_ZC */ +#define WM8994_HPOUT1R_ZC_SHIFT 7 /* HPOUT1R_ZC */ +#define WM8994_HPOUT1R_ZC_WIDTH 1 /* HPOUT1R_ZC */ +#define WM8994_HPOUT1R_MUTE_N 0x0040 /* HPOUT1R_MUTE_N */ +#define WM8994_HPOUT1R_MUTE_N_MASK 0x0040 /* HPOUT1R_MUTE_N */ +#define WM8994_HPOUT1R_MUTE_N_SHIFT 6 /* HPOUT1R_MUTE_N */ +#define WM8994_HPOUT1R_MUTE_N_WIDTH 1 /* HPOUT1R_MUTE_N */ +#define WM8994_HPOUT1R_VOL_MASK 0x003F /* HPOUT1R_VOL - [5:0] */ +#define WM8994_HPOUT1R_VOL_SHIFT 0 /* HPOUT1R_VOL - [5:0] */ +#define WM8994_HPOUT1R_VOL_WIDTH 6 /* HPOUT1R_VOL - [5:0] */ + +/* + * R30 (0x1E) - Line Outputs Volume + */ +#define WM8994_LINEOUT1N_MUTE 0x0040 /* LINEOUT1N_MUTE */ +#define WM8994_LINEOUT1N_MUTE_MASK 0x0040 /* LINEOUT1N_MUTE */ +#define WM8994_LINEOUT1N_MUTE_SHIFT 6 /* LINEOUT1N_MUTE */ +#define WM8994_LINEOUT1N_MUTE_WIDTH 1 /* LINEOUT1N_MUTE */ +#define WM8994_LINEOUT1P_MUTE 0x0020 /* LINEOUT1P_MUTE */ +#define WM8994_LINEOUT1P_MUTE_MASK 0x0020 /* LINEOUT1P_MUTE */ +#define WM8994_LINEOUT1P_MUTE_SHIFT 5 /* LINEOUT1P_MUTE */ +#define WM8994_LINEOUT1P_MUTE_WIDTH 1 /* LINEOUT1P_MUTE */ +#define WM8994_LINEOUT1_VOL 0x0010 /* LINEOUT1_VOL */ +#define WM8994_LINEOUT1_VOL_MASK 0x0010 /* LINEOUT1_VOL */ +#define WM8994_LINEOUT1_VOL_SHIFT 4 /* LINEOUT1_VOL */ +#define WM8994_LINEOUT1_VOL_WIDTH 1 /* LINEOUT1_VOL */ +#define WM8994_LINEOUT2N_MUTE 0x0004 /* LINEOUT2N_MUTE */ +#define WM8994_LINEOUT2N_MUTE_MASK 0x0004 /* LINEOUT2N_MUTE */ +#define WM8994_LINEOUT2N_MUTE_SHIFT 2 /* LINEOUT2N_MUTE */ +#define WM8994_LINEOUT2N_MUTE_WIDTH 1 /* LINEOUT2N_MUTE */ +#define WM8994_LINEOUT2P_MUTE 0x0002 /* LINEOUT2P_MUTE */ +#define WM8994_LINEOUT2P_MUTE_MASK 0x0002 /* LINEOUT2P_MUTE */ +#define WM8994_LINEOUT2P_MUTE_SHIFT 1 /* LINEOUT2P_MUTE */ +#define WM8994_LINEOUT2P_MUTE_WIDTH 1 /* LINEOUT2P_MUTE */ +#define WM8994_LINEOUT2_VOL 0x0001 /* LINEOUT2_VOL */ +#define WM8994_LINEOUT2_VOL_MASK 0x0001 /* LINEOUT2_VOL */ +#define WM8994_LINEOUT2_VOL_SHIFT 0 /* LINEOUT2_VOL */ +#define WM8994_LINEOUT2_VOL_WIDTH 1 /* LINEOUT2_VOL */ + +/* + * R31 (0x1F) - HPOUT2 Volume + */ +#define WM8994_HPOUT2_MUTE 0x0020 /* HPOUT2_MUTE */ +#define WM8994_HPOUT2_MUTE_MASK 0x0020 /* HPOUT2_MUTE */ +#define WM8994_HPOUT2_MUTE_SHIFT 5 /* HPOUT2_MUTE */ +#define WM8994_HPOUT2_MUTE_WIDTH 1 /* HPOUT2_MUTE */ +#define WM8994_HPOUT2_VOL 0x0010 /* HPOUT2_VOL */ +#define WM8994_HPOUT2_VOL_MASK 0x0010 /* HPOUT2_VOL */ +#define WM8994_HPOUT2_VOL_SHIFT 4 /* HPOUT2_VOL */ +#define WM8994_HPOUT2_VOL_WIDTH 1 /* HPOUT2_VOL */ + +/* + * R32 (0x20) - Left OPGA Volume + */ +#define WM8994_MIXOUT_VU 0x0100 /* MIXOUT_VU */ +#define WM8994_MIXOUT_VU_MASK 0x0100 /* MIXOUT_VU */ +#define WM8994_MIXOUT_VU_SHIFT 8 /* MIXOUT_VU */ +#define WM8994_MIXOUT_VU_WIDTH 1 /* MIXOUT_VU */ +#define WM8994_MIXOUTL_ZC 0x0080 /* MIXOUTL_ZC */ +#define WM8994_MIXOUTL_ZC_MASK 0x0080 /* MIXOUTL_ZC */ +#define WM8994_MIXOUTL_ZC_SHIFT 7 /* MIXOUTL_ZC */ +#define WM8994_MIXOUTL_ZC_WIDTH 1 /* MIXOUTL_ZC */ +#define WM8994_MIXOUTL_MUTE_N 0x0040 /* MIXOUTL_MUTE_N */ +#define WM8994_MIXOUTL_MUTE_N_MASK 0x0040 /* MIXOUTL_MUTE_N */ +#define WM8994_MIXOUTL_MUTE_N_SHIFT 6 /* MIXOUTL_MUTE_N */ +#define WM8994_MIXOUTL_MUTE_N_WIDTH 1 /* MIXOUTL_MUTE_N */ +#define WM8994_MIXOUTL_VOL_MASK 0x003F /* MIXOUTL_VOL - [5:0] */ +#define WM8994_MIXOUTL_VOL_SHIFT 0 /* MIXOUTL_VOL - [5:0] */ +#define WM8994_MIXOUTL_VOL_WIDTH 6 /* MIXOUTL_VOL - [5:0] */ + +/* + * R33 (0x21) - Right OPGA Volume + */ +#define WM8994_MIXOUT_VU 0x0100 /* MIXOUT_VU */ +#define WM8994_MIXOUT_VU_MASK 0x0100 /* MIXOUT_VU */ +#define WM8994_MIXOUT_VU_SHIFT 8 /* MIXOUT_VU */ +#define WM8994_MIXOUT_VU_WIDTH 1 /* MIXOUT_VU */ +#define WM8994_MIXOUTR_ZC 0x0080 /* MIXOUTR_ZC */ +#define WM8994_MIXOUTR_ZC_MASK 0x0080 /* MIXOUTR_ZC */ +#define WM8994_MIXOUTR_ZC_SHIFT 7 /* MIXOUTR_ZC */ +#define WM8994_MIXOUTR_ZC_WIDTH 1 /* MIXOUTR_ZC */ +#define WM8994_MIXOUTR_MUTE_N 0x0040 /* MIXOUTR_MUTE_N */ +#define WM8994_MIXOUTR_MUTE_N_MASK 0x0040 /* MIXOUTR_MUTE_N */ +#define WM8994_MIXOUTR_MUTE_N_SHIFT 6 /* MIXOUTR_MUTE_N */ +#define WM8994_MIXOUTR_MUTE_N_WIDTH 1 /* MIXOUTR_MUTE_N */ +#define WM8994_MIXOUTR_VOL_MASK 0x003F /* MIXOUTR_VOL - [5:0] */ +#define WM8994_MIXOUTR_VOL_SHIFT 0 /* MIXOUTR_VOL - [5:0] */ +#define WM8994_MIXOUTR_VOL_WIDTH 6 /* MIXOUTR_VOL - [5:0] */ + +/* + * R34 (0x22) - SPKMIXL Attenuation + */ +#define WM8994_DAC2L_SPKMIXL_VOL 0x0040 /* DAC2L_SPKMIXL_VOL */ +#define WM8994_DAC2L_SPKMIXL_VOL_MASK 0x0040 /* DAC2L_SPKMIXL_VOL */ +#define WM8994_DAC2L_SPKMIXL_VOL_SHIFT 6 /* DAC2L_SPKMIXL_VOL */ +#define WM8994_DAC2L_SPKMIXL_VOL_WIDTH 1 /* DAC2L_SPKMIXL_VOL */ +#define WM8994_MIXINL_SPKMIXL_VOL 0x0020 /* MIXINL_SPKMIXL_VOL */ +#define WM8994_MIXINL_SPKMIXL_VOL_MASK 0x0020 /* MIXINL_SPKMIXL_VOL */ +#define WM8994_MIXINL_SPKMIXL_VOL_SHIFT 5 /* MIXINL_SPKMIXL_VOL */ +#define WM8994_MIXINL_SPKMIXL_VOL_WIDTH 1 /* MIXINL_SPKMIXL_VOL */ +#define WM8994_IN1LP_SPKMIXL_VOL 0x0010 /* IN1LP_SPKMIXL_VOL */ +#define WM8994_IN1LP_SPKMIXL_VOL_MASK 0x0010 /* IN1LP_SPKMIXL_VOL */ +#define WM8994_IN1LP_SPKMIXL_VOL_SHIFT 4 /* IN1LP_SPKMIXL_VOL */ +#define WM8994_IN1LP_SPKMIXL_VOL_WIDTH 1 /* IN1LP_SPKMIXL_VOL */ +#define WM8994_MIXOUTL_SPKMIXL_VOL 0x0008 /* MIXOUTL_SPKMIXL_VOL */ +#define WM8994_MIXOUTL_SPKMIXL_VOL_MASK 0x0008 /* MIXOUTL_SPKMIXL_VOL */ +#define WM8994_MIXOUTL_SPKMIXL_VOL_SHIFT 3 /* MIXOUTL_SPKMIXL_VOL */ +#define WM8994_MIXOUTL_SPKMIXL_VOL_WIDTH 1 /* MIXOUTL_SPKMIXL_VOL */ +#define WM8994_DAC1L_SPKMIXL_VOL 0x0004 /* DAC1L_SPKMIXL_VOL */ +#define WM8994_DAC1L_SPKMIXL_VOL_MASK 0x0004 /* DAC1L_SPKMIXL_VOL */ +#define WM8994_DAC1L_SPKMIXL_VOL_SHIFT 2 /* DAC1L_SPKMIXL_VOL */ +#define WM8994_DAC1L_SPKMIXL_VOL_WIDTH 1 /* DAC1L_SPKMIXL_VOL */ +#define WM8994_SPKMIXL_VOL_MASK 0x0003 /* SPKMIXL_VOL - [1:0] */ +#define WM8994_SPKMIXL_VOL_SHIFT 0 /* SPKMIXL_VOL - [1:0] */ +#define WM8994_SPKMIXL_VOL_WIDTH 2 /* SPKMIXL_VOL - [1:0] */ + +/* + * R35 (0x23) - SPKMIXR Attenuation + */ +#define WM8994_SPKOUT_CLASSAB 0x0100 /* SPKOUT_CLASSAB */ +#define WM8994_SPKOUT_CLASSAB_MASK 0x0100 /* SPKOUT_CLASSAB */ +#define WM8994_SPKOUT_CLASSAB_SHIFT 8 /* SPKOUT_CLASSAB */ +#define WM8994_SPKOUT_CLASSAB_WIDTH 1 /* SPKOUT_CLASSAB */ +#define WM8994_DAC2R_SPKMIXR_VOL 0x0040 /* DAC2R_SPKMIXR_VOL */ +#define WM8994_DAC2R_SPKMIXR_VOL_MASK 0x0040 /* DAC2R_SPKMIXR_VOL */ +#define WM8994_DAC2R_SPKMIXR_VOL_SHIFT 6 /* DAC2R_SPKMIXR_VOL */ +#define WM8994_DAC2R_SPKMIXR_VOL_WIDTH 1 /* DAC2R_SPKMIXR_VOL */ +#define WM8994_MIXINR_SPKMIXR_VOL 0x0020 /* MIXINR_SPKMIXR_VOL */ +#define WM8994_MIXINR_SPKMIXR_VOL_MASK 0x0020 /* MIXINR_SPKMIXR_VOL */ +#define WM8994_MIXINR_SPKMIXR_VOL_SHIFT 5 /* MIXINR_SPKMIXR_VOL */ +#define WM8994_MIXINR_SPKMIXR_VOL_WIDTH 1 /* MIXINR_SPKMIXR_VOL */ +#define WM8994_IN1RP_SPKMIXR_VOL 0x0010 /* IN1RP_SPKMIXR_VOL */ +#define WM8994_IN1RP_SPKMIXR_VOL_MASK 0x0010 /* IN1RP_SPKMIXR_VOL */ +#define WM8994_IN1RP_SPKMIXR_VOL_SHIFT 4 /* IN1RP_SPKMIXR_VOL */ +#define WM8994_IN1RP_SPKMIXR_VOL_WIDTH 1 /* IN1RP_SPKMIXR_VOL */ +#define WM8994_MIXOUTR_SPKMIXR_VOL 0x0008 /* MIXOUTR_SPKMIXR_VOL */ +#define WM8994_MIXOUTR_SPKMIXR_VOL_MASK 0x0008 /* MIXOUTR_SPKMIXR_VOL */ +#define WM8994_MIXOUTR_SPKMIXR_VOL_SHIFT 3 /* MIXOUTR_SPKMIXR_VOL */ +#define WM8994_MIXOUTR_SPKMIXR_VOL_WIDTH 1 /* MIXOUTR_SPKMIXR_VOL */ +#define WM8994_DAC1R_SPKMIXR_VOL 0x0004 /* DAC1R_SPKMIXR_VOL */ +#define WM8994_DAC1R_SPKMIXR_VOL_MASK 0x0004 /* DAC1R_SPKMIXR_VOL */ +#define WM8994_DAC1R_SPKMIXR_VOL_SHIFT 2 /* DAC1R_SPKMIXR_VOL */ +#define WM8994_DAC1R_SPKMIXR_VOL_WIDTH 1 /* DAC1R_SPKMIXR_VOL */ +#define WM8994_SPKMIXR_VOL_MASK 0x0003 /* SPKMIXR_VOL - [1:0] */ +#define WM8994_SPKMIXR_VOL_SHIFT 0 /* SPKMIXR_VOL - [1:0] */ +#define WM8994_SPKMIXR_VOL_WIDTH 2 /* SPKMIXR_VOL - [1:0] */ + +/* + * R36 (0x24) - SPKOUT Mixers + */ +#define WM8994_IN2LRP_TO_SPKOUTL 0x0020 /* IN2LRP_TO_SPKOUTL */ +#define WM8994_IN2LRP_TO_SPKOUTL_MASK 0x0020 /* IN2LRP_TO_SPKOUTL */ +#define WM8994_IN2LRP_TO_SPKOUTL_SHIFT 5 /* IN2LRP_TO_SPKOUTL */ +#define WM8994_IN2LRP_TO_SPKOUTL_WIDTH 1 /* IN2LRP_TO_SPKOUTL */ +#define WM8994_SPKMIXL_TO_SPKOUTL 0x0010 /* SPKMIXL_TO_SPKOUTL */ +#define WM8994_SPKMIXL_TO_SPKOUTL_MASK 0x0010 /* SPKMIXL_TO_SPKOUTL */ +#define WM8994_SPKMIXL_TO_SPKOUTL_SHIFT 4 /* SPKMIXL_TO_SPKOUTL */ +#define WM8994_SPKMIXL_TO_SPKOUTL_WIDTH 1 /* SPKMIXL_TO_SPKOUTL */ +#define WM8994_SPKMIXR_TO_SPKOUTL 0x0008 /* SPKMIXR_TO_SPKOUTL */ +#define WM8994_SPKMIXR_TO_SPKOUTL_MASK 0x0008 /* SPKMIXR_TO_SPKOUTL */ +#define WM8994_SPKMIXR_TO_SPKOUTL_SHIFT 3 /* SPKMIXR_TO_SPKOUTL */ +#define WM8994_SPKMIXR_TO_SPKOUTL_WIDTH 1 /* SPKMIXR_TO_SPKOUTL */ +#define WM8994_IN2LRP_TO_SPKOUTR 0x0004 /* IN2LRP_TO_SPKOUTR */ +#define WM8994_IN2LRP_TO_SPKOUTR_MASK 0x0004 /* IN2LRP_TO_SPKOUTR */ +#define WM8994_IN2LRP_TO_SPKOUTR_SHIFT 2 /* IN2LRP_TO_SPKOUTR */ +#define WM8994_IN2LRP_TO_SPKOUTR_WIDTH 1 /* IN2LRP_TO_SPKOUTR */ +#define WM8994_SPKMIXL_TO_SPKOUTR 0x0002 /* SPKMIXL_TO_SPKOUTR */ +#define WM8994_SPKMIXL_TO_SPKOUTR_MASK 0x0002 /* SPKMIXL_TO_SPKOUTR */ +#define WM8994_SPKMIXL_TO_SPKOUTR_SHIFT 1 /* SPKMIXL_TO_SPKOUTR */ +#define WM8994_SPKMIXL_TO_SPKOUTR_WIDTH 1 /* SPKMIXL_TO_SPKOUTR */ +#define WM8994_SPKMIXR_TO_SPKOUTR 0x0001 /* SPKMIXR_TO_SPKOUTR */ +#define WM8994_SPKMIXR_TO_SPKOUTR_MASK 0x0001 /* SPKMIXR_TO_SPKOUTR */ +#define WM8994_SPKMIXR_TO_SPKOUTR_SHIFT 0 /* SPKMIXR_TO_SPKOUTR */ +#define WM8994_SPKMIXR_TO_SPKOUTR_WIDTH 1 /* SPKMIXR_TO_SPKOUTR */ + +/* + * R37 (0x25) - ClassD + */ +#define WM8994_SPKOUTL_BOOST_MASK 0x0038 /* SPKOUTL_BOOST - [5:3] */ +#define WM8994_SPKOUTL_BOOST_SHIFT 3 /* SPKOUTL_BOOST - [5:3] */ +#define WM8994_SPKOUTL_BOOST_WIDTH 3 /* SPKOUTL_BOOST - [5:3] */ +#define WM8994_SPKOUTR_BOOST_MASK 0x0007 /* SPKOUTR_BOOST - [2:0] */ +#define WM8994_SPKOUTR_BOOST_SHIFT 0 /* SPKOUTR_BOOST - [2:0] */ +#define WM8994_SPKOUTR_BOOST_WIDTH 3 /* SPKOUTR_BOOST - [2:0] */ + +/* + * R38 (0x26) - Speaker Volume Left + */ +#define WM8994_SPKOUT_VU 0x0100 /* SPKOUT_VU */ +#define WM8994_SPKOUT_VU_MASK 0x0100 /* SPKOUT_VU */ +#define WM8994_SPKOUT_VU_SHIFT 8 /* SPKOUT_VU */ +#define WM8994_SPKOUT_VU_WIDTH 1 /* SPKOUT_VU */ +#define WM8994_SPKOUTL_ZC 0x0080 /* SPKOUTL_ZC */ +#define WM8994_SPKOUTL_ZC_MASK 0x0080 /* SPKOUTL_ZC */ +#define WM8994_SPKOUTL_ZC_SHIFT 7 /* SPKOUTL_ZC */ +#define WM8994_SPKOUTL_ZC_WIDTH 1 /* SPKOUTL_ZC */ +#define WM8994_SPKOUTL_MUTE_N 0x0040 /* SPKOUTL_MUTE_N */ +#define WM8994_SPKOUTL_MUTE_N_MASK 0x0040 /* SPKOUTL_MUTE_N */ +#define WM8994_SPKOUTL_MUTE_N_SHIFT 6 /* SPKOUTL_MUTE_N */ +#define WM8994_SPKOUTL_MUTE_N_WIDTH 1 /* SPKOUTL_MUTE_N */ +#define WM8994_SPKOUTL_VOL_MASK 0x003F /* SPKOUTL_VOL - [5:0] */ +#define WM8994_SPKOUTL_VOL_SHIFT 0 /* SPKOUTL_VOL - [5:0] */ +#define WM8994_SPKOUTL_VOL_WIDTH 6 /* SPKOUTL_VOL - [5:0] */ + +/* + * R39 (0x27) - Speaker Volume Right + */ +#define WM8994_SPKOUT_VU 0x0100 /* SPKOUT_VU */ +#define WM8994_SPKOUT_VU_MASK 0x0100 /* SPKOUT_VU */ +#define WM8994_SPKOUT_VU_SHIFT 8 /* SPKOUT_VU */ +#define WM8994_SPKOUT_VU_WIDTH 1 /* SPKOUT_VU */ +#define WM8994_SPKOUTR_ZC 0x0080 /* SPKOUTR_ZC */ +#define WM8994_SPKOUTR_ZC_MASK 0x0080 /* SPKOUTR_ZC */ +#define WM8994_SPKOUTR_ZC_SHIFT 7 /* SPKOUTR_ZC */ +#define WM8994_SPKOUTR_ZC_WIDTH 1 /* SPKOUTR_ZC */ +#define WM8994_SPKOUTR_MUTE_N 0x0040 /* SPKOUTR_MUTE_N */ +#define WM8994_SPKOUTR_MUTE_N_MASK 0x0040 /* SPKOUTR_MUTE_N */ +#define WM8994_SPKOUTR_MUTE_N_SHIFT 6 /* SPKOUTR_MUTE_N */ +#define WM8994_SPKOUTR_MUTE_N_WIDTH 1 /* SPKOUTR_MUTE_N */ +#define WM8994_SPKOUTR_VOL_MASK 0x003F /* SPKOUTR_VOL - [5:0] */ +#define WM8994_SPKOUTR_VOL_SHIFT 0 /* SPKOUTR_VOL - [5:0] */ +#define WM8994_SPKOUTR_VOL_WIDTH 6 /* SPKOUTR_VOL - [5:0] */ + +/* + * R40 (0x28) - Input Mixer (2) + */ +#define WM8994_IN2LP_TO_IN2L 0x0080 /* IN2LP_TO_IN2L */ +#define WM8994_IN2LP_TO_IN2L_MASK 0x0080 /* IN2LP_TO_IN2L */ +#define WM8994_IN2LP_TO_IN2L_SHIFT 7 /* IN2LP_TO_IN2L */ +#define WM8994_IN2LP_TO_IN2L_WIDTH 1 /* IN2LP_TO_IN2L */ +#define WM8994_IN2LN_TO_IN2L 0x0040 /* IN2LN_TO_IN2L */ +#define WM8994_IN2LN_TO_IN2L_MASK 0x0040 /* IN2LN_TO_IN2L */ +#define WM8994_IN2LN_TO_IN2L_SHIFT 6 /* IN2LN_TO_IN2L */ +#define WM8994_IN2LN_TO_IN2L_WIDTH 1 /* IN2LN_TO_IN2L */ +#define WM8994_IN1LP_TO_IN1L 0x0020 /* IN1LP_TO_IN1L */ +#define WM8994_IN1LP_TO_IN1L_MASK 0x0020 /* IN1LP_TO_IN1L */ +#define WM8994_IN1LP_TO_IN1L_SHIFT 5 /* IN1LP_TO_IN1L */ +#define WM8994_IN1LP_TO_IN1L_WIDTH 1 /* IN1LP_TO_IN1L */ +#define WM8994_IN1LN_TO_IN1L 0x0010 /* IN1LN_TO_IN1L */ +#define WM8994_IN1LN_TO_IN1L_MASK 0x0010 /* IN1LN_TO_IN1L */ +#define WM8994_IN1LN_TO_IN1L_SHIFT 4 /* IN1LN_TO_IN1L */ +#define WM8994_IN1LN_TO_IN1L_WIDTH 1 /* IN1LN_TO_IN1L */ +#define WM8994_IN2RP_TO_IN2R 0x0008 /* IN2RP_TO_IN2R */ +#define WM8994_IN2RP_TO_IN2R_MASK 0x0008 /* IN2RP_TO_IN2R */ +#define WM8994_IN2RP_TO_IN2R_SHIFT 3 /* IN2RP_TO_IN2R */ +#define WM8994_IN2RP_TO_IN2R_WIDTH 1 /* IN2RP_TO_IN2R */ +#define WM8994_IN2RN_TO_IN2R 0x0004 /* IN2RN_TO_IN2R */ +#define WM8994_IN2RN_TO_IN2R_MASK 0x0004 /* IN2RN_TO_IN2R */ +#define WM8994_IN2RN_TO_IN2R_SHIFT 2 /* IN2RN_TO_IN2R */ +#define WM8994_IN2RN_TO_IN2R_WIDTH 1 /* IN2RN_TO_IN2R */ +#define WM8994_IN1RP_TO_IN1R 0x0002 /* IN1RP_TO_IN1R */ +#define WM8994_IN1RP_TO_IN1R_MASK 0x0002 /* IN1RP_TO_IN1R */ +#define WM8994_IN1RP_TO_IN1R_SHIFT 1 /* IN1RP_TO_IN1R */ +#define WM8994_IN1RP_TO_IN1R_WIDTH 1 /* IN1RP_TO_IN1R */ +#define WM8994_IN1RN_TO_IN1R 0x0001 /* IN1RN_TO_IN1R */ +#define WM8994_IN1RN_TO_IN1R_MASK 0x0001 /* IN1RN_TO_IN1R */ +#define WM8994_IN1RN_TO_IN1R_SHIFT 0 /* IN1RN_TO_IN1R */ +#define WM8994_IN1RN_TO_IN1R_WIDTH 1 /* IN1RN_TO_IN1R */ + +/* + * R41 (0x29) - Input Mixer (3) + */ +#define WM8994_IN2L_TO_MIXINL 0x0100 /* IN2L_TO_MIXINL */ +#define WM8994_IN2L_TO_MIXINL_MASK 0x0100 /* IN2L_TO_MIXINL */ +#define WM8994_IN2L_TO_MIXINL_SHIFT 8 /* IN2L_TO_MIXINL */ +#define WM8994_IN2L_TO_MIXINL_WIDTH 1 /* IN2L_TO_MIXINL */ +#define WM8994_IN2L_MIXINL_VOL 0x0080 /* IN2L_MIXINL_VOL */ +#define WM8994_IN2L_MIXINL_VOL_MASK 0x0080 /* IN2L_MIXINL_VOL */ +#define WM8994_IN2L_MIXINL_VOL_SHIFT 7 /* IN2L_MIXINL_VOL */ +#define WM8994_IN2L_MIXINL_VOL_WIDTH 1 /* IN2L_MIXINL_VOL */ +#define WM8994_IN1L_TO_MIXINL 0x0020 /* IN1L_TO_MIXINL */ +#define WM8994_IN1L_TO_MIXINL_MASK 0x0020 /* IN1L_TO_MIXINL */ +#define WM8994_IN1L_TO_MIXINL_SHIFT 5 /* IN1L_TO_MIXINL */ +#define WM8994_IN1L_TO_MIXINL_WIDTH 1 /* IN1L_TO_MIXINL */ +#define WM8994_IN1L_MIXINL_VOL 0x0010 /* IN1L_MIXINL_VOL */ +#define WM8994_IN1L_MIXINL_VOL_MASK 0x0010 /* IN1L_MIXINL_VOL */ +#define WM8994_IN1L_MIXINL_VOL_SHIFT 4 /* IN1L_MIXINL_VOL */ +#define WM8994_IN1L_MIXINL_VOL_WIDTH 1 /* IN1L_MIXINL_VOL */ +#define WM8994_MIXOUTL_MIXINL_VOL_MASK 0x0007 /* MIXOUTL_MIXINL_VOL - [2:0] */ +#define WM8994_MIXOUTL_MIXINL_VOL_SHIFT 0 /* MIXOUTL_MIXINL_VOL - [2:0] */ +#define WM8994_MIXOUTL_MIXINL_VOL_WIDTH 3 /* MIXOUTL_MIXINL_VOL - [2:0] */ + +/* + * R42 (0x2A) - Input Mixer (4) + */ +#define WM8994_IN2R_TO_MIXINR 0x0100 /* IN2R_TO_MIXINR */ +#define WM8994_IN2R_TO_MIXINR_MASK 0x0100 /* IN2R_TO_MIXINR */ +#define WM8994_IN2R_TO_MIXINR_SHIFT 8 /* IN2R_TO_MIXINR */ +#define WM8994_IN2R_TO_MIXINR_WIDTH 1 /* IN2R_TO_MIXINR */ +#define WM8994_IN2R_MIXINR_VOL 0x0080 /* IN2R_MIXINR_VOL */ +#define WM8994_IN2R_MIXINR_VOL_MASK 0x0080 /* IN2R_MIXINR_VOL */ +#define WM8994_IN2R_MIXINR_VOL_SHIFT 7 /* IN2R_MIXINR_VOL */ +#define WM8994_IN2R_MIXINR_VOL_WIDTH 1 /* IN2R_MIXINR_VOL */ +#define WM8994_IN1R_TO_MIXINR 0x0020 /* IN1R_TO_MIXINR */ +#define WM8994_IN1R_TO_MIXINR_MASK 0x0020 /* IN1R_TO_MIXINR */ +#define WM8994_IN1R_TO_MIXINR_SHIFT 5 /* IN1R_TO_MIXINR */ +#define WM8994_IN1R_TO_MIXINR_WIDTH 1 /* IN1R_TO_MIXINR */ +#define WM8994_IN1R_MIXINR_VOL 0x0010 /* IN1R_MIXINR_VOL */ +#define WM8994_IN1R_MIXINR_VOL_MASK 0x0010 /* IN1R_MIXINR_VOL */ +#define WM8994_IN1R_MIXINR_VOL_SHIFT 4 /* IN1R_MIXINR_VOL */ +#define WM8994_IN1R_MIXINR_VOL_WIDTH 1 /* IN1R_MIXINR_VOL */ +#define WM8994_MIXOUTR_MIXINR_VOL_MASK 0x0007 /* MIXOUTR_MIXINR_VOL - [2:0] */ +#define WM8994_MIXOUTR_MIXINR_VOL_SHIFT 0 /* MIXOUTR_MIXINR_VOL - [2:0] */ +#define WM8994_MIXOUTR_MIXINR_VOL_WIDTH 3 /* MIXOUTR_MIXINR_VOL - [2:0] */ + +/* + * R43 (0x2B) - Input Mixer (5) + */ +#define WM8994_IN1LP_MIXINL_VOL_MASK 0x01C0 /* IN1LP_MIXINL_VOL - [8:6] */ +#define WM8994_IN1LP_MIXINL_VOL_SHIFT 6 /* IN1LP_MIXINL_VOL - [8:6] */ +#define WM8994_IN1LP_MIXINL_VOL_WIDTH 3 /* IN1LP_MIXINL_VOL - [8:6] */ +#define WM8994_IN2LRP_MIXINL_VOL_MASK 0x0007 /* IN2LRP_MIXINL_VOL - [2:0] */ +#define WM8994_IN2LRP_MIXINL_VOL_SHIFT 0 /* IN2LRP_MIXINL_VOL - [2:0] */ +#define WM8994_IN2LRP_MIXINL_VOL_WIDTH 3 /* IN2LRP_MIXINL_VOL - [2:0] */ + +/* + * R44 (0x2C) - Input Mixer (6) + */ +#define WM8994_IN1RP_MIXINR_VOL_MASK 0x01C0 /* IN1RP_MIXINR_VOL - [8:6] */ +#define WM8994_IN1RP_MIXINR_VOL_SHIFT 6 /* IN1RP_MIXINR_VOL - [8:6] */ +#define WM8994_IN1RP_MIXINR_VOL_WIDTH 3 /* IN1RP_MIXINR_VOL - [8:6] */ +#define WM8994_IN2LRP_MIXINR_VOL_MASK 0x0007 /* IN2LRP_MIXINR_VOL - [2:0] */ +#define WM8994_IN2LRP_MIXINR_VOL_SHIFT 0 /* IN2LRP_MIXINR_VOL - [2:0] */ +#define WM8994_IN2LRP_MIXINR_VOL_WIDTH 3 /* IN2LRP_MIXINR_VOL - [2:0] */ + +/* + * R45 (0x2D) - Output Mixer (1) + */ +#define WM8994_DAC1L_TO_HPOUT1L 0x0100 /* DAC1L_TO_HPOUT1L */ +#define WM8994_DAC1L_TO_HPOUT1L_MASK 0x0100 /* DAC1L_TO_HPOUT1L */ +#define WM8994_DAC1L_TO_HPOUT1L_SHIFT 8 /* DAC1L_TO_HPOUT1L */ +#define WM8994_DAC1L_TO_HPOUT1L_WIDTH 1 /* DAC1L_TO_HPOUT1L */ +#define WM8994_MIXINR_TO_MIXOUTL 0x0080 /* MIXINR_TO_MIXOUTL */ +#define WM8994_MIXINR_TO_MIXOUTL_MASK 0x0080 /* MIXINR_TO_MIXOUTL */ +#define WM8994_MIXINR_TO_MIXOUTL_SHIFT 7 /* MIXINR_TO_MIXOUTL */ +#define WM8994_MIXINR_TO_MIXOUTL_WIDTH 1 /* MIXINR_TO_MIXOUTL */ +#define WM8994_MIXINL_TO_MIXOUTL 0x0040 /* MIXINL_TO_MIXOUTL */ +#define WM8994_MIXINL_TO_MIXOUTL_MASK 0x0040 /* MIXINL_TO_MIXOUTL */ +#define WM8994_MIXINL_TO_MIXOUTL_SHIFT 6 /* MIXINL_TO_MIXOUTL */ +#define WM8994_MIXINL_TO_MIXOUTL_WIDTH 1 /* MIXINL_TO_MIXOUTL */ +#define WM8994_IN2RN_TO_MIXOUTL 0x0020 /* IN2RN_TO_MIXOUTL */ +#define WM8994_IN2RN_TO_MIXOUTL_MASK 0x0020 /* IN2RN_TO_MIXOUTL */ +#define WM8994_IN2RN_TO_MIXOUTL_SHIFT 5 /* IN2RN_TO_MIXOUTL */ +#define WM8994_IN2RN_TO_MIXOUTL_WIDTH 1 /* IN2RN_TO_MIXOUTL */ +#define WM8994_IN2LN_TO_MIXOUTL 0x0010 /* IN2LN_TO_MIXOUTL */ +#define WM8994_IN2LN_TO_MIXOUTL_MASK 0x0010 /* IN2LN_TO_MIXOUTL */ +#define WM8994_IN2LN_TO_MIXOUTL_SHIFT 4 /* IN2LN_TO_MIXOUTL */ +#define WM8994_IN2LN_TO_MIXOUTL_WIDTH 1 /* IN2LN_TO_MIXOUTL */ +#define WM8994_IN1R_TO_MIXOUTL 0x0008 /* IN1R_TO_MIXOUTL */ +#define WM8994_IN1R_TO_MIXOUTL_MASK 0x0008 /* IN1R_TO_MIXOUTL */ +#define WM8994_IN1R_TO_MIXOUTL_SHIFT 3 /* IN1R_TO_MIXOUTL */ +#define WM8994_IN1R_TO_MIXOUTL_WIDTH 1 /* IN1R_TO_MIXOUTL */ +#define WM8994_IN1L_TO_MIXOUTL 0x0004 /* IN1L_TO_MIXOUTL */ +#define WM8994_IN1L_TO_MIXOUTL_MASK 0x0004 /* IN1L_TO_MIXOUTL */ +#define WM8994_IN1L_TO_MIXOUTL_SHIFT 2 /* IN1L_TO_MIXOUTL */ +#define WM8994_IN1L_TO_MIXOUTL_WIDTH 1 /* IN1L_TO_MIXOUTL */ +#define WM8994_IN2LP_TO_MIXOUTL 0x0002 /* IN2LP_TO_MIXOUTL */ +#define WM8994_IN2LP_TO_MIXOUTL_MASK 0x0002 /* IN2LP_TO_MIXOUTL */ +#define WM8994_IN2LP_TO_MIXOUTL_SHIFT 1 /* IN2LP_TO_MIXOUTL */ +#define WM8994_IN2LP_TO_MIXOUTL_WIDTH 1 /* IN2LP_TO_MIXOUTL */ +#define WM8994_DAC1L_TO_MIXOUTL 0x0001 /* DAC1L_TO_MIXOUTL */ +#define WM8994_DAC1L_TO_MIXOUTL_MASK 0x0001 /* DAC1L_TO_MIXOUTL */ +#define WM8994_DAC1L_TO_MIXOUTL_SHIFT 0 /* DAC1L_TO_MIXOUTL */ +#define WM8994_DAC1L_TO_MIXOUTL_WIDTH 1 /* DAC1L_TO_MIXOUTL */ + +/* + * R46 (0x2E) - Output Mixer (2) + */ +#define WM8994_DAC1R_TO_HPOUT1R 0x0100 /* DAC1R_TO_HPOUT1R */ +#define WM8994_DAC1R_TO_HPOUT1R_MASK 0x0100 /* DAC1R_TO_HPOUT1R */ +#define WM8994_DAC1R_TO_HPOUT1R_SHIFT 8 /* DAC1R_TO_HPOUT1R */ +#define WM8994_DAC1R_TO_HPOUT1R_WIDTH 1 /* DAC1R_TO_HPOUT1R */ +#define WM8994_MIXINL_TO_MIXOUTR 0x0080 /* MIXINL_TO_MIXOUTR */ +#define WM8994_MIXINL_TO_MIXOUTR_MASK 0x0080 /* MIXINL_TO_MIXOUTR */ +#define WM8994_MIXINL_TO_MIXOUTR_SHIFT 7 /* MIXINL_TO_MIXOUTR */ +#define WM8994_MIXINL_TO_MIXOUTR_WIDTH 1 /* MIXINL_TO_MIXOUTR */ +#define WM8994_MIXINR_TO_MIXOUTR 0x0040 /* MIXINR_TO_MIXOUTR */ +#define WM8994_MIXINR_TO_MIXOUTR_MASK 0x0040 /* MIXINR_TO_MIXOUTR */ +#define WM8994_MIXINR_TO_MIXOUTR_SHIFT 6 /* MIXINR_TO_MIXOUTR */ +#define WM8994_MIXINR_TO_MIXOUTR_WIDTH 1 /* MIXINR_TO_MIXOUTR */ +#define WM8994_IN2LN_TO_MIXOUTR 0x0020 /* IN2LN_TO_MIXOUTR */ +#define WM8994_IN2LN_TO_MIXOUTR_MASK 0x0020 /* IN2LN_TO_MIXOUTR */ +#define WM8994_IN2LN_TO_MIXOUTR_SHIFT 5 /* IN2LN_TO_MIXOUTR */ +#define WM8994_IN2LN_TO_MIXOUTR_WIDTH 1 /* IN2LN_TO_MIXOUTR */ +#define WM8994_IN2RN_TO_MIXOUTR 0x0010 /* IN2RN_TO_MIXOUTR */ +#define WM8994_IN2RN_TO_MIXOUTR_MASK 0x0010 /* IN2RN_TO_MIXOUTR */ +#define WM8994_IN2RN_TO_MIXOUTR_SHIFT 4 /* IN2RN_TO_MIXOUTR */ +#define WM8994_IN2RN_TO_MIXOUTR_WIDTH 1 /* IN2RN_TO_MIXOUTR */ +#define WM8994_IN1L_TO_MIXOUTR 0x0008 /* IN1L_TO_MIXOUTR */ +#define WM8994_IN1L_TO_MIXOUTR_MASK 0x0008 /* IN1L_TO_MIXOUTR */ +#define WM8994_IN1L_TO_MIXOUTR_SHIFT 3 /* IN1L_TO_MIXOUTR */ +#define WM8994_IN1L_TO_MIXOUTR_WIDTH 1 /* IN1L_TO_MIXOUTR */ +#define WM8994_IN1R_TO_MIXOUTR 0x0004 /* IN1R_TO_MIXOUTR */ +#define WM8994_IN1R_TO_MIXOUTR_MASK 0x0004 /* IN1R_TO_MIXOUTR */ +#define WM8994_IN1R_TO_MIXOUTR_SHIFT 2 /* IN1R_TO_MIXOUTR */ +#define WM8994_IN1R_TO_MIXOUTR_WIDTH 1 /* IN1R_TO_MIXOUTR */ +#define WM8994_IN2RP_TO_MIXOUTR 0x0002 /* IN2RP_TO_MIXOUTR */ +#define WM8994_IN2RP_TO_MIXOUTR_MASK 0x0002 /* IN2RP_TO_MIXOUTR */ +#define WM8994_IN2RP_TO_MIXOUTR_SHIFT 1 /* IN2RP_TO_MIXOUTR */ +#define WM8994_IN2RP_TO_MIXOUTR_WIDTH 1 /* IN2RP_TO_MIXOUTR */ +#define WM8994_DAC1R_TO_MIXOUTR 0x0001 /* DAC1R_TO_MIXOUTR */ +#define WM8994_DAC1R_TO_MIXOUTR_MASK 0x0001 /* DAC1R_TO_MIXOUTR */ +#define WM8994_DAC1R_TO_MIXOUTR_SHIFT 0 /* DAC1R_TO_MIXOUTR */ +#define WM8994_DAC1R_TO_MIXOUTR_WIDTH 1 /* DAC1R_TO_MIXOUTR */ + +/* + * R47 (0x2F) - Output Mixer (3) + */ +#define WM8994_IN2LP_MIXOUTL_VOL_MASK 0x0E00 /* IN2LP_MIXOUTL_VOL - [11:9] */ +#define WM8994_IN2LP_MIXOUTL_VOL_SHIFT 9 /* IN2LP_MIXOUTL_VOL - [11:9] */ +#define WM8994_IN2LP_MIXOUTL_VOL_WIDTH 3 /* IN2LP_MIXOUTL_VOL - [11:9] */ +#define WM8994_IN2LN_MIXOUTL_VOL_MASK 0x01C0 /* IN2LN_MIXOUTL_VOL - [8:6] */ +#define WM8994_IN2LN_MIXOUTL_VOL_SHIFT 6 /* IN2LN_MIXOUTL_VOL - [8:6] */ +#define WM8994_IN2LN_MIXOUTL_VOL_WIDTH 3 /* IN2LN_MIXOUTL_VOL - [8:6] */ +#define WM8994_IN1R_MIXOUTL_VOL_MASK 0x0038 /* IN1R_MIXOUTL_VOL - [5:3] */ +#define WM8994_IN1R_MIXOUTL_VOL_SHIFT 3 /* IN1R_MIXOUTL_VOL - [5:3] */ +#define WM8994_IN1R_MIXOUTL_VOL_WIDTH 3 /* IN1R_MIXOUTL_VOL - [5:3] */ +#define WM8994_IN1L_MIXOUTL_VOL_MASK 0x0007 /* IN1L_MIXOUTL_VOL - [2:0] */ +#define WM8994_IN1L_MIXOUTL_VOL_SHIFT 0 /* IN1L_MIXOUTL_VOL - [2:0] */ +#define WM8994_IN1L_MIXOUTL_VOL_WIDTH 3 /* IN1L_MIXOUTL_VOL - [2:0] */ + +/* + * R48 (0x30) - Output Mixer (4) + */ +#define WM8994_IN2RP_MIXOUTR_VOL_MASK 0x0E00 /* IN2RP_MIXOUTR_VOL - [11:9] */ +#define WM8994_IN2RP_MIXOUTR_VOL_SHIFT 9 /* IN2RP_MIXOUTR_VOL - [11:9] */ +#define WM8994_IN2RP_MIXOUTR_VOL_WIDTH 3 /* IN2RP_MIXOUTR_VOL - [11:9] */ +#define WM8994_IN2RN_MIXOUTR_VOL_MASK 0x01C0 /* IN2RN_MIXOUTR_VOL - [8:6] */ +#define WM8994_IN2RN_MIXOUTR_VOL_SHIFT 6 /* IN2RN_MIXOUTR_VOL - [8:6] */ +#define WM8994_IN2RN_MIXOUTR_VOL_WIDTH 3 /* IN2RN_MIXOUTR_VOL - [8:6] */ +#define WM8994_IN1L_MIXOUTR_VOL_MASK 0x0038 /* IN1L_MIXOUTR_VOL - [5:3] */ +#define WM8994_IN1L_MIXOUTR_VOL_SHIFT 3 /* IN1L_MIXOUTR_VOL - [5:3] */ +#define WM8994_IN1L_MIXOUTR_VOL_WIDTH 3 /* IN1L_MIXOUTR_VOL - [5:3] */ +#define WM8994_IN1R_MIXOUTR_VOL_MASK 0x0007 /* IN1R_MIXOUTR_VOL - [2:0] */ +#define WM8994_IN1R_MIXOUTR_VOL_SHIFT 0 /* IN1R_MIXOUTR_VOL - [2:0] */ +#define WM8994_IN1R_MIXOUTR_VOL_WIDTH 3 /* IN1R_MIXOUTR_VOL - [2:0] */ + +/* + * R49 (0x31) - Output Mixer (5) + */ +#define WM8994_DAC1L_MIXOUTL_VOL_MASK 0x0E00 /* DAC1L_MIXOUTL_VOL - [11:9] */ +#define WM8994_DAC1L_MIXOUTL_VOL_SHIFT 9 /* DAC1L_MIXOUTL_VOL - [11:9] */ +#define WM8994_DAC1L_MIXOUTL_VOL_WIDTH 3 /* DAC1L_MIXOUTL_VOL - [11:9] */ +#define WM8994_IN2RN_MIXOUTL_VOL_MASK 0x01C0 /* IN2RN_MIXOUTL_VOL - [8:6] */ +#define WM8994_IN2RN_MIXOUTL_VOL_SHIFT 6 /* IN2RN_MIXOUTL_VOL - [8:6] */ +#define WM8994_IN2RN_MIXOUTL_VOL_WIDTH 3 /* IN2RN_MIXOUTL_VOL - [8:6] */ +#define WM8994_MIXINR_MIXOUTL_VOL_MASK 0x0038 /* MIXINR_MIXOUTL_VOL - [5:3] */ +#define WM8994_MIXINR_MIXOUTL_VOL_SHIFT 3 /* MIXINR_MIXOUTL_VOL - [5:3] */ +#define WM8994_MIXINR_MIXOUTL_VOL_WIDTH 3 /* MIXINR_MIXOUTL_VOL - [5:3] */ +#define WM8994_MIXINL_MIXOUTL_VOL_MASK 0x0007 /* MIXINL_MIXOUTL_VOL - [2:0] */ +#define WM8994_MIXINL_MIXOUTL_VOL_SHIFT 0 /* MIXINL_MIXOUTL_VOL - [2:0] */ +#define WM8994_MIXINL_MIXOUTL_VOL_WIDTH 3 /* MIXINL_MIXOUTL_VOL - [2:0] */ + +/* + * R50 (0x32) - Output Mixer (6) + */ +#define WM8994_DAC1R_MIXOUTR_VOL_MASK 0x0E00 /* DAC1R_MIXOUTR_VOL - [11:9] */ +#define WM8994_DAC1R_MIXOUTR_VOL_SHIFT 9 /* DAC1R_MIXOUTR_VOL - [11:9] */ +#define WM8994_DAC1R_MIXOUTR_VOL_WIDTH 3 /* DAC1R_MIXOUTR_VOL - [11:9] */ +#define WM8994_IN2LN_MIXOUTR_VOL_MASK 0x01C0 /* IN2LN_MIXOUTR_VOL - [8:6] */ +#define WM8994_IN2LN_MIXOUTR_VOL_SHIFT 6 /* IN2LN_MIXOUTR_VOL - [8:6] */ +#define WM8994_IN2LN_MIXOUTR_VOL_WIDTH 3 /* IN2LN_MIXOUTR_VOL - [8:6] */ +#define WM8994_MIXINL_MIXOUTR_VOL_MASK 0x0038 /* MIXINL_MIXOUTR_VOL - [5:3] */ +#define WM8994_MIXINL_MIXOUTR_VOL_SHIFT 3 /* MIXINL_MIXOUTR_VOL - [5:3] */ +#define WM8994_MIXINL_MIXOUTR_VOL_WIDTH 3 /* MIXINL_MIXOUTR_VOL - [5:3] */ +#define WM8994_MIXINR_MIXOUTR_VOL_MASK 0x0007 /* MIXINR_MIXOUTR_VOL - [2:0] */ +#define WM8994_MIXINR_MIXOUTR_VOL_SHIFT 0 /* MIXINR_MIXOUTR_VOL - [2:0] */ +#define WM8994_MIXINR_MIXOUTR_VOL_WIDTH 3 /* MIXINR_MIXOUTR_VOL - [2:0] */ + +/* + * R51 (0x33) - HPOUT2 Mixer + */ +#define WM8994_IN2LRP_TO_HPOUT2 0x0020 /* IN2LRP_TO_HPOUT2 */ +#define WM8994_IN2LRP_TO_HPOUT2_MASK 0x0020 /* IN2LRP_TO_HPOUT2 */ +#define WM8994_IN2LRP_TO_HPOUT2_SHIFT 5 /* IN2LRP_TO_HPOUT2 */ +#define WM8994_IN2LRP_TO_HPOUT2_WIDTH 1 /* IN2LRP_TO_HPOUT2 */ +#define WM8994_MIXOUTLVOL_TO_HPOUT2 0x0010 /* MIXOUTLVOL_TO_HPOUT2 */ +#define WM8994_MIXOUTLVOL_TO_HPOUT2_MASK 0x0010 /* MIXOUTLVOL_TO_HPOUT2 */ +#define WM8994_MIXOUTLVOL_TO_HPOUT2_SHIFT 4 /* MIXOUTLVOL_TO_HPOUT2 */ +#define WM8994_MIXOUTLVOL_TO_HPOUT2_WIDTH 1 /* MIXOUTLVOL_TO_HPOUT2 */ +#define WM8994_MIXOUTRVOL_TO_HPOUT2 0x0008 /* MIXOUTRVOL_TO_HPOUT2 */ +#define WM8994_MIXOUTRVOL_TO_HPOUT2_MASK 0x0008 /* MIXOUTRVOL_TO_HPOUT2 */ +#define WM8994_MIXOUTRVOL_TO_HPOUT2_SHIFT 3 /* MIXOUTRVOL_TO_HPOUT2 */ +#define WM8994_MIXOUTRVOL_TO_HPOUT2_WIDTH 1 /* MIXOUTRVOL_TO_HPOUT2 */ + +/* + * R52 (0x34) - Line Mixer (1) + */ +#define WM8994_MIXOUTL_TO_LINEOUT1N 0x0040 /* MIXOUTL_TO_LINEOUT1N */ +#define WM8994_MIXOUTL_TO_LINEOUT1N_MASK 0x0040 /* MIXOUTL_TO_LINEOUT1N */ +#define WM8994_MIXOUTL_TO_LINEOUT1N_SHIFT 6 /* MIXOUTL_TO_LINEOUT1N */ +#define WM8994_MIXOUTL_TO_LINEOUT1N_WIDTH 1 /* MIXOUTL_TO_LINEOUT1N */ +#define WM8994_MIXOUTR_TO_LINEOUT1N 0x0020 /* MIXOUTR_TO_LINEOUT1N */ +#define WM8994_MIXOUTR_TO_LINEOUT1N_MASK 0x0020 /* MIXOUTR_TO_LINEOUT1N */ +#define WM8994_MIXOUTR_TO_LINEOUT1N_SHIFT 5 /* MIXOUTR_TO_LINEOUT1N */ +#define WM8994_MIXOUTR_TO_LINEOUT1N_WIDTH 1 /* MIXOUTR_TO_LINEOUT1N */ +#define WM8994_LINEOUT1_MODE 0x0010 /* LINEOUT1_MODE */ +#define WM8994_LINEOUT1_MODE_MASK 0x0010 /* LINEOUT1_MODE */ +#define WM8994_LINEOUT1_MODE_SHIFT 4 /* LINEOUT1_MODE */ +#define WM8994_LINEOUT1_MODE_WIDTH 1 /* LINEOUT1_MODE */ +#define WM8994_IN1R_TO_LINEOUT1P 0x0004 /* IN1R_TO_LINEOUT1P */ +#define WM8994_IN1R_TO_LINEOUT1P_MASK 0x0004 /* IN1R_TO_LINEOUT1P */ +#define WM8994_IN1R_TO_LINEOUT1P_SHIFT 2 /* IN1R_TO_LINEOUT1P */ +#define WM8994_IN1R_TO_LINEOUT1P_WIDTH 1 /* IN1R_TO_LINEOUT1P */ +#define WM8994_IN1L_TO_LINEOUT1P 0x0002 /* IN1L_TO_LINEOUT1P */ +#define WM8994_IN1L_TO_LINEOUT1P_MASK 0x0002 /* IN1L_TO_LINEOUT1P */ +#define WM8994_IN1L_TO_LINEOUT1P_SHIFT 1 /* IN1L_TO_LINEOUT1P */ +#define WM8994_IN1L_TO_LINEOUT1P_WIDTH 1 /* IN1L_TO_LINEOUT1P */ +#define WM8994_MIXOUTL_TO_LINEOUT1P 0x0001 /* MIXOUTL_TO_LINEOUT1P */ +#define WM8994_MIXOUTL_TO_LINEOUT1P_MASK 0x0001 /* MIXOUTL_TO_LINEOUT1P */ +#define WM8994_MIXOUTL_TO_LINEOUT1P_SHIFT 0 /* MIXOUTL_TO_LINEOUT1P */ +#define WM8994_MIXOUTL_TO_LINEOUT1P_WIDTH 1 /* MIXOUTL_TO_LINEOUT1P */ + +/* + * R53 (0x35) - Line Mixer (2) + */ +#define WM8994_MIXOUTR_TO_LINEOUT2N 0x0040 /* MIXOUTR_TO_LINEOUT2N */ +#define WM8994_MIXOUTR_TO_LINEOUT2N_MASK 0x0040 /* MIXOUTR_TO_LINEOUT2N */ +#define WM8994_MIXOUTR_TO_LINEOUT2N_SHIFT 6 /* MIXOUTR_TO_LINEOUT2N */ +#define WM8994_MIXOUTR_TO_LINEOUT2N_WIDTH 1 /* MIXOUTR_TO_LINEOUT2N */ +#define WM8994_MIXOUTL_TO_LINEOUT2N 0x0020 /* MIXOUTL_TO_LINEOUT2N */ +#define WM8994_MIXOUTL_TO_LINEOUT2N_MASK 0x0020 /* MIXOUTL_TO_LINEOUT2N */ +#define WM8994_MIXOUTL_TO_LINEOUT2N_SHIFT 5 /* MIXOUTL_TO_LINEOUT2N */ +#define WM8994_MIXOUTL_TO_LINEOUT2N_WIDTH 1 /* MIXOUTL_TO_LINEOUT2N */ +#define WM8994_LINEOUT2_MODE 0x0010 /* LINEOUT2_MODE */ +#define WM8994_LINEOUT2_MODE_MASK 0x0010 /* LINEOUT2_MODE */ +#define WM8994_LINEOUT2_MODE_SHIFT 4 /* LINEOUT2_MODE */ +#define WM8994_LINEOUT2_MODE_WIDTH 1 /* LINEOUT2_MODE */ +#define WM8994_IN1L_TO_LINEOUT2P 0x0004 /* IN1L_TO_LINEOUT2P */ +#define WM8994_IN1L_TO_LINEOUT2P_MASK 0x0004 /* IN1L_TO_LINEOUT2P */ +#define WM8994_IN1L_TO_LINEOUT2P_SHIFT 2 /* IN1L_TO_LINEOUT2P */ +#define WM8994_IN1L_TO_LINEOUT2P_WIDTH 1 /* IN1L_TO_LINEOUT2P */ +#define WM8994_IN1R_TO_LINEOUT2P 0x0002 /* IN1R_TO_LINEOUT2P */ +#define WM8994_IN1R_TO_LINEOUT2P_MASK 0x0002 /* IN1R_TO_LINEOUT2P */ +#define WM8994_IN1R_TO_LINEOUT2P_SHIFT 1 /* IN1R_TO_LINEOUT2P */ +#define WM8994_IN1R_TO_LINEOUT2P_WIDTH 1 /* IN1R_TO_LINEOUT2P */ +#define WM8994_MIXOUTR_TO_LINEOUT2P 0x0001 /* MIXOUTR_TO_LINEOUT2P */ +#define WM8994_MIXOUTR_TO_LINEOUT2P_MASK 0x0001 /* MIXOUTR_TO_LINEOUT2P */ +#define WM8994_MIXOUTR_TO_LINEOUT2P_SHIFT 0 /* MIXOUTR_TO_LINEOUT2P */ +#define WM8994_MIXOUTR_TO_LINEOUT2P_WIDTH 1 /* MIXOUTR_TO_LINEOUT2P */ + +/* + * R54 (0x36) - Speaker Mixer + */ +#define WM8994_DAC2L_TO_SPKMIXL 0x0200 /* DAC2L_TO_SPKMIXL */ +#define WM8994_DAC2L_TO_SPKMIXL_MASK 0x0200 /* DAC2L_TO_SPKMIXL */ +#define WM8994_DAC2L_TO_SPKMIXL_SHIFT 9 /* DAC2L_TO_SPKMIXL */ +#define WM8994_DAC2L_TO_SPKMIXL_WIDTH 1 /* DAC2L_TO_SPKMIXL */ +#define WM8994_DAC2R_TO_SPKMIXR 0x0100 /* DAC2R_TO_SPKMIXR */ +#define WM8994_DAC2R_TO_SPKMIXR_MASK 0x0100 /* DAC2R_TO_SPKMIXR */ +#define WM8994_DAC2R_TO_SPKMIXR_SHIFT 8 /* DAC2R_TO_SPKMIXR */ +#define WM8994_DAC2R_TO_SPKMIXR_WIDTH 1 /* DAC2R_TO_SPKMIXR */ +#define WM8994_MIXINL_TO_SPKMIXL 0x0080 /* MIXINL_TO_SPKMIXL */ +#define WM8994_MIXINL_TO_SPKMIXL_MASK 0x0080 /* MIXINL_TO_SPKMIXL */ +#define WM8994_MIXINL_TO_SPKMIXL_SHIFT 7 /* MIXINL_TO_SPKMIXL */ +#define WM8994_MIXINL_TO_SPKMIXL_WIDTH 1 /* MIXINL_TO_SPKMIXL */ +#define WM8994_MIXINR_TO_SPKMIXR 0x0040 /* MIXINR_TO_SPKMIXR */ +#define WM8994_MIXINR_TO_SPKMIXR_MASK 0x0040 /* MIXINR_TO_SPKMIXR */ +#define WM8994_MIXINR_TO_SPKMIXR_SHIFT 6 /* MIXINR_TO_SPKMIXR */ +#define WM8994_MIXINR_TO_SPKMIXR_WIDTH 1 /* MIXINR_TO_SPKMIXR */ +#define WM8994_IN1LP_TO_SPKMIXL 0x0020 /* IN1LP_TO_SPKMIXL */ +#define WM8994_IN1LP_TO_SPKMIXL_MASK 0x0020 /* IN1LP_TO_SPKMIXL */ +#define WM8994_IN1LP_TO_SPKMIXL_SHIFT 5 /* IN1LP_TO_SPKMIXL */ +#define WM8994_IN1LP_TO_SPKMIXL_WIDTH 1 /* IN1LP_TO_SPKMIXL */ +#define WM8994_IN1RP_TO_SPKMIXR 0x0010 /* IN1RP_TO_SPKMIXR */ +#define WM8994_IN1RP_TO_SPKMIXR_MASK 0x0010 /* IN1RP_TO_SPKMIXR */ +#define WM8994_IN1RP_TO_SPKMIXR_SHIFT 4 /* IN1RP_TO_SPKMIXR */ +#define WM8994_IN1RP_TO_SPKMIXR_WIDTH 1 /* IN1RP_TO_SPKMIXR */ +#define WM8994_MIXOUTL_TO_SPKMIXL 0x0008 /* MIXOUTL_TO_SPKMIXL */ +#define WM8994_MIXOUTL_TO_SPKMIXL_MASK 0x0008 /* MIXOUTL_TO_SPKMIXL */ +#define WM8994_MIXOUTL_TO_SPKMIXL_SHIFT 3 /* MIXOUTL_TO_SPKMIXL */ +#define WM8994_MIXOUTL_TO_SPKMIXL_WIDTH 1 /* MIXOUTL_TO_SPKMIXL */ +#define WM8994_MIXOUTR_TO_SPKMIXR 0x0004 /* MIXOUTR_TO_SPKMIXR */ +#define WM8994_MIXOUTR_TO_SPKMIXR_MASK 0x0004 /* MIXOUTR_TO_SPKMIXR */ +#define WM8994_MIXOUTR_TO_SPKMIXR_SHIFT 2 /* MIXOUTR_TO_SPKMIXR */ +#define WM8994_MIXOUTR_TO_SPKMIXR_WIDTH 1 /* MIXOUTR_TO_SPKMIXR */ +#define WM8994_DAC1L_TO_SPKMIXL 0x0002 /* DAC1L_TO_SPKMIXL */ +#define WM8994_DAC1L_TO_SPKMIXL_MASK 0x0002 /* DAC1L_TO_SPKMIXL */ +#define WM8994_DAC1L_TO_SPKMIXL_SHIFT 1 /* DAC1L_TO_SPKMIXL */ +#define WM8994_DAC1L_TO_SPKMIXL_WIDTH 1 /* DAC1L_TO_SPKMIXL */ +#define WM8994_DAC1R_TO_SPKMIXR 0x0001 /* DAC1R_TO_SPKMIXR */ +#define WM8994_DAC1R_TO_SPKMIXR_MASK 0x0001 /* DAC1R_TO_SPKMIXR */ +#define WM8994_DAC1R_TO_SPKMIXR_SHIFT 0 /* DAC1R_TO_SPKMIXR */ +#define WM8994_DAC1R_TO_SPKMIXR_WIDTH 1 /* DAC1R_TO_SPKMIXR */ + +/* + * R55 (0x37) - Additional Control + */ +#define WM8994_LINEOUT1_FB 0x0080 /* LINEOUT1_FB */ +#define WM8994_LINEOUT1_FB_MASK 0x0080 /* LINEOUT1_FB */ +#define WM8994_LINEOUT1_FB_SHIFT 7 /* LINEOUT1_FB */ +#define WM8994_LINEOUT1_FB_WIDTH 1 /* LINEOUT1_FB */ +#define WM8994_LINEOUT2_FB 0x0040 /* LINEOUT2_FB */ +#define WM8994_LINEOUT2_FB_MASK 0x0040 /* LINEOUT2_FB */ +#define WM8994_LINEOUT2_FB_SHIFT 6 /* LINEOUT2_FB */ +#define WM8994_LINEOUT2_FB_WIDTH 1 /* LINEOUT2_FB */ +#define WM8994_VROI 0x0001 /* VROI */ +#define WM8994_VROI_MASK 0x0001 /* VROI */ +#define WM8994_VROI_SHIFT 0 /* VROI */ +#define WM8994_VROI_WIDTH 1 /* VROI */ + +/* + * R56 (0x38) - AntiPOP (1) + */ +#define WM8994_LINEOUT_VMID_BUF_ENA 0x0080 /* LINEOUT_VMID_BUF_ENA */ +#define WM8994_LINEOUT_VMID_BUF_ENA_MASK 0x0080 /* LINEOUT_VMID_BUF_ENA */ +#define WM8994_LINEOUT_VMID_BUF_ENA_SHIFT 7 /* LINEOUT_VMID_BUF_ENA */ +#define WM8994_LINEOUT_VMID_BUF_ENA_WIDTH 1 /* LINEOUT_VMID_BUF_ENA */ +#define WM8994_HPOUT2_IN_ENA 0x0040 /* HPOUT2_IN_ENA */ +#define WM8994_HPOUT2_IN_ENA_MASK 0x0040 /* HPOUT2_IN_ENA */ +#define WM8994_HPOUT2_IN_ENA_SHIFT 6 /* HPOUT2_IN_ENA */ +#define WM8994_HPOUT2_IN_ENA_WIDTH 1 /* HPOUT2_IN_ENA */ +#define WM8994_LINEOUT1_DISCH 0x0020 /* LINEOUT1_DISCH */ +#define WM8994_LINEOUT1_DISCH_MASK 0x0020 /* LINEOUT1_DISCH */ +#define WM8994_LINEOUT1_DISCH_SHIFT 5 /* LINEOUT1_DISCH */ +#define WM8994_LINEOUT1_DISCH_WIDTH 1 /* LINEOUT1_DISCH */ +#define WM8994_LINEOUT2_DISCH 0x0010 /* LINEOUT2_DISCH */ +#define WM8994_LINEOUT2_DISCH_MASK 0x0010 /* LINEOUT2_DISCH */ +#define WM8994_LINEOUT2_DISCH_SHIFT 4 /* LINEOUT2_DISCH */ +#define WM8994_LINEOUT2_DISCH_WIDTH 1 /* LINEOUT2_DISCH */ + +/* + * R57 (0x39) - AntiPOP (2) + */ +#define WM8994_MICB2_DISCH 0x0100 /* MICB2_DISCH */ +#define WM8994_MICB2_DISCH_MASK 0x0100 /* MICB2_DISCH */ +#define WM8994_MICB2_DISCH_SHIFT 8 /* MICB2_DISCH */ +#define WM8994_MICB2_DISCH_WIDTH 1 /* MICB2_DISCH */ +#define WM8994_MICB1_DISCH 0x0080 /* MICB1_DISCH */ +#define WM8994_MICB1_DISCH_MASK 0x0080 /* MICB1_DISCH */ +#define WM8994_MICB1_DISCH_SHIFT 7 /* MICB1_DISCH */ +#define WM8994_MICB1_DISCH_WIDTH 1 /* MICB1_DISCH */ +#define WM8994_VMID_RAMP_MASK 0x0060 /* VMID_RAMP - [6:5] */ +#define WM8994_VMID_RAMP_SHIFT 5 /* VMID_RAMP - [6:5] */ +#define WM8994_VMID_RAMP_WIDTH 2 /* VMID_RAMP - [6:5] */ +#define WM8994_VMID_BUF_ENA 0x0008 /* VMID_BUF_ENA */ +#define WM8994_VMID_BUF_ENA_MASK 0x0008 /* VMID_BUF_ENA */ +#define WM8994_VMID_BUF_ENA_SHIFT 3 /* VMID_BUF_ENA */ +#define WM8994_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */ +#define WM8994_STARTUP_BIAS_ENA 0x0004 /* STARTUP_BIAS_ENA */ +#define WM8994_STARTUP_BIAS_ENA_MASK 0x0004 /* STARTUP_BIAS_ENA */ +#define WM8994_STARTUP_BIAS_ENA_SHIFT 2 /* STARTUP_BIAS_ENA */ +#define WM8994_STARTUP_BIAS_ENA_WIDTH 1 /* STARTUP_BIAS_ENA */ +#define WM8994_BIAS_SRC 0x0002 /* BIAS_SRC */ +#define WM8994_BIAS_SRC_MASK 0x0002 /* BIAS_SRC */ +#define WM8994_BIAS_SRC_SHIFT 1 /* BIAS_SRC */ +#define WM8994_BIAS_SRC_WIDTH 1 /* BIAS_SRC */ +#define WM8994_VMID_DISCH 0x0001 /* VMID_DISCH */ +#define WM8994_VMID_DISCH_MASK 0x0001 /* VMID_DISCH */ +#define WM8994_VMID_DISCH_SHIFT 0 /* VMID_DISCH */ +#define WM8994_VMID_DISCH_WIDTH 1 /* VMID_DISCH */ + +/* + * R58 (0x3A) - MICBIAS + */ +#define WM8994_MICD_SCTHR_MASK 0x00C0 /* MICD_SCTHR - [7:6] */ +#define WM8994_MICD_SCTHR_SHIFT 6 /* MICD_SCTHR - [7:6] */ +#define WM8994_MICD_SCTHR_WIDTH 2 /* MICD_SCTHR - [7:6] */ +#define WM8994_MICD_THR_MASK 0x0038 /* MICD_THR - [5:3] */ +#define WM8994_MICD_THR_SHIFT 3 /* MICD_THR - [5:3] */ +#define WM8994_MICD_THR_WIDTH 3 /* MICD_THR - [5:3] */ +#define WM8994_MICD_ENA 0x0004 /* MICD_ENA */ +#define WM8994_MICD_ENA_MASK 0x0004 /* MICD_ENA */ +#define WM8994_MICD_ENA_SHIFT 2 /* MICD_ENA */ +#define WM8994_MICD_ENA_WIDTH 1 /* MICD_ENA */ +#define WM8994_MICB2_LVL 0x0002 /* MICB2_LVL */ +#define WM8994_MICB2_LVL_MASK 0x0002 /* MICB2_LVL */ +#define WM8994_MICB2_LVL_SHIFT 1 /* MICB2_LVL */ +#define WM8994_MICB2_LVL_WIDTH 1 /* MICB2_LVL */ +#define WM8994_MICB1_LVL 0x0001 /* MICB1_LVL */ +#define WM8994_MICB1_LVL_MASK 0x0001 /* MICB1_LVL */ +#define WM8994_MICB1_LVL_SHIFT 0 /* MICB1_LVL */ +#define WM8994_MICB1_LVL_WIDTH 1 /* MICB1_LVL */ + +/* + * R59 (0x3B) - LDO 1 + */ +#define WM8994_LDO1_VSEL_MASK 0x000E /* LDO1_VSEL - [3:1] */ +#define WM8994_LDO1_VSEL_SHIFT 1 /* LDO1_VSEL - [3:1] */ +#define WM8994_LDO1_VSEL_WIDTH 3 /* LDO1_VSEL - [3:1] */ +#define WM8994_LDO1_DISCH 0x0001 /* LDO1_DISCH */ +#define WM8994_LDO1_DISCH_MASK 0x0001 /* LDO1_DISCH */ +#define WM8994_LDO1_DISCH_SHIFT 0 /* LDO1_DISCH */ +#define WM8994_LDO1_DISCH_WIDTH 1 /* LDO1_DISCH */ + +/* + * R60 (0x3C) - LDO 2 + */ +#define WM8994_LDO2_VSEL_MASK 0x0006 /* LDO2_VSEL - [2:1] */ +#define WM8994_LDO2_VSEL_SHIFT 1 /* LDO2_VSEL - [2:1] */ +#define WM8994_LDO2_VSEL_WIDTH 2 /* LDO2_VSEL - [2:1] */ +#define WM8994_LDO2_DISCH 0x0001 /* LDO2_DISCH */ +#define WM8994_LDO2_DISCH_MASK 0x0001 /* LDO2_DISCH */ +#define WM8994_LDO2_DISCH_SHIFT 0 /* LDO2_DISCH */ +#define WM8994_LDO2_DISCH_WIDTH 1 /* LDO2_DISCH */ + +/* + * R76 (0x4C) - Charge Pump (1) + */ +#define WM8994_CP_ENA 0x8000 /* CP_ENA */ +#define WM8994_CP_ENA_MASK 0x8000 /* CP_ENA */ +#define WM8994_CP_ENA_SHIFT 15 /* CP_ENA */ +#define WM8994_CP_ENA_WIDTH 1 /* CP_ENA */ + +/* + * R81 (0x51) - Class W (1) + */ +#define WM8994_CP_DYN_SRC_SEL_MASK 0x0300 /* CP_DYN_SRC_SEL - [9:8] */ +#define WM8994_CP_DYN_SRC_SEL_SHIFT 8 /* CP_DYN_SRC_SEL - [9:8] */ +#define WM8994_CP_DYN_SRC_SEL_WIDTH 2 /* CP_DYN_SRC_SEL - [9:8] */ +#define WM8994_CP_DYN_PWR 0x0001 /* CP_DYN_PWR */ +#define WM8994_CP_DYN_PWR_MASK 0x0001 /* CP_DYN_PWR */ +#define WM8994_CP_DYN_PWR_SHIFT 0 /* CP_DYN_PWR */ +#define WM8994_CP_DYN_PWR_WIDTH 1 /* CP_DYN_PWR */ + +/* + * R84 (0x54) - DC Servo (1) + */ +#define WM8994_DCS_TRIG_SINGLE_1 0x2000 /* DCS_TRIG_SINGLE_1 */ +#define WM8994_DCS_TRIG_SINGLE_1_MASK 0x2000 /* DCS_TRIG_SINGLE_1 */ +#define WM8994_DCS_TRIG_SINGLE_1_SHIFT 13 /* DCS_TRIG_SINGLE_1 */ +#define WM8994_DCS_TRIG_SINGLE_1_WIDTH 1 /* DCS_TRIG_SINGLE_1 */ +#define WM8994_DCS_TRIG_SINGLE_0 0x1000 /* DCS_TRIG_SINGLE_0 */ +#define WM8994_DCS_TRIG_SINGLE_0_MASK 0x1000 /* DCS_TRIG_SINGLE_0 */ +#define WM8994_DCS_TRIG_SINGLE_0_SHIFT 12 /* DCS_TRIG_SINGLE_0 */ +#define WM8994_DCS_TRIG_SINGLE_0_WIDTH 1 /* DCS_TRIG_SINGLE_0 */ +#define WM8994_DCS_TRIG_SERIES_1 0x0200 /* DCS_TRIG_SERIES_1 */ +#define WM8994_DCS_TRIG_SERIES_1_MASK 0x0200 /* DCS_TRIG_SERIES_1 */ +#define WM8994_DCS_TRIG_SERIES_1_SHIFT 9 /* DCS_TRIG_SERIES_1 */ +#define WM8994_DCS_TRIG_SERIES_1_WIDTH 1 /* DCS_TRIG_SERIES_1 */ +#define WM8994_DCS_TRIG_SERIES_0 0x0100 /* DCS_TRIG_SERIES_0 */ +#define WM8994_DCS_TRIG_SERIES_0_MASK 0x0100 /* DCS_TRIG_SERIES_0 */ +#define WM8994_DCS_TRIG_SERIES_0_SHIFT 8 /* DCS_TRIG_SERIES_0 */ +#define WM8994_DCS_TRIG_SERIES_0_WIDTH 1 /* DCS_TRIG_SERIES_0 */ +#define WM8994_DCS_TRIG_STARTUP_1 0x0020 /* DCS_TRIG_STARTUP_1 */ +#define WM8994_DCS_TRIG_STARTUP_1_MASK 0x0020 /* DCS_TRIG_STARTUP_1 */ +#define WM8994_DCS_TRIG_STARTUP_1_SHIFT 5 /* DCS_TRIG_STARTUP_1 */ +#define WM8994_DCS_TRIG_STARTUP_1_WIDTH 1 /* DCS_TRIG_STARTUP_1 */ +#define WM8994_DCS_TRIG_STARTUP_0 0x0010 /* DCS_TRIG_STARTUP_0 */ +#define WM8994_DCS_TRIG_STARTUP_0_MASK 0x0010 /* DCS_TRIG_STARTUP_0 */ +#define WM8994_DCS_TRIG_STARTUP_0_SHIFT 4 /* DCS_TRIG_STARTUP_0 */ +#define WM8994_DCS_TRIG_STARTUP_0_WIDTH 1 /* DCS_TRIG_STARTUP_0 */ +#define WM8994_DCS_TRIG_DAC_WR_1 0x0008 /* DCS_TRIG_DAC_WR_1 */ +#define WM8994_DCS_TRIG_DAC_WR_1_MASK 0x0008 /* DCS_TRIG_DAC_WR_1 */ +#define WM8994_DCS_TRIG_DAC_WR_1_SHIFT 3 /* DCS_TRIG_DAC_WR_1 */ +#define WM8994_DCS_TRIG_DAC_WR_1_WIDTH 1 /* DCS_TRIG_DAC_WR_1 */ +#define WM8994_DCS_TRIG_DAC_WR_0 0x0004 /* DCS_TRIG_DAC_WR_0 */ +#define WM8994_DCS_TRIG_DAC_WR_0_MASK 0x0004 /* DCS_TRIG_DAC_WR_0 */ +#define WM8994_DCS_TRIG_DAC_WR_0_SHIFT 2 /* DCS_TRIG_DAC_WR_0 */ +#define WM8994_DCS_TRIG_DAC_WR_0_WIDTH 1 /* DCS_TRIG_DAC_WR_0 */ +#define WM8994_DCS_ENA_CHAN_1 0x0002 /* DCS_ENA_CHAN_1 */ +#define WM8994_DCS_ENA_CHAN_1_MASK 0x0002 /* DCS_ENA_CHAN_1 */ +#define WM8994_DCS_ENA_CHAN_1_SHIFT 1 /* DCS_ENA_CHAN_1 */ +#define WM8994_DCS_ENA_CHAN_1_WIDTH 1 /* DCS_ENA_CHAN_1 */ +#define WM8994_DCS_ENA_CHAN_0 0x0001 /* DCS_ENA_CHAN_0 */ +#define WM8994_DCS_ENA_CHAN_0_MASK 0x0001 /* DCS_ENA_CHAN_0 */ +#define WM8994_DCS_ENA_CHAN_0_SHIFT 0 /* DCS_ENA_CHAN_0 */ +#define WM8994_DCS_ENA_CHAN_0_WIDTH 1 /* DCS_ENA_CHAN_0 */ + +/* + * R85 (0x55) - DC Servo (2) + */ +#define WM8994_DCS_SERIES_NO_01_MASK 0x0FE0 /* DCS_SERIES_NO_01 - [11:5] */ +#define WM8994_DCS_SERIES_NO_01_SHIFT 5 /* DCS_SERIES_NO_01 - [11:5] */ +#define WM8994_DCS_SERIES_NO_01_WIDTH 7 /* DCS_SERIES_NO_01 - [11:5] */ +#define WM8994_DCS_TIMER_PERIOD_01_MASK 0x000F /* DCS_TIMER_PERIOD_01 - [3:0] */ +#define WM8994_DCS_TIMER_PERIOD_01_SHIFT 0 /* DCS_TIMER_PERIOD_01 - [3:0] */ +#define WM8994_DCS_TIMER_PERIOD_01_WIDTH 4 /* DCS_TIMER_PERIOD_01 - [3:0] */ + +/* + * R87 (0x57) - DC Servo (4) + */ +#define WM8994_DCS_DAC_WR_VAL_1_MASK 0xFF00 /* DCS_DAC_WR_VAL_1 - [15:8] */ +#define WM8994_DCS_DAC_WR_VAL_1_SHIFT 8 /* DCS_DAC_WR_VAL_1 - [15:8] */ +#define WM8994_DCS_DAC_WR_VAL_1_WIDTH 8 /* DCS_DAC_WR_VAL_1 - [15:8] */ +#define WM8994_DCS_DAC_WR_VAL_0_MASK 0x00FF /* DCS_DAC_WR_VAL_0 - [7:0] */ +#define WM8994_DCS_DAC_WR_VAL_0_SHIFT 0 /* DCS_DAC_WR_VAL_0 - [7:0] */ +#define WM8994_DCS_DAC_WR_VAL_0_WIDTH 8 /* DCS_DAC_WR_VAL_0 - [7:0] */ + +/* + * R88 (0x58) - DC Servo Readback + */ +#define WM8994_DCS_CAL_COMPLETE_MASK 0x0300 /* DCS_CAL_COMPLETE - [9:8] */ +#define WM8994_DCS_CAL_COMPLETE_SHIFT 8 /* DCS_CAL_COMPLETE - [9:8] */ +#define WM8994_DCS_CAL_COMPLETE_WIDTH 2 /* DCS_CAL_COMPLETE - [9:8] */ +#define WM8994_DCS_DAC_WR_COMPLETE_MASK 0x0030 /* DCS_DAC_WR_COMPLETE - [5:4] */ +#define WM8994_DCS_DAC_WR_COMPLETE_SHIFT 4 /* DCS_DAC_WR_COMPLETE - [5:4] */ +#define WM8994_DCS_DAC_WR_COMPLETE_WIDTH 2 /* DCS_DAC_WR_COMPLETE - [5:4] */ +#define WM8994_DCS_STARTUP_COMPLETE_MASK 0x0003 /* DCS_STARTUP_COMPLETE - [1:0] */ +#define WM8994_DCS_STARTUP_COMPLETE_SHIFT 0 /* DCS_STARTUP_COMPLETE - [1:0] */ +#define WM8994_DCS_STARTUP_COMPLETE_WIDTH 2 /* DCS_STARTUP_COMPLETE - [1:0] */ + +/* + * R96 (0x60) - Analogue HP (1) + */ +#define WM8994_HPOUT1L_RMV_SHORT 0x0080 /* HPOUT1L_RMV_SHORT */ +#define WM8994_HPOUT1L_RMV_SHORT_MASK 0x0080 /* HPOUT1L_RMV_SHORT */ +#define WM8994_HPOUT1L_RMV_SHORT_SHIFT 7 /* HPOUT1L_RMV_SHORT */ +#define WM8994_HPOUT1L_RMV_SHORT_WIDTH 1 /* HPOUT1L_RMV_SHORT */ +#define WM8994_HPOUT1L_OUTP 0x0040 /* HPOUT1L_OUTP */ +#define WM8994_HPOUT1L_OUTP_MASK 0x0040 /* HPOUT1L_OUTP */ +#define WM8994_HPOUT1L_OUTP_SHIFT 6 /* HPOUT1L_OUTP */ +#define WM8994_HPOUT1L_OUTP_WIDTH 1 /* HPOUT1L_OUTP */ +#define WM8994_HPOUT1L_DLY 0x0020 /* HPOUT1L_DLY */ +#define WM8994_HPOUT1L_DLY_MASK 0x0020 /* HPOUT1L_DLY */ +#define WM8994_HPOUT1L_DLY_SHIFT 5 /* HPOUT1L_DLY */ +#define WM8994_HPOUT1L_DLY_WIDTH 1 /* HPOUT1L_DLY */ +#define WM8994_HPOUT1R_RMV_SHORT 0x0008 /* HPOUT1R_RMV_SHORT */ +#define WM8994_HPOUT1R_RMV_SHORT_MASK 0x0008 /* HPOUT1R_RMV_SHORT */ +#define WM8994_HPOUT1R_RMV_SHORT_SHIFT 3 /* HPOUT1R_RMV_SHORT */ +#define WM8994_HPOUT1R_RMV_SHORT_WIDTH 1 /* HPOUT1R_RMV_SHORT */ +#define WM8994_HPOUT1R_OUTP 0x0004 /* HPOUT1R_OUTP */ +#define WM8994_HPOUT1R_OUTP_MASK 0x0004 /* HPOUT1R_OUTP */ +#define WM8994_HPOUT1R_OUTP_SHIFT 2 /* HPOUT1R_OUTP */ +#define WM8994_HPOUT1R_OUTP_WIDTH 1 /* HPOUT1R_OUTP */ +#define WM8994_HPOUT1R_DLY 0x0002 /* HPOUT1R_DLY */ +#define WM8994_HPOUT1R_DLY_MASK 0x0002 /* HPOUT1R_DLY */ +#define WM8994_HPOUT1R_DLY_SHIFT 1 /* HPOUT1R_DLY */ +#define WM8994_HPOUT1R_DLY_WIDTH 1 /* HPOUT1R_DLY */ + +/* + * R256 (0x100) - Chip Revision + */ +#define WM8994_CHIP_REV_MASK 0x000F /* CHIP_REV - [3:0] */ +#define WM8994_CHIP_REV_SHIFT 0 /* CHIP_REV - [3:0] */ +#define WM8994_CHIP_REV_WIDTH 4 /* CHIP_REV - [3:0] */ + +/* + * R257 (0x101) - Control Interface + */ +#define WM8994_SPI_CONTRD 0x0040 /* SPI_CONTRD */ +#define WM8994_SPI_CONTRD_MASK 0x0040 /* SPI_CONTRD */ +#define WM8994_SPI_CONTRD_SHIFT 6 /* SPI_CONTRD */ +#define WM8994_SPI_CONTRD_WIDTH 1 /* SPI_CONTRD */ +#define WM8994_SPI_4WIRE 0x0020 /* SPI_4WIRE */ +#define WM8994_SPI_4WIRE_MASK 0x0020 /* SPI_4WIRE */ +#define WM8994_SPI_4WIRE_SHIFT 5 /* SPI_4WIRE */ +#define WM8994_SPI_4WIRE_WIDTH 1 /* SPI_4WIRE */ +#define WM8994_SPI_CFG 0x0010 /* SPI_CFG */ +#define WM8994_SPI_CFG_MASK 0x0010 /* SPI_CFG */ +#define WM8994_SPI_CFG_SHIFT 4 /* SPI_CFG */ +#define WM8994_SPI_CFG_WIDTH 1 /* SPI_CFG */ +#define WM8994_AUTO_INC 0x0004 /* AUTO_INC */ +#define WM8994_AUTO_INC_MASK 0x0004 /* AUTO_INC */ +#define WM8994_AUTO_INC_SHIFT 2 /* AUTO_INC */ +#define WM8994_AUTO_INC_WIDTH 1 /* AUTO_INC */ + +/* + * R272 (0x110) - Write Sequencer Ctrl (1) + */ +#define WM8994_WSEQ_ENA 0x8000 /* WSEQ_ENA */ +#define WM8994_WSEQ_ENA_MASK 0x8000 /* WSEQ_ENA */ +#define WM8994_WSEQ_ENA_SHIFT 15 /* WSEQ_ENA */ +#define WM8994_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */ +#define WM8994_WSEQ_ABORT 0x0200 /* WSEQ_ABORT */ +#define WM8994_WSEQ_ABORT_MASK 0x0200 /* WSEQ_ABORT */ +#define WM8994_WSEQ_ABORT_SHIFT 9 /* WSEQ_ABORT */ +#define WM8994_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */ +#define WM8994_WSEQ_START 0x0100 /* WSEQ_START */ +#define WM8994_WSEQ_START_MASK 0x0100 /* WSEQ_START */ +#define WM8994_WSEQ_START_SHIFT 8 /* WSEQ_START */ +#define WM8994_WSEQ_START_WIDTH 1 /* WSEQ_START */ +#define WM8994_WSEQ_START_INDEX_MASK 0x007F /* WSEQ_START_INDEX - [6:0] */ +#define WM8994_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [6:0] */ +#define WM8994_WSEQ_START_INDEX_WIDTH 7 /* WSEQ_START_INDEX - [6:0] */ + +/* + * R273 (0x111) - Write Sequencer Ctrl (2) + */ +#define WM8994_WSEQ_BUSY 0x0100 /* WSEQ_BUSY */ +#define WM8994_WSEQ_BUSY_MASK 0x0100 /* WSEQ_BUSY */ +#define WM8994_WSEQ_BUSY_SHIFT 8 /* WSEQ_BUSY */ +#define WM8994_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */ +#define WM8994_WSEQ_CURRENT_INDEX_MASK 0x007F /* WSEQ_CURRENT_INDEX - [6:0] */ +#define WM8994_WSEQ_CURRENT_INDEX_SHIFT 0 /* WSEQ_CURRENT_INDEX - [6:0] */ +#define WM8994_WSEQ_CURRENT_INDEX_WIDTH 7 /* WSEQ_CURRENT_INDEX - [6:0] */ + +/* + * R512 (0x200) - AIF1 Clocking (1) + */ +#define WM8994_AIF1CLK_SRC_MASK 0x0018 /* AIF1CLK_SRC - [4:3] */ +#define WM8994_AIF1CLK_SRC_SHIFT 3 /* AIF1CLK_SRC - [4:3] */ +#define WM8994_AIF1CLK_SRC_WIDTH 2 /* AIF1CLK_SRC - [4:3] */ +#define WM8994_AIF1CLK_INV 0x0004 /* AIF1CLK_INV */ +#define WM8994_AIF1CLK_INV_MASK 0x0004 /* AIF1CLK_INV */ +#define WM8994_AIF1CLK_INV_SHIFT 2 /* AIF1CLK_INV */ +#define WM8994_AIF1CLK_INV_WIDTH 1 /* AIF1CLK_INV */ +#define WM8994_AIF1CLK_DIV 0x0002 /* AIF1CLK_DIV */ +#define WM8994_AIF1CLK_DIV_MASK 0x0002 /* AIF1CLK_DIV */ +#define WM8994_AIF1CLK_DIV_SHIFT 1 /* AIF1CLK_DIV */ +#define WM8994_AIF1CLK_DIV_WIDTH 1 /* AIF1CLK_DIV */ +#define WM8994_AIF1CLK_ENA 0x0001 /* AIF1CLK_ENA */ +#define WM8994_AIF1CLK_ENA_MASK 0x0001 /* AIF1CLK_ENA */ +#define WM8994_AIF1CLK_ENA_SHIFT 0 /* AIF1CLK_ENA */ +#define WM8994_AIF1CLK_ENA_WIDTH 1 /* AIF1CLK_ENA */ + +/* + * R513 (0x201) - AIF1 Clocking (2) + */ +#define WM8994_AIF1DAC_DIV_MASK 0x0038 /* AIF1DAC_DIV - [5:3] */ +#define WM8994_AIF1DAC_DIV_SHIFT 3 /* AIF1DAC_DIV - [5:3] */ +#define WM8994_AIF1DAC_DIV_WIDTH 3 /* AIF1DAC_DIV - [5:3] */ +#define WM8994_AIF1ADC_DIV_MASK 0x0007 /* AIF1ADC_DIV - [2:0] */ +#define WM8994_AIF1ADC_DIV_SHIFT 0 /* AIF1ADC_DIV - [2:0] */ +#define WM8994_AIF1ADC_DIV_WIDTH 3 /* AIF1ADC_DIV - [2:0] */ + +/* + * R516 (0x204) - AIF2 Clocking (1) + */ +#define WM8994_AIF2CLK_SRC_MASK 0x0018 /* AIF2CLK_SRC - [4:3] */ +#define WM8994_AIF2CLK_SRC_SHIFT 3 /* AIF2CLK_SRC - [4:3] */ +#define WM8994_AIF2CLK_SRC_WIDTH 2 /* AIF2CLK_SRC - [4:3] */ +#define WM8994_AIF2CLK_INV 0x0004 /* AIF2CLK_INV */ +#define WM8994_AIF2CLK_INV_MASK 0x0004 /* AIF2CLK_INV */ +#define WM8994_AIF2CLK_INV_SHIFT 2 /* AIF2CLK_INV */ +#define WM8994_AIF2CLK_INV_WIDTH 1 /* AIF2CLK_INV */ +#define WM8994_AIF2CLK_DIV 0x0002 /* AIF2CLK_DIV */ +#define WM8994_AIF2CLK_DIV_MASK 0x0002 /* AIF2CLK_DIV */ +#define WM8994_AIF2CLK_DIV_SHIFT 1 /* AIF2CLK_DIV */ +#define WM8994_AIF2CLK_DIV_WIDTH 1 /* AIF2CLK_DIV */ +#define WM8994_AIF2CLK_ENA 0x0001 /* AIF2CLK_ENA */ +#define WM8994_AIF2CLK_ENA_MASK 0x0001 /* AIF2CLK_ENA */ +#define WM8994_AIF2CLK_ENA_SHIFT 0 /* AIF2CLK_ENA */ +#define WM8994_AIF2CLK_ENA_WIDTH 1 /* AIF2CLK_ENA */ + +/* + * R517 (0x205) - AIF2 Clocking (2) + */ +#define WM8994_AIF2DAC_DIV_MASK 0x0038 /* AIF2DAC_DIV - [5:3] */ +#define WM8994_AIF2DAC_DIV_SHIFT 3 /* AIF2DAC_DIV - [5:3] */ +#define WM8994_AIF2DAC_DIV_WIDTH 3 /* AIF2DAC_DIV - [5:3] */ +#define WM8994_AIF2ADC_DIV_MASK 0x0007 /* AIF2ADC_DIV - [2:0] */ +#define WM8994_AIF2ADC_DIV_SHIFT 0 /* AIF2ADC_DIV - [2:0] */ +#define WM8994_AIF2ADC_DIV_WIDTH 3 /* AIF2ADC_DIV - [2:0] */ + +/* + * R520 (0x208) - Clocking (1) + */ +#define WM8994_TOCLK_ENA 0x0010 /* TOCLK_ENA */ +#define WM8994_TOCLK_ENA_MASK 0x0010 /* TOCLK_ENA */ +#define WM8994_TOCLK_ENA_SHIFT 4 /* TOCLK_ENA */ +#define WM8994_TOCLK_ENA_WIDTH 1 /* TOCLK_ENA */ +#define WM8994_AIF1DSPCLK_ENA 0x0008 /* AIF1DSPCLK_ENA */ +#define WM8994_AIF1DSPCLK_ENA_MASK 0x0008 /* AIF1DSPCLK_ENA */ +#define WM8994_AIF1DSPCLK_ENA_SHIFT 3 /* AIF1DSPCLK_ENA */ +#define WM8994_AIF1DSPCLK_ENA_WIDTH 1 /* AIF1DSPCLK_ENA */ +#define WM8994_AIF2DSPCLK_ENA 0x0004 /* AIF2DSPCLK_ENA */ +#define WM8994_AIF2DSPCLK_ENA_MASK 0x0004 /* AIF2DSPCLK_ENA */ +#define WM8994_AIF2DSPCLK_ENA_SHIFT 2 /* AIF2DSPCLK_ENA */ +#define WM8994_AIF2DSPCLK_ENA_WIDTH 1 /* AIF2DSPCLK_ENA */ +#define WM8994_SYSDSPCLK_ENA 0x0002 /* SYSDSPCLK_ENA */ +#define WM8994_SYSDSPCLK_ENA_MASK 0x0002 /* SYSDSPCLK_ENA */ +#define WM8994_SYSDSPCLK_ENA_SHIFT 1 /* SYSDSPCLK_ENA */ +#define WM8994_SYSDSPCLK_ENA_WIDTH 1 /* SYSDSPCLK_ENA */ +#define WM8994_SYSCLK_SRC 0x0001 /* SYSCLK_SRC */ +#define WM8994_SYSCLK_SRC_MASK 0x0001 /* SYSCLK_SRC */ +#define WM8994_SYSCLK_SRC_SHIFT 0 /* SYSCLK_SRC */ +#define WM8994_SYSCLK_SRC_WIDTH 1 /* SYSCLK_SRC */ + +/* + * R521 (0x209) - Clocking (2) + */ +#define WM8994_TOCLK_DIV_MASK 0x0700 /* TOCLK_DIV - [10:8] */ +#define WM8994_TOCLK_DIV_SHIFT 8 /* TOCLK_DIV - [10:8] */ +#define WM8994_TOCLK_DIV_WIDTH 3 /* TOCLK_DIV - [10:8] */ +#define WM8994_DBCLK_DIV_MASK 0x0070 /* DBCLK_DIV - [6:4] */ +#define WM8994_DBCLK_DIV_SHIFT 4 /* DBCLK_DIV - [6:4] */ +#define WM8994_DBCLK_DIV_WIDTH 3 /* DBCLK_DIV - [6:4] */ +#define WM8994_OPCLK_DIV_MASK 0x0007 /* OPCLK_DIV - [2:0] */ +#define WM8994_OPCLK_DIV_SHIFT 0 /* OPCLK_DIV - [2:0] */ +#define WM8994_OPCLK_DIV_WIDTH 3 /* OPCLK_DIV - [2:0] */ + +/* + * R528 (0x210) - AIF1 Rate + */ +#define WM8994_AIF1_SR_MASK 0x00F0 /* AIF1_SR - [7:4] */ +#define WM8994_AIF1_SR_SHIFT 4 /* AIF1_SR - [7:4] */ +#define WM8994_AIF1_SR_WIDTH 4 /* AIF1_SR - [7:4] */ +#define WM8994_AIF1CLK_RATE_MASK 0x000F /* AIF1CLK_RATE - [3:0] */ +#define WM8994_AIF1CLK_RATE_SHIFT 0 /* AIF1CLK_RATE - [3:0] */ +#define WM8994_AIF1CLK_RATE_WIDTH 4 /* AIF1CLK_RATE - [3:0] */ + +/* + * R529 (0x211) - AIF2 Rate + */ +#define WM8994_AIF2_SR_MASK 0x00F0 /* AIF2_SR - [7:4] */ +#define WM8994_AIF2_SR_SHIFT 4 /* AIF2_SR - [7:4] */ +#define WM8994_AIF2_SR_WIDTH 4 /* AIF2_SR - [7:4] */ +#define WM8994_AIF2CLK_RATE_MASK 0x000F /* AIF2CLK_RATE - [3:0] */ +#define WM8994_AIF2CLK_RATE_SHIFT 0 /* AIF2CLK_RATE - [3:0] */ +#define WM8994_AIF2CLK_RATE_WIDTH 4 /* AIF2CLK_RATE - [3:0] */ + +/* + * R530 (0x212) - Rate Status + */ +#define WM8994_SR_ERROR_MASK 0x000F /* SR_ERROR - [3:0] */ +#define WM8994_SR_ERROR_SHIFT 0 /* SR_ERROR - [3:0] */ +#define WM8994_SR_ERROR_WIDTH 4 /* SR_ERROR - [3:0] */ + +/* + * R544 (0x220) - FLL1 Control (1) + */ +#define WM8994_FLL1_FRAC 0x0004 /* FLL1_FRAC */ +#define WM8994_FLL1_FRAC_MASK 0x0004 /* FLL1_FRAC */ +#define WM8994_FLL1_FRAC_SHIFT 2 /* FLL1_FRAC */ +#define WM8994_FLL1_FRAC_WIDTH 1 /* FLL1_FRAC */ +#define WM8994_FLL1_OSC_ENA 0x0002 /* FLL1_OSC_ENA */ +#define WM8994_FLL1_OSC_ENA_MASK 0x0002 /* FLL1_OSC_ENA */ +#define WM8994_FLL1_OSC_ENA_SHIFT 1 /* FLL1_OSC_ENA */ +#define WM8994_FLL1_OSC_ENA_WIDTH 1 /* FLL1_OSC_ENA */ +#define WM8994_FLL1_ENA 0x0001 /* FLL1_ENA */ +#define WM8994_FLL1_ENA_MASK 0x0001 /* FLL1_ENA */ +#define WM8994_FLL1_ENA_SHIFT 0 /* FLL1_ENA */ +#define WM8994_FLL1_ENA_WIDTH 1 /* FLL1_ENA */ + +/* + * R545 (0x221) - FLL1 Control (2) + */ +#define WM8994_FLL1_OUTDIV_MASK 0x3F00 /* FLL1_OUTDIV - [13:8] */ +#define WM8994_FLL1_OUTDIV_SHIFT 8 /* FLL1_OUTDIV - [13:8] */ +#define WM8994_FLL1_OUTDIV_WIDTH 6 /* FLL1_OUTDIV - [13:8] */ +#define WM8994_FLL1_CTRL_RATE_MASK 0x0070 /* FLL1_CTRL_RATE - [6:4] */ +#define WM8994_FLL1_CTRL_RATE_SHIFT 4 /* FLL1_CTRL_RATE - [6:4] */ +#define WM8994_FLL1_CTRL_RATE_WIDTH 3 /* FLL1_CTRL_RATE - [6:4] */ +#define WM8994_FLL1_FRATIO_MASK 0x0007 /* FLL1_FRATIO - [2:0] */ +#define WM8994_FLL1_FRATIO_SHIFT 0 /* FLL1_FRATIO - [2:0] */ +#define WM8994_FLL1_FRATIO_WIDTH 3 /* FLL1_FRATIO - [2:0] */ + +/* + * R546 (0x222) - FLL1 Control (3) + */ +#define WM8994_FLL1_K_MASK 0xFFFF /* FLL1_K - [15:0] */ +#define WM8994_FLL1_K_SHIFT 0 /* FLL1_K - [15:0] */ +#define WM8994_FLL1_K_WIDTH 16 /* FLL1_K - [15:0] */ + +/* + * R547 (0x223) - FLL1 Control (4) + */ +#define WM8994_FLL1_N_MASK 0x7FE0 /* FLL1_N - [14:5] */ +#define WM8994_FLL1_N_SHIFT 5 /* FLL1_N - [14:5] */ +#define WM8994_FLL1_N_WIDTH 10 /* FLL1_N - [14:5] */ +#define WM8994_FLL1_LOOP_GAIN_MASK 0x000F /* FLL1_LOOP_GAIN - [3:0] */ +#define WM8994_FLL1_LOOP_GAIN_SHIFT 0 /* FLL1_LOOP_GAIN - [3:0] */ +#define WM8994_FLL1_LOOP_GAIN_WIDTH 4 /* FLL1_LOOP_GAIN - [3:0] */ + +/* + * R548 (0x224) - FLL1 Control (5) + */ +#define WM8994_FLL1_FRC_NCO_VAL_MASK 0x1F80 /* FLL1_FRC_NCO_VAL - [12:7] */ +#define WM8994_FLL1_FRC_NCO_VAL_SHIFT 7 /* FLL1_FRC_NCO_VAL - [12:7] */ +#define WM8994_FLL1_FRC_NCO_VAL_WIDTH 6 /* FLL1_FRC_NCO_VAL - [12:7] */ +#define WM8994_FLL1_FRC_NCO 0x0040 /* FLL1_FRC_NCO */ +#define WM8994_FLL1_FRC_NCO_MASK 0x0040 /* FLL1_FRC_NCO */ +#define WM8994_FLL1_FRC_NCO_SHIFT 6 /* FLL1_FRC_NCO */ +#define WM8994_FLL1_FRC_NCO_WIDTH 1 /* FLL1_FRC_NCO */ +#define WM8994_FLL1_REFCLK_DIV_MASK 0x0018 /* FLL1_REFCLK_DIV - [4:3] */ +#define WM8994_FLL1_REFCLK_DIV_SHIFT 3 /* FLL1_REFCLK_DIV - [4:3] */ +#define WM8994_FLL1_REFCLK_DIV_WIDTH 2 /* FLL1_REFCLK_DIV - [4:3] */ +#define WM8994_FLL1_REFCLK_SRC_MASK 0x0003 /* FLL1_REFCLK_SRC - [1:0] */ +#define WM8994_FLL1_REFCLK_SRC_SHIFT 0 /* FLL1_REFCLK_SRC - [1:0] */ +#define WM8994_FLL1_REFCLK_SRC_WIDTH 2 /* FLL1_REFCLK_SRC - [1:0] */ + +/* + * R576 (0x240) - FLL2 Control (1) + */ +#define WM8994_FLL2_FRAC 0x0004 /* FLL2_FRAC */ +#define WM8994_FLL2_FRAC_MASK 0x0004 /* FLL2_FRAC */ +#define WM8994_FLL2_FRAC_SHIFT 2 /* FLL2_FRAC */ +#define WM8994_FLL2_FRAC_WIDTH 1 /* FLL2_FRAC */ +#define WM8994_FLL2_OSC_ENA 0x0002 /* FLL2_OSC_ENA */ +#define WM8994_FLL2_OSC_ENA_MASK 0x0002 /* FLL2_OSC_ENA */ +#define WM8994_FLL2_OSC_ENA_SHIFT 1 /* FLL2_OSC_ENA */ +#define WM8994_FLL2_OSC_ENA_WIDTH 1 /* FLL2_OSC_ENA */ +#define WM8994_FLL2_ENA 0x0001 /* FLL2_ENA */ +#define WM8994_FLL2_ENA_MASK 0x0001 /* FLL2_ENA */ +#define WM8994_FLL2_ENA_SHIFT 0 /* FLL2_ENA */ +#define WM8994_FLL2_ENA_WIDTH 1 /* FLL2_ENA */ + +/* + * R577 (0x241) - FLL2 Control (2) + */ +#define WM8994_FLL2_OUTDIV_MASK 0x3F00 /* FLL2_OUTDIV - [13:8] */ +#define WM8994_FLL2_OUTDIV_SHIFT 8 /* FLL2_OUTDIV - [13:8] */ +#define WM8994_FLL2_OUTDIV_WIDTH 6 /* FLL2_OUTDIV - [13:8] */ +#define WM8994_FLL2_CTRL_RATE_MASK 0x0070 /* FLL2_CTRL_RATE - [6:4] */ +#define WM8994_FLL2_CTRL_RATE_SHIFT 4 /* FLL2_CTRL_RATE - [6:4] */ +#define WM8994_FLL2_CTRL_RATE_WIDTH 3 /* FLL2_CTRL_RATE - [6:4] */ +#define WM8994_FLL2_FRATIO_MASK 0x0007 /* FLL2_FRATIO - [2:0] */ +#define WM8994_FLL2_FRATIO_SHIFT 0 /* FLL2_FRATIO - [2:0] */ +#define WM8994_FLL2_FRATIO_WIDTH 3 /* FLL2_FRATIO - [2:0] */ + +/* + * R578 (0x242) - FLL2 Control (3) + */ +#define WM8994_FLL2_K_MASK 0xFFFF /* FLL2_K - [15:0] */ +#define WM8994_FLL2_K_SHIFT 0 /* FLL2_K - [15:0] */ +#define WM8994_FLL2_K_WIDTH 16 /* FLL2_K - [15:0] */ + +/* + * R579 (0x243) - FLL2 Control (4) + */ +#define WM8994_FLL2_N_MASK 0x7FE0 /* FLL2_N - [14:5] */ +#define WM8994_FLL2_N_SHIFT 5 /* FLL2_N - [14:5] */ +#define WM8994_FLL2_N_WIDTH 10 /* FLL2_N - [14:5] */ +#define WM8994_FLL2_LOOP_GAIN_MASK 0x000F /* FLL2_LOOP_GAIN - [3:0] */ +#define WM8994_FLL2_LOOP_GAIN_SHIFT 0 /* FLL2_LOOP_GAIN - [3:0] */ +#define WM8994_FLL2_LOOP_GAIN_WIDTH 4 /* FLL2_LOOP_GAIN - [3:0] */ + +/* + * R580 (0x244) - FLL2 Control (5) + */ +#define WM8994_FLL2_FRC_NCO_VAL_MASK 0x1F80 /* FLL2_FRC_NCO_VAL - [12:7] */ +#define WM8994_FLL2_FRC_NCO_VAL_SHIFT 7 /* FLL2_FRC_NCO_VAL - [12:7] */ +#define WM8994_FLL2_FRC_NCO_VAL_WIDTH 6 /* FLL2_FRC_NCO_VAL - [12:7] */ +#define WM8994_FLL2_FRC_NCO 0x0040 /* FLL2_FRC_NCO */ +#define WM8994_FLL2_FRC_NCO_MASK 0x0040 /* FLL2_FRC_NCO */ +#define WM8994_FLL2_FRC_NCO_SHIFT 6 /* FLL2_FRC_NCO */ +#define WM8994_FLL2_FRC_NCO_WIDTH 1 /* FLL2_FRC_NCO */ +#define WM8994_FLL2_REFCLK_DIV_MASK 0x0018 /* FLL2_REFCLK_DIV - [4:3] */ +#define WM8994_FLL2_REFCLK_DIV_SHIFT 3 /* FLL2_REFCLK_DIV - [4:3] */ +#define WM8994_FLL2_REFCLK_DIV_WIDTH 2 /* FLL2_REFCLK_DIV - [4:3] */ +#define WM8994_FLL2_REFCLK_SRC_MASK 0x0003 /* FLL2_REFCLK_SRC - [1:0] */ +#define WM8994_FLL2_REFCLK_SRC_SHIFT 0 /* FLL2_REFCLK_SRC - [1:0] */ +#define WM8994_FLL2_REFCLK_SRC_WIDTH 2 /* FLL2_REFCLK_SRC - [1:0] */ + +/* + * R768 (0x300) - AIF1 Control (1) + */ +#define WM8994_AIF1ADCL_SRC 0x8000 /* AIF1ADCL_SRC */ +#define WM8994_AIF1ADCL_SRC_MASK 0x8000 /* AIF1ADCL_SRC */ +#define WM8994_AIF1ADCL_SRC_SHIFT 15 /* AIF1ADCL_SRC */ +#define WM8994_AIF1ADCL_SRC_WIDTH 1 /* AIF1ADCL_SRC */ +#define WM8994_AIF1ADCR_SRC 0x4000 /* AIF1ADCR_SRC */ +#define WM8994_AIF1ADCR_SRC_MASK 0x4000 /* AIF1ADCR_SRC */ +#define WM8994_AIF1ADCR_SRC_SHIFT 14 /* AIF1ADCR_SRC */ +#define WM8994_AIF1ADCR_SRC_WIDTH 1 /* AIF1ADCR_SRC */ +#define WM8994_AIF1ADC_TDM 0x2000 /* AIF1ADC_TDM */ +#define WM8994_AIF1ADC_TDM_MASK 0x2000 /* AIF1ADC_TDM */ +#define WM8994_AIF1ADC_TDM_SHIFT 13 /* AIF1ADC_TDM */ +#define WM8994_AIF1ADC_TDM_WIDTH 1 /* AIF1ADC_TDM */ +#define WM8994_AIF1_BCLK_INV 0x0100 /* AIF1_BCLK_INV */ +#define WM8994_AIF1_BCLK_INV_MASK 0x0100 /* AIF1_BCLK_INV */ +#define WM8994_AIF1_BCLK_INV_SHIFT 8 /* AIF1_BCLK_INV */ +#define WM8994_AIF1_BCLK_INV_WIDTH 1 /* AIF1_BCLK_INV */ +#define WM8994_AIF1_LRCLK_INV 0x0080 /* AIF1_LRCLK_INV */ +#define WM8994_AIF1_LRCLK_INV_MASK 0x0080 /* AIF1_LRCLK_INV */ +#define WM8994_AIF1_LRCLK_INV_SHIFT 7 /* AIF1_LRCLK_INV */ +#define WM8994_AIF1_LRCLK_INV_WIDTH 1 /* AIF1_LRCLK_INV */ +#define WM8994_AIF1_WL_MASK 0x0060 /* AIF1_WL - [6:5] */ +#define WM8994_AIF1_WL_SHIFT 5 /* AIF1_WL - [6:5] */ +#define WM8994_AIF1_WL_WIDTH 2 /* AIF1_WL - [6:5] */ +#define WM8994_AIF1_FMT_MASK 0x0018 /* AIF1_FMT - [4:3] */ +#define WM8994_AIF1_FMT_SHIFT 3 /* AIF1_FMT - [4:3] */ +#define WM8994_AIF1_FMT_WIDTH 2 /* AIF1_FMT - [4:3] */ + +/* + * R769 (0x301) - AIF1 Control (2) + */ +#define WM8994_AIF1DACL_SRC 0x8000 /* AIF1DACL_SRC */ +#define WM8994_AIF1DACL_SRC_MASK 0x8000 /* AIF1DACL_SRC */ +#define WM8994_AIF1DACL_SRC_SHIFT 15 /* AIF1DACL_SRC */ +#define WM8994_AIF1DACL_SRC_WIDTH 1 /* AIF1DACL_SRC */ +#define WM8994_AIF1DACR_SRC 0x4000 /* AIF1DACR_SRC */ +#define WM8994_AIF1DACR_SRC_MASK 0x4000 /* AIF1DACR_SRC */ +#define WM8994_AIF1DACR_SRC_SHIFT 14 /* AIF1DACR_SRC */ +#define WM8994_AIF1DACR_SRC_WIDTH 1 /* AIF1DACR_SRC */ +#define WM8994_AIF1DAC_BOOST_MASK 0x0C00 /* AIF1DAC_BOOST - [11:10] */ +#define WM8994_AIF1DAC_BOOST_SHIFT 10 /* AIF1DAC_BOOST - [11:10] */ +#define WM8994_AIF1DAC_BOOST_WIDTH 2 /* AIF1DAC_BOOST - [11:10] */ +#define WM8994_AIF1_MONO 0x0100 /* AIF1_MONO */ +#define WM8994_AIF1_MONO_MASK 0x0100 /* AIF1_MONO */ +#define WM8994_AIF1_MONO_SHIFT 8 /* AIF1_MONO */ +#define WM8994_AIF1_MONO_WIDTH 1 /* AIF1_MONO */ +#define WM8994_AIF1DAC_COMP 0x0010 /* AIF1DAC_COMP */ +#define WM8994_AIF1DAC_COMP_MASK 0x0010 /* AIF1DAC_COMP */ +#define WM8994_AIF1DAC_COMP_SHIFT 4 /* AIF1DAC_COMP */ +#define WM8994_AIF1DAC_COMP_WIDTH 1 /* AIF1DAC_COMP */ +#define WM8994_AIF1DAC_COMPMODE 0x0008 /* AIF1DAC_COMPMODE */ +#define WM8994_AIF1DAC_COMPMODE_MASK 0x0008 /* AIF1DAC_COMPMODE */ +#define WM8994_AIF1DAC_COMPMODE_SHIFT 3 /* AIF1DAC_COMPMODE */ +#define WM8994_AIF1DAC_COMPMODE_WIDTH 1 /* AIF1DAC_COMPMODE */ +#define WM8994_AIF1ADC_COMP 0x0004 /* AIF1ADC_COMP */ +#define WM8994_AIF1ADC_COMP_MASK 0x0004 /* AIF1ADC_COMP */ +#define WM8994_AIF1ADC_COMP_SHIFT 2 /* AIF1ADC_COMP */ +#define WM8994_AIF1ADC_COMP_WIDTH 1 /* AIF1ADC_COMP */ +#define WM8994_AIF1ADC_COMPMODE 0x0002 /* AIF1ADC_COMPMODE */ +#define WM8994_AIF1ADC_COMPMODE_MASK 0x0002 /* AIF1ADC_COMPMODE */ +#define WM8994_AIF1ADC_COMPMODE_SHIFT 1 /* AIF1ADC_COMPMODE */ +#define WM8994_AIF1ADC_COMPMODE_WIDTH 1 /* AIF1ADC_COMPMODE */ +#define WM8994_AIF1_LOOPBACK 0x0001 /* AIF1_LOOPBACK */ +#define WM8994_AIF1_LOOPBACK_MASK 0x0001 /* AIF1_LOOPBACK */ +#define WM8994_AIF1_LOOPBACK_SHIFT 0 /* AIF1_LOOPBACK */ +#define WM8994_AIF1_LOOPBACK_WIDTH 1 /* AIF1_LOOPBACK */ + +/* + * R770 (0x302) - AIF1 Master/Slave + */ +#define WM8994_AIF1_TRI 0x8000 /* AIF1_TRI */ +#define WM8994_AIF1_TRI_MASK 0x8000 /* AIF1_TRI */ +#define WM8994_AIF1_TRI_SHIFT 15 /* AIF1_TRI */ +#define WM8994_AIF1_TRI_WIDTH 1 /* AIF1_TRI */ +#define WM8994_AIF1_MSTR 0x4000 /* AIF1_MSTR */ +#define WM8994_AIF1_MSTR_MASK 0x4000 /* AIF1_MSTR */ +#define WM8994_AIF1_MSTR_SHIFT 14 /* AIF1_MSTR */ +#define WM8994_AIF1_MSTR_WIDTH 1 /* AIF1_MSTR */ +#define WM8994_AIF1_CLK_FRC 0x2000 /* AIF1_CLK_FRC */ +#define WM8994_AIF1_CLK_FRC_MASK 0x2000 /* AIF1_CLK_FRC */ +#define WM8994_AIF1_CLK_FRC_SHIFT 13 /* AIF1_CLK_FRC */ +#define WM8994_AIF1_CLK_FRC_WIDTH 1 /* AIF1_CLK_FRC */ +#define WM8994_AIF1_LRCLK_FRC 0x1000 /* AIF1_LRCLK_FRC */ +#define WM8994_AIF1_LRCLK_FRC_MASK 0x1000 /* AIF1_LRCLK_FRC */ +#define WM8994_AIF1_LRCLK_FRC_SHIFT 12 /* AIF1_LRCLK_FRC */ +#define WM8994_AIF1_LRCLK_FRC_WIDTH 1 /* AIF1_LRCLK_FRC */ + +/* + * R771 (0x303) - AIF1 BCLK + */ +#define WM8994_AIF1_BCLK_DIV_MASK 0x01F0 /* AIF1_BCLK_DIV - [8:4] */ +#define WM8994_AIF1_BCLK_DIV_SHIFT 4 /* AIF1_BCLK_DIV - [8:4] */ +#define WM8994_AIF1_BCLK_DIV_WIDTH 5 /* AIF1_BCLK_DIV - [8:4] */ + +/* + * R772 (0x304) - AIF1ADC LRCLK + */ +#define WM8994_AIF1ADC_LRCLK_DIR 0x0800 /* AIF1ADC_LRCLK_DIR */ +#define WM8994_AIF1ADC_LRCLK_DIR_MASK 0x0800 /* AIF1ADC_LRCLK_DIR */ +#define WM8994_AIF1ADC_LRCLK_DIR_SHIFT 11 /* AIF1ADC_LRCLK_DIR */ +#define WM8994_AIF1ADC_LRCLK_DIR_WIDTH 1 /* AIF1ADC_LRCLK_DIR */ +#define WM8994_AIF1ADC_RATE_MASK 0x07FF /* AIF1ADC_RATE - [10:0] */ +#define WM8994_AIF1ADC_RATE_SHIFT 0 /* AIF1ADC_RATE - [10:0] */ +#define WM8994_AIF1ADC_RATE_WIDTH 11 /* AIF1ADC_RATE - [10:0] */ + +/* + * R773 (0x305) - AIF1DAC LRCLK + */ +#define WM8994_AIF1DAC_LRCLK_DIR 0x0800 /* AIF1DAC_LRCLK_DIR */ +#define WM8994_AIF1DAC_LRCLK_DIR_MASK 0x0800 /* AIF1DAC_LRCLK_DIR */ +#define WM8994_AIF1DAC_LRCLK_DIR_SHIFT 11 /* AIF1DAC_LRCLK_DIR */ +#define WM8994_AIF1DAC_LRCLK_DIR_WIDTH 1 /* AIF1DAC_LRCLK_DIR */ +#define WM8994_AIF1DAC_RATE_MASK 0x07FF /* AIF1DAC_RATE - [10:0] */ +#define WM8994_AIF1DAC_RATE_SHIFT 0 /* AIF1DAC_RATE - [10:0] */ +#define WM8994_AIF1DAC_RATE_WIDTH 11 /* AIF1DAC_RATE - [10:0] */ + +/* + * R774 (0x306) - AIF1DAC Data + */ +#define WM8994_AIF1DACL_DAT_INV 0x0002 /* AIF1DACL_DAT_INV */ +#define WM8994_AIF1DACL_DAT_INV_MASK 0x0002 /* AIF1DACL_DAT_INV */ +#define WM8994_AIF1DACL_DAT_INV_SHIFT 1 /* AIF1DACL_DAT_INV */ +#define WM8994_AIF1DACL_DAT_INV_WIDTH 1 /* AIF1DACL_DAT_INV */ +#define WM8994_AIF1DACR_DAT_INV 0x0001 /* AIF1DACR_DAT_INV */ +#define WM8994_AIF1DACR_DAT_INV_MASK 0x0001 /* AIF1DACR_DAT_INV */ +#define WM8994_AIF1DACR_DAT_INV_SHIFT 0 /* AIF1DACR_DAT_INV */ +#define WM8994_AIF1DACR_DAT_INV_WIDTH 1 /* AIF1DACR_DAT_INV */ + +/* + * R775 (0x307) - AIF1ADC Data + */ +#define WM8994_AIF1ADCL_DAT_INV 0x0002 /* AIF1ADCL_DAT_INV */ +#define WM8994_AIF1ADCL_DAT_INV_MASK 0x0002 /* AIF1ADCL_DAT_INV */ +#define WM8994_AIF1ADCL_DAT_INV_SHIFT 1 /* AIF1ADCL_DAT_INV */ +#define WM8994_AIF1ADCL_DAT_INV_WIDTH 1 /* AIF1ADCL_DAT_INV */ +#define WM8994_AIF1ADCR_DAT_INV 0x0001 /* AIF1ADCR_DAT_INV */ +#define WM8994_AIF1ADCR_DAT_INV_MASK 0x0001 /* AIF1ADCR_DAT_INV */ +#define WM8994_AIF1ADCR_DAT_INV_SHIFT 0 /* AIF1ADCR_DAT_INV */ +#define WM8994_AIF1ADCR_DAT_INV_WIDTH 1 /* AIF1ADCR_DAT_INV */ + +/* + * R784 (0x310) - AIF2 Control (1) + */ +#define WM8994_AIF2ADCL_SRC 0x8000 /* AIF2ADCL_SRC */ +#define WM8994_AIF2ADCL_SRC_MASK 0x8000 /* AIF2ADCL_SRC */ +#define WM8994_AIF2ADCL_SRC_SHIFT 15 /* AIF2ADCL_SRC */ +#define WM8994_AIF2ADCL_SRC_WIDTH 1 /* AIF2ADCL_SRC */ +#define WM8994_AIF2ADCR_SRC 0x4000 /* AIF2ADCR_SRC */ +#define WM8994_AIF2ADCR_SRC_MASK 0x4000 /* AIF2ADCR_SRC */ +#define WM8994_AIF2ADCR_SRC_SHIFT 14 /* AIF2ADCR_SRC */ +#define WM8994_AIF2ADCR_SRC_WIDTH 1 /* AIF2ADCR_SRC */ +#define WM8994_AIF2ADC_TDM 0x2000 /* AIF2ADC_TDM */ +#define WM8994_AIF2ADC_TDM_MASK 0x2000 /* AIF2ADC_TDM */ +#define WM8994_AIF2ADC_TDM_SHIFT 13 /* AIF2ADC_TDM */ +#define WM8994_AIF2ADC_TDM_WIDTH 1 /* AIF2ADC_TDM */ +#define WM8994_AIF2ADC_TDM_CHAN 0x1000 /* AIF2ADC_TDM_CHAN */ +#define WM8994_AIF2ADC_TDM_CHAN_MASK 0x1000 /* AIF2ADC_TDM_CHAN */ +#define WM8994_AIF2ADC_TDM_CHAN_SHIFT 12 /* AIF2ADC_TDM_CHAN */ +#define WM8994_AIF2ADC_TDM_CHAN_WIDTH 1 /* AIF2ADC_TDM_CHAN */ +#define WM8994_AIF2_BCLK_INV 0x0100 /* AIF2_BCLK_INV */ +#define WM8994_AIF2_BCLK_INV_MASK 0x0100 /* AIF2_BCLK_INV */ +#define WM8994_AIF2_BCLK_INV_SHIFT 8 /* AIF2_BCLK_INV */ +#define WM8994_AIF2_BCLK_INV_WIDTH 1 /* AIF2_BCLK_INV */ +#define WM8994_AIF2_LRCLK_INV 0x0080 /* AIF2_LRCLK_INV */ +#define WM8994_AIF2_LRCLK_INV_MASK 0x0080 /* AIF2_LRCLK_INV */ +#define WM8994_AIF2_LRCLK_INV_SHIFT 7 /* AIF2_LRCLK_INV */ +#define WM8994_AIF2_LRCLK_INV_WIDTH 1 /* AIF2_LRCLK_INV */ +#define WM8994_AIF2_WL_MASK 0x0060 /* AIF2_WL - [6:5] */ +#define WM8994_AIF2_WL_SHIFT 5 /* AIF2_WL - [6:5] */ +#define WM8994_AIF2_WL_WIDTH 2 /* AIF2_WL - [6:5] */ +#define WM8994_AIF2_FMT_MASK 0x0018 /* AIF2_FMT - [4:3] */ +#define WM8994_AIF2_FMT_SHIFT 3 /* AIF2_FMT - [4:3] */ +#define WM8994_AIF2_FMT_WIDTH 2 /* AIF2_FMT - [4:3] */ + +/* + * R785 (0x311) - AIF2 Control (2) + */ +#define WM8994_AIF2DACL_SRC 0x8000 /* AIF2DACL_SRC */ +#define WM8994_AIF2DACL_SRC_MASK 0x8000 /* AIF2DACL_SRC */ +#define WM8994_AIF2DACL_SRC_SHIFT 15 /* AIF2DACL_SRC */ +#define WM8994_AIF2DACL_SRC_WIDTH 1 /* AIF2DACL_SRC */ +#define WM8994_AIF2DACR_SRC 0x4000 /* AIF2DACR_SRC */ +#define WM8994_AIF2DACR_SRC_MASK 0x4000 /* AIF2DACR_SRC */ +#define WM8994_AIF2DACR_SRC_SHIFT 14 /* AIF2DACR_SRC */ +#define WM8994_AIF2DACR_SRC_WIDTH 1 /* AIF2DACR_SRC */ +#define WM8994_AIF2DAC_TDM 0x2000 /* AIF2DAC_TDM */ +#define WM8994_AIF2DAC_TDM_MASK 0x2000 /* AIF2DAC_TDM */ +#define WM8994_AIF2DAC_TDM_SHIFT 13 /* AIF2DAC_TDM */ +#define WM8994_AIF2DAC_TDM_WIDTH 1 /* AIF2DAC_TDM */ +#define WM8994_AIF2DAC_TDM_CHAN 0x1000 /* AIF2DAC_TDM_CHAN */ +#define WM8994_AIF2DAC_TDM_CHAN_MASK 0x1000 /* AIF2DAC_TDM_CHAN */ +#define WM8994_AIF2DAC_TDM_CHAN_SHIFT 12 /* AIF2DAC_TDM_CHAN */ +#define WM8994_AIF2DAC_TDM_CHAN_WIDTH 1 /* AIF2DAC_TDM_CHAN */ +#define WM8994_AIF2DAC_BOOST_MASK 0x0C00 /* AIF2DAC_BOOST - [11:10] */ +#define WM8994_AIF2DAC_BOOST_SHIFT 10 /* AIF2DAC_BOOST - [11:10] */ +#define WM8994_AIF2DAC_BOOST_WIDTH 2 /* AIF2DAC_BOOST - [11:10] */ +#define WM8994_AIF2_MONO 0x0100 /* AIF2_MONO */ +#define WM8994_AIF2_MONO_MASK 0x0100 /* AIF2_MONO */ +#define WM8994_AIF2_MONO_SHIFT 8 /* AIF2_MONO */ +#define WM8994_AIF2_MONO_WIDTH 1 /* AIF2_MONO */ +#define WM8994_AIF2DAC_COMP 0x0010 /* AIF2DAC_COMP */ +#define WM8994_AIF2DAC_COMP_MASK 0x0010 /* AIF2DAC_COMP */ +#define WM8994_AIF2DAC_COMP_SHIFT 4 /* AIF2DAC_COMP */ +#define WM8994_AIF2DAC_COMP_WIDTH 1 /* AIF2DAC_COMP */ +#define WM8994_AIF2DAC_COMPMODE 0x0008 /* AIF2DAC_COMPMODE */ +#define WM8994_AIF2DAC_COMPMODE_MASK 0x0008 /* AIF2DAC_COMPMODE */ +#define WM8994_AIF2DAC_COMPMODE_SHIFT 3 /* AIF2DAC_COMPMODE */ +#define WM8994_AIF2DAC_COMPMODE_WIDTH 1 /* AIF2DAC_COMPMODE */ +#define WM8994_AIF2ADC_COMP 0x0004 /* AIF2ADC_COMP */ +#define WM8994_AIF2ADC_COMP_MASK 0x0004 /* AIF2ADC_COMP */ +#define WM8994_AIF2ADC_COMP_SHIFT 2 /* AIF2ADC_COMP */ +#define WM8994_AIF2ADC_COMP_WIDTH 1 /* AIF2ADC_COMP */ +#define WM8994_AIF2ADC_COMPMODE 0x0002 /* AIF2ADC_COMPMODE */ +#define WM8994_AIF2ADC_COMPMODE_MASK 0x0002 /* AIF2ADC_COMPMODE */ +#define WM8994_AIF2ADC_COMPMODE_SHIFT 1 /* AIF2ADC_COMPMODE */ +#define WM8994_AIF2ADC_COMPMODE_WIDTH 1 /* AIF2ADC_COMPMODE */ +#define WM8994_AIF2_LOOPBACK 0x0001 /* AIF2_LOOPBACK */ +#define WM8994_AIF2_LOOPBACK_MASK 0x0001 /* AIF2_LOOPBACK */ +#define WM8994_AIF2_LOOPBACK_SHIFT 0 /* AIF2_LOOPBACK */ +#define WM8994_AIF2_LOOPBACK_WIDTH 1 /* AIF2_LOOPBACK */ + +/* + * R786 (0x312) - AIF2 Master/Slave + */ +#define WM8994_AIF2_TRI 0x8000 /* AIF2_TRI */ +#define WM8994_AIF2_TRI_MASK 0x8000 /* AIF2_TRI */ +#define WM8994_AIF2_TRI_SHIFT 15 /* AIF2_TRI */ +#define WM8994_AIF2_TRI_WIDTH 1 /* AIF2_TRI */ +#define WM8994_AIF2_MSTR 0x4000 /* AIF2_MSTR */ +#define WM8994_AIF2_MSTR_MASK 0x4000 /* AIF2_MSTR */ +#define WM8994_AIF2_MSTR_SHIFT 14 /* AIF2_MSTR */ +#define WM8994_AIF2_MSTR_WIDTH 1 /* AIF2_MSTR */ +#define WM8994_AIF2_CLK_FRC 0x2000 /* AIF2_CLK_FRC */ +#define WM8994_AIF2_CLK_FRC_MASK 0x2000 /* AIF2_CLK_FRC */ +#define WM8994_AIF2_CLK_FRC_SHIFT 13 /* AIF2_CLK_FRC */ +#define WM8994_AIF2_CLK_FRC_WIDTH 1 /* AIF2_CLK_FRC */ +#define WM8994_AIF2_LRCLK_FRC 0x1000 /* AIF2_LRCLK_FRC */ +#define WM8994_AIF2_LRCLK_FRC_MASK 0x1000 /* AIF2_LRCLK_FRC */ +#define WM8994_AIF2_LRCLK_FRC_SHIFT 12 /* AIF2_LRCLK_FRC */ +#define WM8994_AIF2_LRCLK_FRC_WIDTH 1 /* AIF2_LRCLK_FRC */ + +/* + * R787 (0x313) - AIF2 BCLK + */ +#define WM8994_AIF2_BCLK_DIV_MASK 0x01F0 /* AIF2_BCLK_DIV - [8:4] */ +#define WM8994_AIF2_BCLK_DIV_SHIFT 4 /* AIF2_BCLK_DIV - [8:4] */ +#define WM8994_AIF2_BCLK_DIV_WIDTH 5 /* AIF2_BCLK_DIV - [8:4] */ + +/* + * R788 (0x314) - AIF2ADC LRCLK + */ +#define WM8994_AIF2ADC_LRCLK_DIR 0x0800 /* AIF2ADC_LRCLK_DIR */ +#define WM8994_AIF2ADC_LRCLK_DIR_MASK 0x0800 /* AIF2ADC_LRCLK_DIR */ +#define WM8994_AIF2ADC_LRCLK_DIR_SHIFT 11 /* AIF2ADC_LRCLK_DIR */ +#define WM8994_AIF2ADC_LRCLK_DIR_WIDTH 1 /* AIF2ADC_LRCLK_DIR */ +#define WM8994_AIF2ADC_RATE_MASK 0x07FF /* AIF2ADC_RATE - [10:0] */ +#define WM8994_AIF2ADC_RATE_SHIFT 0 /* AIF2ADC_RATE - [10:0] */ +#define WM8994_AIF2ADC_RATE_WIDTH 11 /* AIF2ADC_RATE - [10:0] */ + +/* + * R789 (0x315) - AIF2DAC LRCLK + */ +#define WM8994_AIF2DAC_LRCLK_DIR 0x0800 /* AIF2DAC_LRCLK_DIR */ +#define WM8994_AIF2DAC_LRCLK_DIR_MASK 0x0800 /* AIF2DAC_LRCLK_DIR */ +#define WM8994_AIF2DAC_LRCLK_DIR_SHIFT 11 /* AIF2DAC_LRCLK_DIR */ +#define WM8994_AIF2DAC_LRCLK_DIR_WIDTH 1 /* AIF2DAC_LRCLK_DIR */ +#define WM8994_AIF2DAC_RATE_MASK 0x07FF /* AIF2DAC_RATE - [10:0] */ +#define WM8994_AIF2DAC_RATE_SHIFT 0 /* AIF2DAC_RATE - [10:0] */ +#define WM8994_AIF2DAC_RATE_WIDTH 11 /* AIF2DAC_RATE - [10:0] */ + +/* + * R790 (0x316) - AIF2DAC Data + */ +#define WM8994_AIF2DACL_DAT_INV 0x0002 /* AIF2DACL_DAT_INV */ +#define WM8994_AIF2DACL_DAT_INV_MASK 0x0002 /* AIF2DACL_DAT_INV */ +#define WM8994_AIF2DACL_DAT_INV_SHIFT 1 /* AIF2DACL_DAT_INV */ +#define WM8994_AIF2DACL_DAT_INV_WIDTH 1 /* AIF2DACL_DAT_INV */ +#define WM8994_AIF2DACR_DAT_INV 0x0001 /* AIF2DACR_DAT_INV */ +#define WM8994_AIF2DACR_DAT_INV_MASK 0x0001 /* AIF2DACR_DAT_INV */ +#define WM8994_AIF2DACR_DAT_INV_SHIFT 0 /* AIF2DACR_DAT_INV */ +#define WM8994_AIF2DACR_DAT_INV_WIDTH 1 /* AIF2DACR_DAT_INV */ + +/* + * R791 (0x317) - AIF2ADC Data + */ +#define WM8994_AIF2ADCL_DAT_INV 0x0002 /* AIF2ADCL_DAT_INV */ +#define WM8994_AIF2ADCL_DAT_INV_MASK 0x0002 /* AIF2ADCL_DAT_INV */ +#define WM8994_AIF2ADCL_DAT_INV_SHIFT 1 /* AIF2ADCL_DAT_INV */ +#define WM8994_AIF2ADCL_DAT_INV_WIDTH 1 /* AIF2ADCL_DAT_INV */ +#define WM8994_AIF2ADCR_DAT_INV 0x0001 /* AIF2ADCR_DAT_INV */ +#define WM8994_AIF2ADCR_DAT_INV_MASK 0x0001 /* AIF2ADCR_DAT_INV */ +#define WM8994_AIF2ADCR_DAT_INV_SHIFT 0 /* AIF2ADCR_DAT_INV */ +#define WM8994_AIF2ADCR_DAT_INV_WIDTH 1 /* AIF2ADCR_DAT_INV */ + +/* + * R1024 (0x400) - AIF1 ADC1 Left Volume + */ +#define WM8994_AIF1ADC1_VU 0x0100 /* AIF1ADC1_VU */ +#define WM8994_AIF1ADC1_VU_MASK 0x0100 /* AIF1ADC1_VU */ +#define WM8994_AIF1ADC1_VU_SHIFT 8 /* AIF1ADC1_VU */ +#define WM8994_AIF1ADC1_VU_WIDTH 1 /* AIF1ADC1_VU */ +#define WM8994_AIF1ADC1L_VOL_MASK 0x00FF /* AIF1ADC1L_VOL - [7:0] */ +#define WM8994_AIF1ADC1L_VOL_SHIFT 0 /* AIF1ADC1L_VOL - [7:0] */ +#define WM8994_AIF1ADC1L_VOL_WIDTH 8 /* AIF1ADC1L_VOL - [7:0] */ + +/* + * R1025 (0x401) - AIF1 ADC1 Right Volume + */ +#define WM8994_AIF1ADC1_VU 0x0100 /* AIF1ADC1_VU */ +#define WM8994_AIF1ADC1_VU_MASK 0x0100 /* AIF1ADC1_VU */ +#define WM8994_AIF1ADC1_VU_SHIFT 8 /* AIF1ADC1_VU */ +#define WM8994_AIF1ADC1_VU_WIDTH 1 /* AIF1ADC1_VU */ +#define WM8994_AIF1ADC1R_VOL_MASK 0x00FF /* AIF1ADC1R_VOL - [7:0] */ +#define WM8994_AIF1ADC1R_VOL_SHIFT 0 /* AIF1ADC1R_VOL - [7:0] */ +#define WM8994_AIF1ADC1R_VOL_WIDTH 8 /* AIF1ADC1R_VOL - [7:0] */ + +/* + * R1026 (0x402) - AIF1 DAC1 Left Volume + */ +#define WM8994_AIF1DAC1_VU 0x0100 /* AIF1DAC1_VU */ +#define WM8994_AIF1DAC1_VU_MASK 0x0100 /* AIF1DAC1_VU */ +#define WM8994_AIF1DAC1_VU_SHIFT 8 /* AIF1DAC1_VU */ +#define WM8994_AIF1DAC1_VU_WIDTH 1 /* AIF1DAC1_VU */ +#define WM8994_AIF1DAC1L_VOL_MASK 0x00FF /* AIF1DAC1L_VOL - [7:0] */ +#define WM8994_AIF1DAC1L_VOL_SHIFT 0 /* AIF1DAC1L_VOL - [7:0] */ +#define WM8994_AIF1DAC1L_VOL_WIDTH 8 /* AIF1DAC1L_VOL - [7:0] */ + +/* + * R1027 (0x403) - AIF1 DAC1 Right Volume + */ +#define WM8994_AIF1DAC1_VU 0x0100 /* AIF1DAC1_VU */ +#define WM8994_AIF1DAC1_VU_MASK 0x0100 /* AIF1DAC1_VU */ +#define WM8994_AIF1DAC1_VU_SHIFT 8 /* AIF1DAC1_VU */ +#define WM8994_AIF1DAC1_VU_WIDTH 1 /* AIF1DAC1_VU */ +#define WM8994_AIF1DAC1R_VOL_MASK 0x00FF /* AIF1DAC1R_VOL - [7:0] */ +#define WM8994_AIF1DAC1R_VOL_SHIFT 0 /* AIF1DAC1R_VOL - [7:0] */ +#define WM8994_AIF1DAC1R_VOL_WIDTH 8 /* AIF1DAC1R_VOL - [7:0] */ + +/* + * R1028 (0x404) - AIF1 ADC2 Left Volume + */ +#define WM8994_AIF1ADC2_VU 0x0100 /* AIF1ADC2_VU */ +#define WM8994_AIF1ADC2_VU_MASK 0x0100 /* AIF1ADC2_VU */ +#define WM8994_AIF1ADC2_VU_SHIFT 8 /* AIF1ADC2_VU */ +#define WM8994_AIF1ADC2_VU_WIDTH 1 /* AIF1ADC2_VU */ +#define WM8994_AIF1ADC2L_VOL_MASK 0x00FF /* AIF1ADC2L_VOL - [7:0] */ +#define WM8994_AIF1ADC2L_VOL_SHIFT 0 /* AIF1ADC2L_VOL - [7:0] */ +#define WM8994_AIF1ADC2L_VOL_WIDTH 8 /* AIF1ADC2L_VOL - [7:0] */ + +/* + * R1029 (0x405) - AIF1 ADC2 Right Volume + */ +#define WM8994_AIF1ADC2_VU 0x0100 /* AIF1ADC2_VU */ +#define WM8994_AIF1ADC2_VU_MASK 0x0100 /* AIF1ADC2_VU */ +#define WM8994_AIF1ADC2_VU_SHIFT 8 /* AIF1ADC2_VU */ +#define WM8994_AIF1ADC2_VU_WIDTH 1 /* AIF1ADC2_VU */ +#define WM8994_AIF1ADC2R_VOL_MASK 0x00FF /* AIF1ADC2R_VOL - [7:0] */ +#define WM8994_AIF1ADC2R_VOL_SHIFT 0 /* AIF1ADC2R_VOL - [7:0] */ +#define WM8994_AIF1ADC2R_VOL_WIDTH 8 /* AIF1ADC2R_VOL - [7:0] */ + +/* + * R1030 (0x406) - AIF1 DAC2 Left Volume + */ +#define WM8994_AIF1DAC2_VU 0x0100 /* AIF1DAC2_VU */ +#define WM8994_AIF1DAC2_VU_MASK 0x0100 /* AIF1DAC2_VU */ +#define WM8994_AIF1DAC2_VU_SHIFT 8 /* AIF1DAC2_VU */ +#define WM8994_AIF1DAC2_VU_WIDTH 1 /* AIF1DAC2_VU */ +#define WM8994_AIF1DAC2L_VOL_MASK 0x00FF /* AIF1DAC2L_VOL - [7:0] */ +#define WM8994_AIF1DAC2L_VOL_SHIFT 0 /* AIF1DAC2L_VOL - [7:0] */ +#define WM8994_AIF1DAC2L_VOL_WIDTH 8 /* AIF1DAC2L_VOL - [7:0] */ + +/* + * R1031 (0x407) - AIF1 DAC2 Right Volume + */ +#define WM8994_AIF1DAC2_VU 0x0100 /* AIF1DAC2_VU */ +#define WM8994_AIF1DAC2_VU_MASK 0x0100 /* AIF1DAC2_VU */ +#define WM8994_AIF1DAC2_VU_SHIFT 8 /* AIF1DAC2_VU */ +#define WM8994_AIF1DAC2_VU_WIDTH 1 /* AIF1DAC2_VU */ +#define WM8994_AIF1DAC2R_VOL_MASK 0x00FF /* AIF1DAC2R_VOL - [7:0] */ +#define WM8994_AIF1DAC2R_VOL_SHIFT 0 /* AIF1DAC2R_VOL - [7:0] */ +#define WM8994_AIF1DAC2R_VOL_WIDTH 8 /* AIF1DAC2R_VOL - [7:0] */ + +/* + * R1040 (0x410) - AIF1 ADC1 Filters + */ +#define WM8994_AIF1ADC_4FS 0x8000 /* AIF1ADC_4FS */ +#define WM8994_AIF1ADC_4FS_MASK 0x8000 /* AIF1ADC_4FS */ +#define WM8994_AIF1ADC_4FS_SHIFT 15 /* AIF1ADC_4FS */ +#define WM8994_AIF1ADC_4FS_WIDTH 1 /* AIF1ADC_4FS */ +#define WM8994_AIF1ADC1_HPF_CUT_MASK 0x6000 /* AIF1ADC1_HPF_CUT - [14:13] */ +#define WM8994_AIF1ADC1_HPF_CUT_SHIFT 13 /* AIF1ADC1_HPF_CUT - [14:13] */ +#define WM8994_AIF1ADC1_HPF_CUT_WIDTH 2 /* AIF1ADC1_HPF_CUT - [14:13] */ +#define WM8994_AIF1ADC1L_HPF 0x1000 /* AIF1ADC1L_HPF */ +#define WM8994_AIF1ADC1L_HPF_MASK 0x1000 /* AIF1ADC1L_HPF */ +#define WM8994_AIF1ADC1L_HPF_SHIFT 12 /* AIF1ADC1L_HPF */ +#define WM8994_AIF1ADC1L_HPF_WIDTH 1 /* AIF1ADC1L_HPF */ +#define WM8994_AIF1ADC1R_HPF 0x0800 /* AIF1ADC1R_HPF */ +#define WM8994_AIF1ADC1R_HPF_MASK 0x0800 /* AIF1ADC1R_HPF */ +#define WM8994_AIF1ADC1R_HPF_SHIFT 11 /* AIF1ADC1R_HPF */ +#define WM8994_AIF1ADC1R_HPF_WIDTH 1 /* AIF1ADC1R_HPF */ + +/* + * R1041 (0x411) - AIF1 ADC2 Filters + */ +#define WM8994_AIF1ADC2_HPF_CUT_MASK 0x6000 /* AIF1ADC2_HPF_CUT - [14:13] */ +#define WM8994_AIF1ADC2_HPF_CUT_SHIFT 13 /* AIF1ADC2_HPF_CUT - [14:13] */ +#define WM8994_AIF1ADC2_HPF_CUT_WIDTH 2 /* AIF1ADC2_HPF_CUT - [14:13] */ +#define WM8994_AIF1ADC2L_HPF 0x1000 /* AIF1ADC2L_HPF */ +#define WM8994_AIF1ADC2L_HPF_MASK 0x1000 /* AIF1ADC2L_HPF */ +#define WM8994_AIF1ADC2L_HPF_SHIFT 12 /* AIF1ADC2L_HPF */ +#define WM8994_AIF1ADC2L_HPF_WIDTH 1 /* AIF1ADC2L_HPF */ +#define WM8994_AIF1ADC2R_HPF 0x0800 /* AIF1ADC2R_HPF */ +#define WM8994_AIF1ADC2R_HPF_MASK 0x0800 /* AIF1ADC2R_HPF */ +#define WM8994_AIF1ADC2R_HPF_SHIFT 11 /* AIF1ADC2R_HPF */ +#define WM8994_AIF1ADC2R_HPF_WIDTH 1 /* AIF1ADC2R_HPF */ + +/* + * R1056 (0x420) - AIF1 DAC1 Filters (1) + */ +#define WM8994_AIF1DAC1_MUTE 0x0200 /* AIF1DAC1_MUTE */ +#define WM8994_AIF1DAC1_MUTE_MASK 0x0200 /* AIF1DAC1_MUTE */ +#define WM8994_AIF1DAC1_MUTE_SHIFT 9 /* AIF1DAC1_MUTE */ +#define WM8994_AIF1DAC1_MUTE_WIDTH 1 /* AIF1DAC1_MUTE */ +#define WM8994_AIF1DAC1_MONO 0x0080 /* AIF1DAC1_MONO */ +#define WM8994_AIF1DAC1_MONO_MASK 0x0080 /* AIF1DAC1_MONO */ +#define WM8994_AIF1DAC1_MONO_SHIFT 7 /* AIF1DAC1_MONO */ +#define WM8994_AIF1DAC1_MONO_WIDTH 1 /* AIF1DAC1_MONO */ +#define WM8994_AIF1DAC1_MUTERATE 0x0020 /* AIF1DAC1_MUTERATE */ +#define WM8994_AIF1DAC1_MUTERATE_MASK 0x0020 /* AIF1DAC1_MUTERATE */ +#define WM8994_AIF1DAC1_MUTERATE_SHIFT 5 /* AIF1DAC1_MUTERATE */ +#define WM8994_AIF1DAC1_MUTERATE_WIDTH 1 /* AIF1DAC1_MUTERATE */ +#define WM8994_AIF1DAC1_UNMUTE_RAMP 0x0010 /* AIF1DAC1_UNMUTE_RAMP */ +#define WM8994_AIF1DAC1_UNMUTE_RAMP_MASK 0x0010 /* AIF1DAC1_UNMUTE_RAMP */ +#define WM8994_AIF1DAC1_UNMUTE_RAMP_SHIFT 4 /* AIF1DAC1_UNMUTE_RAMP */ +#define WM8994_AIF1DAC1_UNMUTE_RAMP_WIDTH 1 /* AIF1DAC1_UNMUTE_RAMP */ +#define WM8994_AIF1DAC1_DEEMP_MASK 0x0006 /* AIF1DAC1_DEEMP - [2:1] */ +#define WM8994_AIF1DAC1_DEEMP_SHIFT 1 /* AIF1DAC1_DEEMP - [2:1] */ +#define WM8994_AIF1DAC1_DEEMP_WIDTH 2 /* AIF1DAC1_DEEMP - [2:1] */ + +/* + * R1057 (0x421) - AIF1 DAC1 Filters (2) + */ +#define WM8994_AIF1DAC1_3D_GAIN_MASK 0x3E00 /* AIF1DAC1_3D_GAIN - [13:9] */ +#define WM8994_AIF1DAC1_3D_GAIN_SHIFT 9 /* AIF1DAC1_3D_GAIN - [13:9] */ +#define WM8994_AIF1DAC1_3D_GAIN_WIDTH 5 /* AIF1DAC1_3D_GAIN - [13:9] */ +#define WM8994_AIF1DAC1_3D_ENA 0x0100 /* AIF1DAC1_3D_ENA */ +#define WM8994_AIF1DAC1_3D_ENA_MASK 0x0100 /* AIF1DAC1_3D_ENA */ +#define WM8994_AIF1DAC1_3D_ENA_SHIFT 8 /* AIF1DAC1_3D_ENA */ +#define WM8994_AIF1DAC1_3D_ENA_WIDTH 1 /* AIF1DAC1_3D_ENA */ + +/* + * R1058 (0x422) - AIF1 DAC2 Filters (1) + */ +#define WM8994_AIF1DAC2_MUTE 0x0200 /* AIF1DAC2_MUTE */ +#define WM8994_AIF1DAC2_MUTE_MASK 0x0200 /* AIF1DAC2_MUTE */ +#define WM8994_AIF1DAC2_MUTE_SHIFT 9 /* AIF1DAC2_MUTE */ +#define WM8994_AIF1DAC2_MUTE_WIDTH 1 /* AIF1DAC2_MUTE */ +#define WM8994_AIF1DAC2_MONO 0x0080 /* AIF1DAC2_MONO */ +#define WM8994_AIF1DAC2_MONO_MASK 0x0080 /* AIF1DAC2_MONO */ +#define WM8994_AIF1DAC2_MONO_SHIFT 7 /* AIF1DAC2_MONO */ +#define WM8994_AIF1DAC2_MONO_WIDTH 1 /* AIF1DAC2_MONO */ +#define WM8994_AIF1DAC2_MUTERATE 0x0020 /* AIF1DAC2_MUTERATE */ +#define WM8994_AIF1DAC2_MUTERATE_MASK 0x0020 /* AIF1DAC2_MUTERATE */ +#define WM8994_AIF1DAC2_MUTERATE_SHIFT 5 /* AIF1DAC2_MUTERATE */ +#define WM8994_AIF1DAC2_MUTERATE_WIDTH 1 /* AIF1DAC2_MUTERATE */ +#define WM8994_AIF1DAC2_UNMUTE_RAMP 0x0010 /* AIF1DAC2_UNMUTE_RAMP */ +#define WM8994_AIF1DAC2_UNMUTE_RAMP_MASK 0x0010 /* AIF1DAC2_UNMUTE_RAMP */ +#define WM8994_AIF1DAC2_UNMUTE_RAMP_SHIFT 4 /* AIF1DAC2_UNMUTE_RAMP */ +#define WM8994_AIF1DAC2_UNMUTE_RAMP_WIDTH 1 /* AIF1DAC2_UNMUTE_RAMP */ +#define WM8994_AIF1DAC2_DEEMP_MASK 0x0006 /* AIF1DAC2_DEEMP - [2:1] */ +#define WM8994_AIF1DAC2_DEEMP_SHIFT 1 /* AIF1DAC2_DEEMP - [2:1] */ +#define WM8994_AIF1DAC2_DEEMP_WIDTH 2 /* AIF1DAC2_DEEMP - [2:1] */ + +/* + * R1059 (0x423) - AIF1 DAC2 Filters (2) + */ +#define WM8994_AIF1DAC2_3D_GAIN_MASK 0x3E00 /* AIF1DAC2_3D_GAIN - [13:9] */ +#define WM8994_AIF1DAC2_3D_GAIN_SHIFT 9 /* AIF1DAC2_3D_GAIN - [13:9] */ +#define WM8994_AIF1DAC2_3D_GAIN_WIDTH 5 /* AIF1DAC2_3D_GAIN - [13:9] */ +#define WM8994_AIF1DAC2_3D_ENA 0x0100 /* AIF1DAC2_3D_ENA */ +#define WM8994_AIF1DAC2_3D_ENA_MASK 0x0100 /* AIF1DAC2_3D_ENA */ +#define WM8994_AIF1DAC2_3D_ENA_SHIFT 8 /* AIF1DAC2_3D_ENA */ +#define WM8994_AIF1DAC2_3D_ENA_WIDTH 1 /* AIF1DAC2_3D_ENA */ + +/* + * R1088 (0x440) - AIF1 DRC1 (1) + */ +#define WM8994_AIF1DRC1_SIG_DET_RMS_MASK 0xF800 /* AIF1DRC1_SIG_DET_RMS - [15:11] */ +#define WM8994_AIF1DRC1_SIG_DET_RMS_SHIFT 11 /* AIF1DRC1_SIG_DET_RMS - [15:11] */ +#define WM8994_AIF1DRC1_SIG_DET_RMS_WIDTH 5 /* AIF1DRC1_SIG_DET_RMS - [15:11] */ +#define WM8994_AIF1DRC1_SIG_DET_PK_MASK 0x0600 /* AIF1DRC1_SIG_DET_PK - [10:9] */ +#define WM8994_AIF1DRC1_SIG_DET_PK_SHIFT 9 /* AIF1DRC1_SIG_DET_PK - [10:9] */ +#define WM8994_AIF1DRC1_SIG_DET_PK_WIDTH 2 /* AIF1DRC1_SIG_DET_PK - [10:9] */ +#define WM8994_AIF1DRC1_NG_ENA 0x0100 /* AIF1DRC1_NG_ENA */ +#define WM8994_AIF1DRC1_NG_ENA_MASK 0x0100 /* AIF1DRC1_NG_ENA */ +#define WM8994_AIF1DRC1_NG_ENA_SHIFT 8 /* AIF1DRC1_NG_ENA */ +#define WM8994_AIF1DRC1_NG_ENA_WIDTH 1 /* AIF1DRC1_NG_ENA */ +#define WM8994_AIF1DRC1_SIG_DET_MODE 0x0080 /* AIF1DRC1_SIG_DET_MODE */ +#define WM8994_AIF1DRC1_SIG_DET_MODE_MASK 0x0080 /* AIF1DRC1_SIG_DET_MODE */ +#define WM8994_AIF1DRC1_SIG_DET_MODE_SHIFT 7 /* AIF1DRC1_SIG_DET_MODE */ +#define WM8994_AIF1DRC1_SIG_DET_MODE_WIDTH 1 /* AIF1DRC1_SIG_DET_MODE */ +#define WM8994_AIF1DRC1_SIG_DET 0x0040 /* AIF1DRC1_SIG_DET */ +#define WM8994_AIF1DRC1_SIG_DET_MASK 0x0040 /* AIF1DRC1_SIG_DET */ +#define WM8994_AIF1DRC1_SIG_DET_SHIFT 6 /* AIF1DRC1_SIG_DET */ +#define WM8994_AIF1DRC1_SIG_DET_WIDTH 1 /* AIF1DRC1_SIG_DET */ +#define WM8994_AIF1DRC1_KNEE2_OP_ENA 0x0020 /* AIF1DRC1_KNEE2_OP_ENA */ +#define WM8994_AIF1DRC1_KNEE2_OP_ENA_MASK 0x0020 /* AIF1DRC1_KNEE2_OP_ENA */ +#define WM8994_AIF1DRC1_KNEE2_OP_ENA_SHIFT 5 /* AIF1DRC1_KNEE2_OP_ENA */ +#define WM8994_AIF1DRC1_KNEE2_OP_ENA_WIDTH 1 /* AIF1DRC1_KNEE2_OP_ENA */ +#define WM8994_AIF1DRC1_QR 0x0010 /* AIF1DRC1_QR */ +#define WM8994_AIF1DRC1_QR_MASK 0x0010 /* AIF1DRC1_QR */ +#define WM8994_AIF1DRC1_QR_SHIFT 4 /* AIF1DRC1_QR */ +#define WM8994_AIF1DRC1_QR_WIDTH 1 /* AIF1DRC1_QR */ +#define WM8994_AIF1DRC1_ANTICLIP 0x0008 /* AIF1DRC1_ANTICLIP */ +#define WM8994_AIF1DRC1_ANTICLIP_MASK 0x0008 /* AIF1DRC1_ANTICLIP */ +#define WM8994_AIF1DRC1_ANTICLIP_SHIFT 3 /* AIF1DRC1_ANTICLIP */ +#define WM8994_AIF1DRC1_ANTICLIP_WIDTH 1 /* AIF1DRC1_ANTICLIP */ +#define WM8994_AIF1DAC1_DRC_ENA 0x0004 /* AIF1DAC1_DRC_ENA */ +#define WM8994_AIF1DAC1_DRC_ENA_MASK 0x0004 /* AIF1DAC1_DRC_ENA */ +#define WM8994_AIF1DAC1_DRC_ENA_SHIFT 2 /* AIF1DAC1_DRC_ENA */ +#define WM8994_AIF1DAC1_DRC_ENA_WIDTH 1 /* AIF1DAC1_DRC_ENA */ +#define WM8994_AIF1ADC1L_DRC_ENA 0x0002 /* AIF1ADC1L_DRC_ENA */ +#define WM8994_AIF1ADC1L_DRC_ENA_MASK 0x0002 /* AIF1ADC1L_DRC_ENA */ +#define WM8994_AIF1ADC1L_DRC_ENA_SHIFT 1 /* AIF1ADC1L_DRC_ENA */ +#define WM8994_AIF1ADC1L_DRC_ENA_WIDTH 1 /* AIF1ADC1L_DRC_ENA */ +#define WM8994_AIF1ADC1R_DRC_ENA 0x0001 /* AIF1ADC1R_DRC_ENA */ +#define WM8994_AIF1ADC1R_DRC_ENA_MASK 0x0001 /* AIF1ADC1R_DRC_ENA */ +#define WM8994_AIF1ADC1R_DRC_ENA_SHIFT 0 /* AIF1ADC1R_DRC_ENA */ +#define WM8994_AIF1ADC1R_DRC_ENA_WIDTH 1 /* AIF1ADC1R_DRC_ENA */ + +/* + * R1089 (0x441) - AIF1 DRC1 (2) + */ +#define WM8994_AIF1DRC1_ATK_MASK 0x1E00 /* AIF1DRC1_ATK - [12:9] */ +#define WM8994_AIF1DRC1_ATK_SHIFT 9 /* AIF1DRC1_ATK - [12:9] */ +#define WM8994_AIF1DRC1_ATK_WIDTH 4 /* AIF1DRC1_ATK - [12:9] */ +#define WM8994_AIF1DRC1_DCY_MASK 0x01E0 /* AIF1DRC1_DCY - [8:5] */ +#define WM8994_AIF1DRC1_DCY_SHIFT 5 /* AIF1DRC1_DCY - [8:5] */ +#define WM8994_AIF1DRC1_DCY_WIDTH 4 /* AIF1DRC1_DCY - [8:5] */ +#define WM8994_AIF1DRC1_MINGAIN_MASK 0x001C /* AIF1DRC1_MINGAIN - [4:2] */ +#define WM8994_AIF1DRC1_MINGAIN_SHIFT 2 /* AIF1DRC1_MINGAIN - [4:2] */ +#define WM8994_AIF1DRC1_MINGAIN_WIDTH 3 /* AIF1DRC1_MINGAIN - [4:2] */ +#define WM8994_AIF1DRC1_MAXGAIN_MASK 0x0003 /* AIF1DRC1_MAXGAIN - [1:0] */ +#define WM8994_AIF1DRC1_MAXGAIN_SHIFT 0 /* AIF1DRC1_MAXGAIN - [1:0] */ +#define WM8994_AIF1DRC1_MAXGAIN_WIDTH 2 /* AIF1DRC1_MAXGAIN - [1:0] */ + +/* + * R1090 (0x442) - AIF1 DRC1 (3) + */ +#define WM8994_AIF1DRC1_NG_MINGAIN_MASK 0xF000 /* AIF1DRC1_NG_MINGAIN - [15:12] */ +#define WM8994_AIF1DRC1_NG_MINGAIN_SHIFT 12 /* AIF1DRC1_NG_MINGAIN - [15:12] */ +#define WM8994_AIF1DRC1_NG_MINGAIN_WIDTH 4 /* AIF1DRC1_NG_MINGAIN - [15:12] */ +#define WM8994_AIF1DRC1_NG_EXP_MASK 0x0C00 /* AIF1DRC1_NG_EXP - [11:10] */ +#define WM8994_AIF1DRC1_NG_EXP_SHIFT 10 /* AIF1DRC1_NG_EXP - [11:10] */ +#define WM8994_AIF1DRC1_NG_EXP_WIDTH 2 /* AIF1DRC1_NG_EXP - [11:10] */ +#define WM8994_AIF1DRC1_QR_THR_MASK 0x0300 /* AIF1DRC1_QR_THR - [9:8] */ +#define WM8994_AIF1DRC1_QR_THR_SHIFT 8 /* AIF1DRC1_QR_THR - [9:8] */ +#define WM8994_AIF1DRC1_QR_THR_WIDTH 2 /* AIF1DRC1_QR_THR - [9:8] */ +#define WM8994_AIF1DRC1_QR_DCY_MASK 0x00C0 /* AIF1DRC1_QR_DCY - [7:6] */ +#define WM8994_AIF1DRC1_QR_DCY_SHIFT 6 /* AIF1DRC1_QR_DCY - [7:6] */ +#define WM8994_AIF1DRC1_QR_DCY_WIDTH 2 /* AIF1DRC1_QR_DCY - [7:6] */ +#define WM8994_AIF1DRC1_HI_COMP_MASK 0x0038 /* AIF1DRC1_HI_COMP - [5:3] */ +#define WM8994_AIF1DRC1_HI_COMP_SHIFT 3 /* AIF1DRC1_HI_COMP - [5:3] */ +#define WM8994_AIF1DRC1_HI_COMP_WIDTH 3 /* AIF1DRC1_HI_COMP - [5:3] */ +#define WM8994_AIF1DRC1_LO_COMP_MASK 0x0007 /* AIF1DRC1_LO_COMP - [2:0] */ +#define WM8994_AIF1DRC1_LO_COMP_SHIFT 0 /* AIF1DRC1_LO_COMP - [2:0] */ +#define WM8994_AIF1DRC1_LO_COMP_WIDTH 3 /* AIF1DRC1_LO_COMP - [2:0] */ + +/* + * R1091 (0x443) - AIF1 DRC1 (4) + */ +#define WM8994_AIF1DRC1_KNEE_IP_MASK 0x07E0 /* AIF1DRC1_KNEE_IP - [10:5] */ +#define WM8994_AIF1DRC1_KNEE_IP_SHIFT 5 /* AIF1DRC1_KNEE_IP - [10:5] */ +#define WM8994_AIF1DRC1_KNEE_IP_WIDTH 6 /* AIF1DRC1_KNEE_IP - [10:5] */ +#define WM8994_AIF1DRC1_KNEE_OP_MASK 0x001F /* AIF1DRC1_KNEE_OP - [4:0] */ +#define WM8994_AIF1DRC1_KNEE_OP_SHIFT 0 /* AIF1DRC1_KNEE_OP - [4:0] */ +#define WM8994_AIF1DRC1_KNEE_OP_WIDTH 5 /* AIF1DRC1_KNEE_OP - [4:0] */ + +/* + * R1092 (0x444) - AIF1 DRC1 (5) + */ +#define WM8994_AIF1DRC1_KNEE2_IP_MASK 0x03E0 /* AIF1DRC1_KNEE2_IP - [9:5] */ +#define WM8994_AIF1DRC1_KNEE2_IP_SHIFT 5 /* AIF1DRC1_KNEE2_IP - [9:5] */ +#define WM8994_AIF1DRC1_KNEE2_IP_WIDTH 5 /* AIF1DRC1_KNEE2_IP - [9:5] */ +#define WM8994_AIF1DRC1_KNEE2_OP_MASK 0x001F /* AIF1DRC1_KNEE2_OP - [4:0] */ +#define WM8994_AIF1DRC1_KNEE2_OP_SHIFT 0 /* AIF1DRC1_KNEE2_OP - [4:0] */ +#define WM8994_AIF1DRC1_KNEE2_OP_WIDTH 5 /* AIF1DRC1_KNEE2_OP - [4:0] */ + +/* + * R1104 (0x450) - AIF1 DRC2 (1) + */ +#define WM8994_AIF1DRC2_SIG_DET_RMS_MASK 0xF800 /* AIF1DRC2_SIG_DET_RMS - [15:11] */ +#define WM8994_AIF1DRC2_SIG_DET_RMS_SHIFT 11 /* AIF1DRC2_SIG_DET_RMS - [15:11] */ +#define WM8994_AIF1DRC2_SIG_DET_RMS_WIDTH 5 /* AIF1DRC2_SIG_DET_RMS - [15:11] */ +#define WM8994_AIF1DRC2_SIG_DET_PK_MASK 0x0600 /* AIF1DRC2_SIG_DET_PK - [10:9] */ +#define WM8994_AIF1DRC2_SIG_DET_PK_SHIFT 9 /* AIF1DRC2_SIG_DET_PK - [10:9] */ +#define WM8994_AIF1DRC2_SIG_DET_PK_WIDTH 2 /* AIF1DRC2_SIG_DET_PK - [10:9] */ +#define WM8994_AIF1DRC2_NG_ENA 0x0100 /* AIF1DRC2_NG_ENA */ +#define WM8994_AIF1DRC2_NG_ENA_MASK 0x0100 /* AIF1DRC2_NG_ENA */ +#define WM8994_AIF1DRC2_NG_ENA_SHIFT 8 /* AIF1DRC2_NG_ENA */ +#define WM8994_AIF1DRC2_NG_ENA_WIDTH 1 /* AIF1DRC2_NG_ENA */ +#define WM8994_AIF1DRC2_SIG_DET_MODE 0x0080 /* AIF1DRC2_SIG_DET_MODE */ +#define WM8994_AIF1DRC2_SIG_DET_MODE_MASK 0x0080 /* AIF1DRC2_SIG_DET_MODE */ +#define WM8994_AIF1DRC2_SIG_DET_MODE_SHIFT 7 /* AIF1DRC2_SIG_DET_MODE */ +#define WM8994_AIF1DRC2_SIG_DET_MODE_WIDTH 1 /* AIF1DRC2_SIG_DET_MODE */ +#define WM8994_AIF1DRC2_SIG_DET 0x0040 /* AIF1DRC2_SIG_DET */ +#define WM8994_AIF1DRC2_SIG_DET_MASK 0x0040 /* AIF1DRC2_SIG_DET */ +#define WM8994_AIF1DRC2_SIG_DET_SHIFT 6 /* AIF1DRC2_SIG_DET */ +#define WM8994_AIF1DRC2_SIG_DET_WIDTH 1 /* AIF1DRC2_SIG_DET */ +#define WM8994_AIF1DRC2_KNEE2_OP_ENA 0x0020 /* AIF1DRC2_KNEE2_OP_ENA */ +#define WM8994_AIF1DRC2_KNEE2_OP_ENA_MASK 0x0020 /* AIF1DRC2_KNEE2_OP_ENA */ +#define WM8994_AIF1DRC2_KNEE2_OP_ENA_SHIFT 5 /* AIF1DRC2_KNEE2_OP_ENA */ +#define WM8994_AIF1DRC2_KNEE2_OP_ENA_WIDTH 1 /* AIF1DRC2_KNEE2_OP_ENA */ +#define WM8994_AIF1DRC2_QR 0x0010 /* AIF1DRC2_QR */ +#define WM8994_AIF1DRC2_QR_MASK 0x0010 /* AIF1DRC2_QR */ +#define WM8994_AIF1DRC2_QR_SHIFT 4 /* AIF1DRC2_QR */ +#define WM8994_AIF1DRC2_QR_WIDTH 1 /* AIF1DRC2_QR */ +#define WM8994_AIF1DRC2_ANTICLIP 0x0008 /* AIF1DRC2_ANTICLIP */ +#define WM8994_AIF1DRC2_ANTICLIP_MASK 0x0008 /* AIF1DRC2_ANTICLIP */ +#define WM8994_AIF1DRC2_ANTICLIP_SHIFT 3 /* AIF1DRC2_ANTICLIP */ +#define WM8994_AIF1DRC2_ANTICLIP_WIDTH 1 /* AIF1DRC2_ANTICLIP */ +#define WM8994_AIF1DAC2_DRC_ENA 0x0004 /* AIF1DAC2_DRC_ENA */ +#define WM8994_AIF1DAC2_DRC_ENA_MASK 0x0004 /* AIF1DAC2_DRC_ENA */ +#define WM8994_AIF1DAC2_DRC_ENA_SHIFT 2 /* AIF1DAC2_DRC_ENA */ +#define WM8994_AIF1DAC2_DRC_ENA_WIDTH 1 /* AIF1DAC2_DRC_ENA */ +#define WM8994_AIF1ADC2L_DRC_ENA 0x0002 /* AIF1ADC2L_DRC_ENA */ +#define WM8994_AIF1ADC2L_DRC_ENA_MASK 0x0002 /* AIF1ADC2L_DRC_ENA */ +#define WM8994_AIF1ADC2L_DRC_ENA_SHIFT 1 /* AIF1ADC2L_DRC_ENA */ +#define WM8994_AIF1ADC2L_DRC_ENA_WIDTH 1 /* AIF1ADC2L_DRC_ENA */ +#define WM8994_AIF1ADC2R_DRC_ENA 0x0001 /* AIF1ADC2R_DRC_ENA */ +#define WM8994_AIF1ADC2R_DRC_ENA_MASK 0x0001 /* AIF1ADC2R_DRC_ENA */ +#define WM8994_AIF1ADC2R_DRC_ENA_SHIFT 0 /* AIF1ADC2R_DRC_ENA */ +#define WM8994_AIF1ADC2R_DRC_ENA_WIDTH 1 /* AIF1ADC2R_DRC_ENA */ + +/* + * R1105 (0x451) - AIF1 DRC2 (2) + */ +#define WM8994_AIF1DRC2_ATK_MASK 0x1E00 /* AIF1DRC2_ATK - [12:9] */ +#define WM8994_AIF1DRC2_ATK_SHIFT 9 /* AIF1DRC2_ATK - [12:9] */ +#define WM8994_AIF1DRC2_ATK_WIDTH 4 /* AIF1DRC2_ATK - [12:9] */ +#define WM8994_AIF1DRC2_DCY_MASK 0x01E0 /* AIF1DRC2_DCY - [8:5] */ +#define WM8994_AIF1DRC2_DCY_SHIFT 5 /* AIF1DRC2_DCY - [8:5] */ +#define WM8994_AIF1DRC2_DCY_WIDTH 4 /* AIF1DRC2_DCY - [8:5] */ +#define WM8994_AIF1DRC2_MINGAIN_MASK 0x001C /* AIF1DRC2_MINGAIN - [4:2] */ +#define WM8994_AIF1DRC2_MINGAIN_SHIFT 2 /* AIF1DRC2_MINGAIN - [4:2] */ +#define WM8994_AIF1DRC2_MINGAIN_WIDTH 3 /* AIF1DRC2_MINGAIN - [4:2] */ +#define WM8994_AIF1DRC2_MAXGAIN_MASK 0x0003 /* AIF1DRC2_MAXGAIN - [1:0] */ +#define WM8994_AIF1DRC2_MAXGAIN_SHIFT 0 /* AIF1DRC2_MAXGAIN - [1:0] */ +#define WM8994_AIF1DRC2_MAXGAIN_WIDTH 2 /* AIF1DRC2_MAXGAIN - [1:0] */ + +/* + * R1106 (0x452) - AIF1 DRC2 (3) + */ +#define WM8994_AIF1DRC2_NG_MINGAIN_MASK 0xF000 /* AIF1DRC2_NG_MINGAIN - [15:12] */ +#define WM8994_AIF1DRC2_NG_MINGAIN_SHIFT 12 /* AIF1DRC2_NG_MINGAIN - [15:12] */ +#define WM8994_AIF1DRC2_NG_MINGAIN_WIDTH 4 /* AIF1DRC2_NG_MINGAIN - [15:12] */ +#define WM8994_AIF1DRC2_NG_EXP_MASK 0x0C00 /* AIF1DRC2_NG_EXP - [11:10] */ +#define WM8994_AIF1DRC2_NG_EXP_SHIFT 10 /* AIF1DRC2_NG_EXP - [11:10] */ +#define WM8994_AIF1DRC2_NG_EXP_WIDTH 2 /* AIF1DRC2_NG_EXP - [11:10] */ +#define WM8994_AIF1DRC2_QR_THR_MASK 0x0300 /* AIF1DRC2_QR_THR - [9:8] */ +#define WM8994_AIF1DRC2_QR_THR_SHIFT 8 /* AIF1DRC2_QR_THR - [9:8] */ +#define WM8994_AIF1DRC2_QR_THR_WIDTH 2 /* AIF1DRC2_QR_THR - [9:8] */ +#define WM8994_AIF1DRC2_QR_DCY_MASK 0x00C0 /* AIF1DRC2_QR_DCY - [7:6] */ +#define WM8994_AIF1DRC2_QR_DCY_SHIFT 6 /* AIF1DRC2_QR_DCY - [7:6] */ +#define WM8994_AIF1DRC2_QR_DCY_WIDTH 2 /* AIF1DRC2_QR_DCY - [7:6] */ +#define WM8994_AIF1DRC2_HI_COMP_MASK 0x0038 /* AIF1DRC2_HI_COMP - [5:3] */ +#define WM8994_AIF1DRC2_HI_COMP_SHIFT 3 /* AIF1DRC2_HI_COMP - [5:3] */ +#define WM8994_AIF1DRC2_HI_COMP_WIDTH 3 /* AIF1DRC2_HI_COMP - [5:3] */ +#define WM8994_AIF1DRC2_LO_COMP_MASK 0x0007 /* AIF1DRC2_LO_COMP - [2:0] */ +#define WM8994_AIF1DRC2_LO_COMP_SHIFT 0 /* AIF1DRC2_LO_COMP - [2:0] */ +#define WM8994_AIF1DRC2_LO_COMP_WIDTH 3 /* AIF1DRC2_LO_COMP - [2:0] */ + +/* + * R1107 (0x453) - AIF1 DRC2 (4) + */ +#define WM8994_AIF1DRC2_KNEE_IP_MASK 0x07E0 /* AIF1DRC2_KNEE_IP - [10:5] */ +#define WM8994_AIF1DRC2_KNEE_IP_SHIFT 5 /* AIF1DRC2_KNEE_IP - [10:5] */ +#define WM8994_AIF1DRC2_KNEE_IP_WIDTH 6 /* AIF1DRC2_KNEE_IP - [10:5] */ +#define WM8994_AIF1DRC2_KNEE_OP_MASK 0x001F /* AIF1DRC2_KNEE_OP - [4:0] */ +#define WM8994_AIF1DRC2_KNEE_OP_SHIFT 0 /* AIF1DRC2_KNEE_OP - [4:0] */ +#define WM8994_AIF1DRC2_KNEE_OP_WIDTH 5 /* AIF1DRC2_KNEE_OP - [4:0] */ + +/* + * R1108 (0x454) - AIF1 DRC2 (5) + */ +#define WM8994_AIF1DRC2_KNEE2_IP_MASK 0x03E0 /* AIF1DRC2_KNEE2_IP - [9:5] */ +#define WM8994_AIF1DRC2_KNEE2_IP_SHIFT 5 /* AIF1DRC2_KNEE2_IP - [9:5] */ +#define WM8994_AIF1DRC2_KNEE2_IP_WIDTH 5 /* AIF1DRC2_KNEE2_IP - [9:5] */ +#define WM8994_AIF1DRC2_KNEE2_OP_MASK 0x001F /* AIF1DRC2_KNEE2_OP - [4:0] */ +#define WM8994_AIF1DRC2_KNEE2_OP_SHIFT 0 /* AIF1DRC2_KNEE2_OP - [4:0] */ +#define WM8994_AIF1DRC2_KNEE2_OP_WIDTH 5 /* AIF1DRC2_KNEE2_OP - [4:0] */ + +/* + * R1152 (0x480) - AIF1 DAC1 EQ Gains (1) + */ +#define WM8994_AIF1DAC1_EQ_B1_GAIN_MASK 0xF800 /* AIF1DAC1_EQ_B1_GAIN - [15:11] */ +#define WM8994_AIF1DAC1_EQ_B1_GAIN_SHIFT 11 /* AIF1DAC1_EQ_B1_GAIN - [15:11] */ +#define WM8994_AIF1DAC1_EQ_B1_GAIN_WIDTH 5 /* AIF1DAC1_EQ_B1_GAIN - [15:11] */ +#define WM8994_AIF1DAC1_EQ_B2_GAIN_MASK 0x07C0 /* AIF1DAC1_EQ_B2_GAIN - [10:6] */ +#define WM8994_AIF1DAC1_EQ_B2_GAIN_SHIFT 6 /* AIF1DAC1_EQ_B2_GAIN - [10:6] */ +#define WM8994_AIF1DAC1_EQ_B2_GAIN_WIDTH 5 /* AIF1DAC1_EQ_B2_GAIN - [10:6] */ +#define WM8994_AIF1DAC1_EQ_B3_GAIN_MASK 0x003E /* AIF1DAC1_EQ_B3_GAIN - [5:1] */ +#define WM8994_AIF1DAC1_EQ_B3_GAIN_SHIFT 1 /* AIF1DAC1_EQ_B3_GAIN - [5:1] */ +#define WM8994_AIF1DAC1_EQ_B3_GAIN_WIDTH 5 /* AIF1DAC1_EQ_B3_GAIN - [5:1] */ +#define WM8994_AIF1DAC1_EQ_ENA 0x0001 /* AIF1DAC1_EQ_ENA */ +#define WM8994_AIF1DAC1_EQ_ENA_MASK 0x0001 /* AIF1DAC1_EQ_ENA */ +#define WM8994_AIF1DAC1_EQ_ENA_SHIFT 0 /* AIF1DAC1_EQ_ENA */ +#define WM8994_AIF1DAC1_EQ_ENA_WIDTH 1 /* AIF1DAC1_EQ_ENA */ + +/* + * R1153 (0x481) - AIF1 DAC1 EQ Gains (2) + */ +#define WM8994_AIF1DAC1_EQ_B4_GAIN_MASK 0xF800 /* AIF1DAC1_EQ_B4_GAIN - [15:11] */ +#define WM8994_AIF1DAC1_EQ_B4_GAIN_SHIFT 11 /* AIF1DAC1_EQ_B4_GAIN - [15:11] */ +#define WM8994_AIF1DAC1_EQ_B4_GAIN_WIDTH 5 /* AIF1DAC1_EQ_B4_GAIN - [15:11] */ +#define WM8994_AIF1DAC1_EQ_B5_GAIN_MASK 0x07C0 /* AIF1DAC1_EQ_B5_GAIN - [10:6] */ +#define WM8994_AIF1DAC1_EQ_B5_GAIN_SHIFT 6 /* AIF1DAC1_EQ_B5_GAIN - [10:6] */ +#define WM8994_AIF1DAC1_EQ_B5_GAIN_WIDTH 5 /* AIF1DAC1_EQ_B5_GAIN - [10:6] */ + +/* + * R1154 (0x482) - AIF1 DAC1 EQ Band 1 A + */ +#define WM8994_AIF1DAC1_EQ_B1_A_MASK 0xFFFF /* AIF1DAC1_EQ_B1_A - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B1_A_SHIFT 0 /* AIF1DAC1_EQ_B1_A - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B1_A_WIDTH 16 /* AIF1DAC1_EQ_B1_A - [15:0] */ + +/* + * R1155 (0x483) - AIF1 DAC1 EQ Band 1 B + */ +#define WM8994_AIF1DAC1_EQ_B1_B_MASK 0xFFFF /* AIF1DAC1_EQ_B1_B - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B1_B_SHIFT 0 /* AIF1DAC1_EQ_B1_B - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B1_B_WIDTH 16 /* AIF1DAC1_EQ_B1_B - [15:0] */ + +/* + * R1156 (0x484) - AIF1 DAC1 EQ Band 1 PG + */ +#define WM8994_AIF1DAC1_EQ_B1_PG_MASK 0xFFFF /* AIF1DAC1_EQ_B1_PG - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B1_PG_SHIFT 0 /* AIF1DAC1_EQ_B1_PG - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B1_PG_WIDTH 16 /* AIF1DAC1_EQ_B1_PG - [15:0] */ + +/* + * R1157 (0x485) - AIF1 DAC1 EQ Band 2 A + */ +#define WM8994_AIF1DAC1_EQ_B2_A_MASK 0xFFFF /* AIF1DAC1_EQ_B2_A - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B2_A_SHIFT 0 /* AIF1DAC1_EQ_B2_A - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B2_A_WIDTH 16 /* AIF1DAC1_EQ_B2_A - [15:0] */ + +/* + * R1158 (0x486) - AIF1 DAC1 EQ Band 2 B + */ +#define WM8994_AIF1DAC1_EQ_B2_B_MASK 0xFFFF /* AIF1DAC1_EQ_B2_B - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B2_B_SHIFT 0 /* AIF1DAC1_EQ_B2_B - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B2_B_WIDTH 16 /* AIF1DAC1_EQ_B2_B - [15:0] */ + +/* + * R1159 (0x487) - AIF1 DAC1 EQ Band 2 C + */ +#define WM8994_AIF1DAC1_EQ_B2_C_MASK 0xFFFF /* AIF1DAC1_EQ_B2_C - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B2_C_SHIFT 0 /* AIF1DAC1_EQ_B2_C - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B2_C_WIDTH 16 /* AIF1DAC1_EQ_B2_C - [15:0] */ + +/* + * R1160 (0x488) - AIF1 DAC1 EQ Band 2 PG + */ +#define WM8994_AIF1DAC1_EQ_B2_PG_MASK 0xFFFF /* AIF1DAC1_EQ_B2_PG - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B2_PG_SHIFT 0 /* AIF1DAC1_EQ_B2_PG - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B2_PG_WIDTH 16 /* AIF1DAC1_EQ_B2_PG - [15:0] */ + +/* + * R1161 (0x489) - AIF1 DAC1 EQ Band 3 A + */ +#define WM8994_AIF1DAC1_EQ_B3_A_MASK 0xFFFF /* AIF1DAC1_EQ_B3_A - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B3_A_SHIFT 0 /* AIF1DAC1_EQ_B3_A - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B3_A_WIDTH 16 /* AIF1DAC1_EQ_B3_A - [15:0] */ + +/* + * R1162 (0x48A) - AIF1 DAC1 EQ Band 3 B + */ +#define WM8994_AIF1DAC1_EQ_B3_B_MASK 0xFFFF /* AIF1DAC1_EQ_B3_B - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B3_B_SHIFT 0 /* AIF1DAC1_EQ_B3_B - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B3_B_WIDTH 16 /* AIF1DAC1_EQ_B3_B - [15:0] */ + +/* + * R1163 (0x48B) - AIF1 DAC1 EQ Band 3 C + */ +#define WM8994_AIF1DAC1_EQ_B3_C_MASK 0xFFFF /* AIF1DAC1_EQ_B3_C - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B3_C_SHIFT 0 /* AIF1DAC1_EQ_B3_C - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B3_C_WIDTH 16 /* AIF1DAC1_EQ_B3_C - [15:0] */ + +/* + * R1164 (0x48C) - AIF1 DAC1 EQ Band 3 PG + */ +#define WM8994_AIF1DAC1_EQ_B3_PG_MASK 0xFFFF /* AIF1DAC1_EQ_B3_PG - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B3_PG_SHIFT 0 /* AIF1DAC1_EQ_B3_PG - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B3_PG_WIDTH 16 /* AIF1DAC1_EQ_B3_PG - [15:0] */ + +/* + * R1165 (0x48D) - AIF1 DAC1 EQ Band 4 A + */ +#define WM8994_AIF1DAC1_EQ_B4_A_MASK 0xFFFF /* AIF1DAC1_EQ_B4_A - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B4_A_SHIFT 0 /* AIF1DAC1_EQ_B4_A - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B4_A_WIDTH 16 /* AIF1DAC1_EQ_B4_A - [15:0] */ + +/* + * R1166 (0x48E) - AIF1 DAC1 EQ Band 4 B + */ +#define WM8994_AIF1DAC1_EQ_B4_B_MASK 0xFFFF /* AIF1DAC1_EQ_B4_B - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B4_B_SHIFT 0 /* AIF1DAC1_EQ_B4_B - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B4_B_WIDTH 16 /* AIF1DAC1_EQ_B4_B - [15:0] */ + +/* + * R1167 (0x48F) - AIF1 DAC1 EQ Band 4 C + */ +#define WM8994_AIF1DAC1_EQ_B4_C_MASK 0xFFFF /* AIF1DAC1_EQ_B4_C - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B4_C_SHIFT 0 /* AIF1DAC1_EQ_B4_C - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B4_C_WIDTH 16 /* AIF1DAC1_EQ_B4_C - [15:0] */ + +/* + * R1168 (0x490) - AIF1 DAC1 EQ Band 4 PG + */ +#define WM8994_AIF1DAC1_EQ_B4_PG_MASK 0xFFFF /* AIF1DAC1_EQ_B4_PG - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B4_PG_SHIFT 0 /* AIF1DAC1_EQ_B4_PG - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B4_PG_WIDTH 16 /* AIF1DAC1_EQ_B4_PG - [15:0] */ + +/* + * R1169 (0x491) - AIF1 DAC1 EQ Band 5 A + */ +#define WM8994_AIF1DAC1_EQ_B5_A_MASK 0xFFFF /* AIF1DAC1_EQ_B5_A - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B5_A_SHIFT 0 /* AIF1DAC1_EQ_B5_A - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B5_A_WIDTH 16 /* AIF1DAC1_EQ_B5_A - [15:0] */ + +/* + * R1170 (0x492) - AIF1 DAC1 EQ Band 5 B + */ +#define WM8994_AIF1DAC1_EQ_B5_B_MASK 0xFFFF /* AIF1DAC1_EQ_B5_B - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B5_B_SHIFT 0 /* AIF1DAC1_EQ_B5_B - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B5_B_WIDTH 16 /* AIF1DAC1_EQ_B5_B - [15:0] */ + +/* + * R1171 (0x493) - AIF1 DAC1 EQ Band 5 PG + */ +#define WM8994_AIF1DAC1_EQ_B5_PG_MASK 0xFFFF /* AIF1DAC1_EQ_B5_PG - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B5_PG_SHIFT 0 /* AIF1DAC1_EQ_B5_PG - [15:0] */ +#define WM8994_AIF1DAC1_EQ_B5_PG_WIDTH 16 /* AIF1DAC1_EQ_B5_PG - [15:0] */ + +/* + * R1184 (0x4A0) - AIF1 DAC2 EQ Gains (1) + */ +#define WM8994_AIF1DAC2_EQ_B1_GAIN_MASK 0xF800 /* AIF1DAC2_EQ_B1_GAIN - [15:11] */ +#define WM8994_AIF1DAC2_EQ_B1_GAIN_SHIFT 11 /* AIF1DAC2_EQ_B1_GAIN - [15:11] */ +#define WM8994_AIF1DAC2_EQ_B1_GAIN_WIDTH 5 /* AIF1DAC2_EQ_B1_GAIN - [15:11] */ +#define WM8994_AIF1DAC2_EQ_B2_GAIN_MASK 0x07C0 /* AIF1DAC2_EQ_B2_GAIN - [10:6] */ +#define WM8994_AIF1DAC2_EQ_B2_GAIN_SHIFT 6 /* AIF1DAC2_EQ_B2_GAIN - [10:6] */ +#define WM8994_AIF1DAC2_EQ_B2_GAIN_WIDTH 5 /* AIF1DAC2_EQ_B2_GAIN - [10:6] */ +#define WM8994_AIF1DAC2_EQ_B3_GAIN_MASK 0x003E /* AIF1DAC2_EQ_B3_GAIN - [5:1] */ +#define WM8994_AIF1DAC2_EQ_B3_GAIN_SHIFT 1 /* AIF1DAC2_EQ_B3_GAIN - [5:1] */ +#define WM8994_AIF1DAC2_EQ_B3_GAIN_WIDTH 5 /* AIF1DAC2_EQ_B3_GAIN - [5:1] */ +#define WM8994_AIF1DAC2_EQ_ENA 0x0001 /* AIF1DAC2_EQ_ENA */ +#define WM8994_AIF1DAC2_EQ_ENA_MASK 0x0001 /* AIF1DAC2_EQ_ENA */ +#define WM8994_AIF1DAC2_EQ_ENA_SHIFT 0 /* AIF1DAC2_EQ_ENA */ +#define WM8994_AIF1DAC2_EQ_ENA_WIDTH 1 /* AIF1DAC2_EQ_ENA */ + +/* + * R1185 (0x4A1) - AIF1 DAC2 EQ Gains (2) + */ +#define WM8994_AIF1DAC2_EQ_B4_GAIN_MASK 0xF800 /* AIF1DAC2_EQ_B4_GAIN - [15:11] */ +#define WM8994_AIF1DAC2_EQ_B4_GAIN_SHIFT 11 /* AIF1DAC2_EQ_B4_GAIN - [15:11] */ +#define WM8994_AIF1DAC2_EQ_B4_GAIN_WIDTH 5 /* AIF1DAC2_EQ_B4_GAIN - [15:11] */ +#define WM8994_AIF1DAC2_EQ_B5_GAIN_MASK 0x07C0 /* AIF1DAC2_EQ_B5_GAIN - [10:6] */ +#define WM8994_AIF1DAC2_EQ_B5_GAIN_SHIFT 6 /* AIF1DAC2_EQ_B5_GAIN - [10:6] */ +#define WM8994_AIF1DAC2_EQ_B5_GAIN_WIDTH 5 /* AIF1DAC2_EQ_B5_GAIN - [10:6] */ + +/* + * R1186 (0x4A2) - AIF1 DAC2 EQ Band 1 A + */ +#define WM8994_AIF1DAC2_EQ_B1_A_MASK 0xFFFF /* AIF1DAC2_EQ_B1_A - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B1_A_SHIFT 0 /* AIF1DAC2_EQ_B1_A - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B1_A_WIDTH 16 /* AIF1DAC2_EQ_B1_A - [15:0] */ + +/* + * R1187 (0x4A3) - AIF1 DAC2 EQ Band 1 B + */ +#define WM8994_AIF1DAC2_EQ_B1_B_MASK 0xFFFF /* AIF1DAC2_EQ_B1_B - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B1_B_SHIFT 0 /* AIF1DAC2_EQ_B1_B - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B1_B_WIDTH 16 /* AIF1DAC2_EQ_B1_B - [15:0] */ + +/* + * R1188 (0x4A4) - AIF1 DAC2 EQ Band 1 PG + */ +#define WM8994_AIF1DAC2_EQ_B1_PG_MASK 0xFFFF /* AIF1DAC2_EQ_B1_PG - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B1_PG_SHIFT 0 /* AIF1DAC2_EQ_B1_PG - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B1_PG_WIDTH 16 /* AIF1DAC2_EQ_B1_PG - [15:0] */ + +/* + * R1189 (0x4A5) - AIF1 DAC2 EQ Band 2 A + */ +#define WM8994_AIF1DAC2_EQ_B2_A_MASK 0xFFFF /* AIF1DAC2_EQ_B2_A - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B2_A_SHIFT 0 /* AIF1DAC2_EQ_B2_A - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B2_A_WIDTH 16 /* AIF1DAC2_EQ_B2_A - [15:0] */ + +/* + * R1190 (0x4A6) - AIF1 DAC2 EQ Band 2 B + */ +#define WM8994_AIF1DAC2_EQ_B2_B_MASK 0xFFFF /* AIF1DAC2_EQ_B2_B - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B2_B_SHIFT 0 /* AIF1DAC2_EQ_B2_B - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B2_B_WIDTH 16 /* AIF1DAC2_EQ_B2_B - [15:0] */ + +/* + * R1191 (0x4A7) - AIF1 DAC2 EQ Band 2 C + */ +#define WM8994_AIF1DAC2_EQ_B2_C_MASK 0xFFFF /* AIF1DAC2_EQ_B2_C - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B2_C_SHIFT 0 /* AIF1DAC2_EQ_B2_C - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B2_C_WIDTH 16 /* AIF1DAC2_EQ_B2_C - [15:0] */ + +/* + * R1192 (0x4A8) - AIF1 DAC2 EQ Band 2 PG + */ +#define WM8994_AIF1DAC2_EQ_B2_PG_MASK 0xFFFF /* AIF1DAC2_EQ_B2_PG - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B2_PG_SHIFT 0 /* AIF1DAC2_EQ_B2_PG - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B2_PG_WIDTH 16 /* AIF1DAC2_EQ_B2_PG - [15:0] */ + +/* + * R1193 (0x4A9) - AIF1 DAC2 EQ Band 3 A + */ +#define WM8994_AIF1DAC2_EQ_B3_A_MASK 0xFFFF /* AIF1DAC2_EQ_B3_A - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B3_A_SHIFT 0 /* AIF1DAC2_EQ_B3_A - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B3_A_WIDTH 16 /* AIF1DAC2_EQ_B3_A - [15:0] */ + +/* + * R1194 (0x4AA) - AIF1 DAC2 EQ Band 3 B + */ +#define WM8994_AIF1DAC2_EQ_B3_B_MASK 0xFFFF /* AIF1DAC2_EQ_B3_B - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B3_B_SHIFT 0 /* AIF1DAC2_EQ_B3_B - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B3_B_WIDTH 16 /* AIF1DAC2_EQ_B3_B - [15:0] */ + +/* + * R1195 (0x4AB) - AIF1 DAC2 EQ Band 3 C + */ +#define WM8994_AIF1DAC2_EQ_B3_C_MASK 0xFFFF /* AIF1DAC2_EQ_B3_C - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B3_C_SHIFT 0 /* AIF1DAC2_EQ_B3_C - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B3_C_WIDTH 16 /* AIF1DAC2_EQ_B3_C - [15:0] */ + +/* + * R1196 (0x4AC) - AIF1 DAC2 EQ Band 3 PG + */ +#define WM8994_AIF1DAC2_EQ_B3_PG_MASK 0xFFFF /* AIF1DAC2_EQ_B3_PG - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B3_PG_SHIFT 0 /* AIF1DAC2_EQ_B3_PG - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B3_PG_WIDTH 16 /* AIF1DAC2_EQ_B3_PG - [15:0] */ + +/* + * R1197 (0x4AD) - AIF1 DAC2 EQ Band 4 A + */ +#define WM8994_AIF1DAC2_EQ_B4_A_MASK 0xFFFF /* AIF1DAC2_EQ_B4_A - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B4_A_SHIFT 0 /* AIF1DAC2_EQ_B4_A - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B4_A_WIDTH 16 /* AIF1DAC2_EQ_B4_A - [15:0] */ + +/* + * R1198 (0x4AE) - AIF1 DAC2 EQ Band 4 B + */ +#define WM8994_AIF1DAC2_EQ_B4_B_MASK 0xFFFF /* AIF1DAC2_EQ_B4_B - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B4_B_SHIFT 0 /* AIF1DAC2_EQ_B4_B - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B4_B_WIDTH 16 /* AIF1DAC2_EQ_B4_B - [15:0] */ + +/* + * R1199 (0x4AF) - AIF1 DAC2 EQ Band 4 C + */ +#define WM8994_AIF1DAC2_EQ_B4_C_MASK 0xFFFF /* AIF1DAC2_EQ_B4_C - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B4_C_SHIFT 0 /* AIF1DAC2_EQ_B4_C - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B4_C_WIDTH 16 /* AIF1DAC2_EQ_B4_C - [15:0] */ + +/* + * R1200 (0x4B0) - AIF1 DAC2 EQ Band 4 PG + */ +#define WM8994_AIF1DAC2_EQ_B4_PG_MASK 0xFFFF /* AIF1DAC2_EQ_B4_PG - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B4_PG_SHIFT 0 /* AIF1DAC2_EQ_B4_PG - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B4_PG_WIDTH 16 /* AIF1DAC2_EQ_B4_PG - [15:0] */ + +/* + * R1201 (0x4B1) - AIF1 DAC2 EQ Band 5 A + */ +#define WM8994_AIF1DAC2_EQ_B5_A_MASK 0xFFFF /* AIF1DAC2_EQ_B5_A - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B5_A_SHIFT 0 /* AIF1DAC2_EQ_B5_A - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B5_A_WIDTH 16 /* AIF1DAC2_EQ_B5_A - [15:0] */ + +/* + * R1202 (0x4B2) - AIF1 DAC2 EQ Band 5 B + */ +#define WM8994_AIF1DAC2_EQ_B5_B_MASK 0xFFFF /* AIF1DAC2_EQ_B5_B - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B5_B_SHIFT 0 /* AIF1DAC2_EQ_B5_B - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B5_B_WIDTH 16 /* AIF1DAC2_EQ_B5_B - [15:0] */ + +/* + * R1203 (0x4B3) - AIF1 DAC2 EQ Band 5 PG + */ +#define WM8994_AIF1DAC2_EQ_B5_PG_MASK 0xFFFF /* AIF1DAC2_EQ_B5_PG - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B5_PG_SHIFT 0 /* AIF1DAC2_EQ_B5_PG - [15:0] */ +#define WM8994_AIF1DAC2_EQ_B5_PG_WIDTH 16 /* AIF1DAC2_EQ_B5_PG - [15:0] */ + +/* + * R1280 (0x500) - AIF2 ADC Left Volume + */ +#define WM8994_AIF2ADC_VU 0x0100 /* AIF2ADC_VU */ +#define WM8994_AIF2ADC_VU_MASK 0x0100 /* AIF2ADC_VU */ +#define WM8994_AIF2ADC_VU_SHIFT 8 /* AIF2ADC_VU */ +#define WM8994_AIF2ADC_VU_WIDTH 1 /* AIF2ADC_VU */ +#define WM8994_AIF2ADCL_VOL_MASK 0x00FF /* AIF2ADCL_VOL - [7:0] */ +#define WM8994_AIF2ADCL_VOL_SHIFT 0 /* AIF2ADCL_VOL - [7:0] */ +#define WM8994_AIF2ADCL_VOL_WIDTH 8 /* AIF2ADCL_VOL - [7:0] */ + +/* + * R1281 (0x501) - AIF2 ADC Right Volume + */ +#define WM8994_AIF2ADC_VU 0x0100 /* AIF2ADC_VU */ +#define WM8994_AIF2ADC_VU_MASK 0x0100 /* AIF2ADC_VU */ +#define WM8994_AIF2ADC_VU_SHIFT 8 /* AIF2ADC_VU */ +#define WM8994_AIF2ADC_VU_WIDTH 1 /* AIF2ADC_VU */ +#define WM8994_AIF2ADCR_VOL_MASK 0x00FF /* AIF2ADCR_VOL - [7:0] */ +#define WM8994_AIF2ADCR_VOL_SHIFT 0 /* AIF2ADCR_VOL - [7:0] */ +#define WM8994_AIF2ADCR_VOL_WIDTH 8 /* AIF2ADCR_VOL - [7:0] */ + +/* + * R1282 (0x502) - AIF2 DAC Left Volume + */ +#define WM8994_AIF2DAC_VU 0x0100 /* AIF2DAC_VU */ +#define WM8994_AIF2DAC_VU_MASK 0x0100 /* AIF2DAC_VU */ +#define WM8994_AIF2DAC_VU_SHIFT 8 /* AIF2DAC_VU */ +#define WM8994_AIF2DAC_VU_WIDTH 1 /* AIF2DAC_VU */ +#define WM8994_AIF2DACL_VOL_MASK 0x00FF /* AIF2DACL_VOL - [7:0] */ +#define WM8994_AIF2DACL_VOL_SHIFT 0 /* AIF2DACL_VOL - [7:0] */ +#define WM8994_AIF2DACL_VOL_WIDTH 8 /* AIF2DACL_VOL - [7:0] */ + +/* + * R1283 (0x503) - AIF2 DAC Right Volume + */ +#define WM8994_AIF2DAC_VU 0x0100 /* AIF2DAC_VU */ +#define WM8994_AIF2DAC_VU_MASK 0x0100 /* AIF2DAC_VU */ +#define WM8994_AIF2DAC_VU_SHIFT 8 /* AIF2DAC_VU */ +#define WM8994_AIF2DAC_VU_WIDTH 1 /* AIF2DAC_VU */ +#define WM8994_AIF2DACR_VOL_MASK 0x00FF /* AIF2DACR_VOL - [7:0] */ +#define WM8994_AIF2DACR_VOL_SHIFT 0 /* AIF2DACR_VOL - [7:0] */ +#define WM8994_AIF2DACR_VOL_WIDTH 8 /* AIF2DACR_VOL - [7:0] */ + +/* + * R1296 (0x510) - AIF2 ADC Filters + */ +#define WM8994_AIF2ADC_4FS 0x8000 /* AIF2ADC_4FS */ +#define WM8994_AIF2ADC_4FS_MASK 0x8000 /* AIF2ADC_4FS */ +#define WM8994_AIF2ADC_4FS_SHIFT 15 /* AIF2ADC_4FS */ +#define WM8994_AIF2ADC_4FS_WIDTH 1 /* AIF2ADC_4FS */ +#define WM8994_AIF2ADC_HPF_CUT_MASK 0x6000 /* AIF2ADC_HPF_CUT - [14:13] */ +#define WM8994_AIF2ADC_HPF_CUT_SHIFT 13 /* AIF2ADC_HPF_CUT - [14:13] */ +#define WM8994_AIF2ADC_HPF_CUT_WIDTH 2 /* AIF2ADC_HPF_CUT - [14:13] */ +#define WM8994_AIF2ADCL_HPF 0x1000 /* AIF2ADCL_HPF */ +#define WM8994_AIF2ADCL_HPF_MASK 0x1000 /* AIF2ADCL_HPF */ +#define WM8994_AIF2ADCL_HPF_SHIFT 12 /* AIF2ADCL_HPF */ +#define WM8994_AIF2ADCL_HPF_WIDTH 1 /* AIF2ADCL_HPF */ +#define WM8994_AIF2ADCR_HPF 0x0800 /* AIF2ADCR_HPF */ +#define WM8994_AIF2ADCR_HPF_MASK 0x0800 /* AIF2ADCR_HPF */ +#define WM8994_AIF2ADCR_HPF_SHIFT 11 /* AIF2ADCR_HPF */ +#define WM8994_AIF2ADCR_HPF_WIDTH 1 /* AIF2ADCR_HPF */ + +/* + * R1312 (0x520) - AIF2 DAC Filters (1) + */ +#define WM8994_AIF2DAC_MUTE 0x0200 /* AIF2DAC_MUTE */ +#define WM8994_AIF2DAC_MUTE_MASK 0x0200 /* AIF2DAC_MUTE */ +#define WM8994_AIF2DAC_MUTE_SHIFT 9 /* AIF2DAC_MUTE */ +#define WM8994_AIF2DAC_MUTE_WIDTH 1 /* AIF2DAC_MUTE */ +#define WM8994_AIF2DAC_MONO 0x0080 /* AIF2DAC_MONO */ +#define WM8994_AIF2DAC_MONO_MASK 0x0080 /* AIF2DAC_MONO */ +#define WM8994_AIF2DAC_MONO_SHIFT 7 /* AIF2DAC_MONO */ +#define WM8994_AIF2DAC_MONO_WIDTH 1 /* AIF2DAC_MONO */ +#define WM8994_AIF2DAC_MUTERATE 0x0020 /* AIF2DAC_MUTERATE */ +#define WM8994_AIF2DAC_MUTERATE_MASK 0x0020 /* AIF2DAC_MUTERATE */ +#define WM8994_AIF2DAC_MUTERATE_SHIFT 5 /* AIF2DAC_MUTERATE */ +#define WM8994_AIF2DAC_MUTERATE_WIDTH 1 /* AIF2DAC_MUTERATE */ +#define WM8994_AIF2DAC_UNMUTE_RAMP 0x0010 /* AIF2DAC_UNMUTE_RAMP */ +#define WM8994_AIF2DAC_UNMUTE_RAMP_MASK 0x0010 /* AIF2DAC_UNMUTE_RAMP */ +#define WM8994_AIF2DAC_UNMUTE_RAMP_SHIFT 4 /* AIF2DAC_UNMUTE_RAMP */ +#define WM8994_AIF2DAC_UNMUTE_RAMP_WIDTH 1 /* AIF2DAC_UNMUTE_RAMP */ +#define WM8994_AIF2DAC_DEEMP_MASK 0x0006 /* AIF2DAC_DEEMP - [2:1] */ +#define WM8994_AIF2DAC_DEEMP_SHIFT 1 /* AIF2DAC_DEEMP - [2:1] */ +#define WM8994_AIF2DAC_DEEMP_WIDTH 2 /* AIF2DAC_DEEMP - [2:1] */ + +/* + * R1313 (0x521) - AIF2 DAC Filters (2) + */ +#define WM8994_AIF2DAC_3D_GAIN_MASK 0x3E00 /* AIF2DAC_3D_GAIN - [13:9] */ +#define WM8994_AIF2DAC_3D_GAIN_SHIFT 9 /* AIF2DAC_3D_GAIN - [13:9] */ +#define WM8994_AIF2DAC_3D_GAIN_WIDTH 5 /* AIF2DAC_3D_GAIN - [13:9] */ +#define WM8994_AIF2DAC_3D_ENA 0x0100 /* AIF2DAC_3D_ENA */ +#define WM8994_AIF2DAC_3D_ENA_MASK 0x0100 /* AIF2DAC_3D_ENA */ +#define WM8994_AIF2DAC_3D_ENA_SHIFT 8 /* AIF2DAC_3D_ENA */ +#define WM8994_AIF2DAC_3D_ENA_WIDTH 1 /* AIF2DAC_3D_ENA */ + +/* + * R1344 (0x540) - AIF2 DRC (1) + */ +#define WM8994_AIF2DRC_SIG_DET_RMS_MASK 0xF800 /* AIF2DRC_SIG_DET_RMS - [15:11] */ +#define WM8994_AIF2DRC_SIG_DET_RMS_SHIFT 11 /* AIF2DRC_SIG_DET_RMS - [15:11] */ +#define WM8994_AIF2DRC_SIG_DET_RMS_WIDTH 5 /* AIF2DRC_SIG_DET_RMS - [15:11] */ +#define WM8994_AIF2DRC_SIG_DET_PK_MASK 0x0600 /* AIF2DRC_SIG_DET_PK - [10:9] */ +#define WM8994_AIF2DRC_SIG_DET_PK_SHIFT 9 /* AIF2DRC_SIG_DET_PK - [10:9] */ +#define WM8994_AIF2DRC_SIG_DET_PK_WIDTH 2 /* AIF2DRC_SIG_DET_PK - [10:9] */ +#define WM8994_AIF2DRC_NG_ENA 0x0100 /* AIF2DRC_NG_ENA */ +#define WM8994_AIF2DRC_NG_ENA_MASK 0x0100 /* AIF2DRC_NG_ENA */ +#define WM8994_AIF2DRC_NG_ENA_SHIFT 8 /* AIF2DRC_NG_ENA */ +#define WM8994_AIF2DRC_NG_ENA_WIDTH 1 /* AIF2DRC_NG_ENA */ +#define WM8994_AIF2DRC_SIG_DET_MODE 0x0080 /* AIF2DRC_SIG_DET_MODE */ +#define WM8994_AIF2DRC_SIG_DET_MODE_MASK 0x0080 /* AIF2DRC_SIG_DET_MODE */ +#define WM8994_AIF2DRC_SIG_DET_MODE_SHIFT 7 /* AIF2DRC_SIG_DET_MODE */ +#define WM8994_AIF2DRC_SIG_DET_MODE_WIDTH 1 /* AIF2DRC_SIG_DET_MODE */ +#define WM8994_AIF2DRC_SIG_DET 0x0040 /* AIF2DRC_SIG_DET */ +#define WM8994_AIF2DRC_SIG_DET_MASK 0x0040 /* AIF2DRC_SIG_DET */ +#define WM8994_AIF2DRC_SIG_DET_SHIFT 6 /* AIF2DRC_SIG_DET */ +#define WM8994_AIF2DRC_SIG_DET_WIDTH 1 /* AIF2DRC_SIG_DET */ +#define WM8994_AIF2DRC_KNEE2_OP_ENA 0x0020 /* AIF2DRC_KNEE2_OP_ENA */ +#define WM8994_AIF2DRC_KNEE2_OP_ENA_MASK 0x0020 /* AIF2DRC_KNEE2_OP_ENA */ +#define WM8994_AIF2DRC_KNEE2_OP_ENA_SHIFT 5 /* AIF2DRC_KNEE2_OP_ENA */ +#define WM8994_AIF2DRC_KNEE2_OP_ENA_WIDTH 1 /* AIF2DRC_KNEE2_OP_ENA */ +#define WM8994_AIF2DRC_QR 0x0010 /* AIF2DRC_QR */ +#define WM8994_AIF2DRC_QR_MASK 0x0010 /* AIF2DRC_QR */ +#define WM8994_AIF2DRC_QR_SHIFT 4 /* AIF2DRC_QR */ +#define WM8994_AIF2DRC_QR_WIDTH 1 /* AIF2DRC_QR */ +#define WM8994_AIF2DRC_ANTICLIP 0x0008 /* AIF2DRC_ANTICLIP */ +#define WM8994_AIF2DRC_ANTICLIP_MASK 0x0008 /* AIF2DRC_ANTICLIP */ +#define WM8994_AIF2DRC_ANTICLIP_SHIFT 3 /* AIF2DRC_ANTICLIP */ +#define WM8994_AIF2DRC_ANTICLIP_WIDTH 1 /* AIF2DRC_ANTICLIP */ +#define WM8994_AIF2DAC_DRC_ENA 0x0004 /* AIF2DAC_DRC_ENA */ +#define WM8994_AIF2DAC_DRC_ENA_MASK 0x0004 /* AIF2DAC_DRC_ENA */ +#define WM8994_AIF2DAC_DRC_ENA_SHIFT 2 /* AIF2DAC_DRC_ENA */ +#define WM8994_AIF2DAC_DRC_ENA_WIDTH 1 /* AIF2DAC_DRC_ENA */ +#define WM8994_AIF2ADCL_DRC_ENA 0x0002 /* AIF2ADCL_DRC_ENA */ +#define WM8994_AIF2ADCL_DRC_ENA_MASK 0x0002 /* AIF2ADCL_DRC_ENA */ +#define WM8994_AIF2ADCL_DRC_ENA_SHIFT 1 /* AIF2ADCL_DRC_ENA */ +#define WM8994_AIF2ADCL_DRC_ENA_WIDTH 1 /* AIF2ADCL_DRC_ENA */ +#define WM8994_AIF2ADCR_DRC_ENA 0x0001 /* AIF2ADCR_DRC_ENA */ +#define WM8994_AIF2ADCR_DRC_ENA_MASK 0x0001 /* AIF2ADCR_DRC_ENA */ +#define WM8994_AIF2ADCR_DRC_ENA_SHIFT 0 /* AIF2ADCR_DRC_ENA */ +#define WM8994_AIF2ADCR_DRC_ENA_WIDTH 1 /* AIF2ADCR_DRC_ENA */ + +/* + * R1345 (0x541) - AIF2 DRC (2) + */ +#define WM8994_AIF2DRC_ATK_MASK 0x1E00 /* AIF2DRC_ATK - [12:9] */ +#define WM8994_AIF2DRC_ATK_SHIFT 9 /* AIF2DRC_ATK - [12:9] */ +#define WM8994_AIF2DRC_ATK_WIDTH 4 /* AIF2DRC_ATK - [12:9] */ +#define WM8994_AIF2DRC_DCY_MASK 0x01E0 /* AIF2DRC_DCY - [8:5] */ +#define WM8994_AIF2DRC_DCY_SHIFT 5 /* AIF2DRC_DCY - [8:5] */ +#define WM8994_AIF2DRC_DCY_WIDTH 4 /* AIF2DRC_DCY - [8:5] */ +#define WM8994_AIF2DRC_MINGAIN_MASK 0x001C /* AIF2DRC_MINGAIN - [4:2] */ +#define WM8994_AIF2DRC_MINGAIN_SHIFT 2 /* AIF2DRC_MINGAIN - [4:2] */ +#define WM8994_AIF2DRC_MINGAIN_WIDTH 3 /* AIF2DRC_MINGAIN - [4:2] */ +#define WM8994_AIF2DRC_MAXGAIN_MASK 0x0003 /* AIF2DRC_MAXGAIN - [1:0] */ +#define WM8994_AIF2DRC_MAXGAIN_SHIFT 0 /* AIF2DRC_MAXGAIN - [1:0] */ +#define WM8994_AIF2DRC_MAXGAIN_WIDTH 2 /* AIF2DRC_MAXGAIN - [1:0] */ + +/* + * R1346 (0x542) - AIF2 DRC (3) + */ +#define WM8994_AIF2DRC_NG_MINGAIN_MASK 0xF000 /* AIF2DRC_NG_MINGAIN - [15:12] */ +#define WM8994_AIF2DRC_NG_MINGAIN_SHIFT 12 /* AIF2DRC_NG_MINGAIN - [15:12] */ +#define WM8994_AIF2DRC_NG_MINGAIN_WIDTH 4 /* AIF2DRC_NG_MINGAIN - [15:12] */ +#define WM8994_AIF2DRC_NG_EXP_MASK 0x0C00 /* AIF2DRC_NG_EXP - [11:10] */ +#define WM8994_AIF2DRC_NG_EXP_SHIFT 10 /* AIF2DRC_NG_EXP - [11:10] */ +#define WM8994_AIF2DRC_NG_EXP_WIDTH 2 /* AIF2DRC_NG_EXP - [11:10] */ +#define WM8994_AIF2DRC_QR_THR_MASK 0x0300 /* AIF2DRC_QR_THR - [9:8] */ +#define WM8994_AIF2DRC_QR_THR_SHIFT 8 /* AIF2DRC_QR_THR - [9:8] */ +#define WM8994_AIF2DRC_QR_THR_WIDTH 2 /* AIF2DRC_QR_THR - [9:8] */ +#define WM8994_AIF2DRC_QR_DCY_MASK 0x00C0 /* AIF2DRC_QR_DCY - [7:6] */ +#define WM8994_AIF2DRC_QR_DCY_SHIFT 6 /* AIF2DRC_QR_DCY - [7:6] */ +#define WM8994_AIF2DRC_QR_DCY_WIDTH 2 /* AIF2DRC_QR_DCY - [7:6] */ +#define WM8994_AIF2DRC_HI_COMP_MASK 0x0038 /* AIF2DRC_HI_COMP - [5:3] */ +#define WM8994_AIF2DRC_HI_COMP_SHIFT 3 /* AIF2DRC_HI_COMP - [5:3] */ +#define WM8994_AIF2DRC_HI_COMP_WIDTH 3 /* AIF2DRC_HI_COMP - [5:3] */ +#define WM8994_AIF2DRC_LO_COMP_MASK 0x0007 /* AIF2DRC_LO_COMP - [2:0] */ +#define WM8994_AIF2DRC_LO_COMP_SHIFT 0 /* AIF2DRC_LO_COMP - [2:0] */ +#define WM8994_AIF2DRC_LO_COMP_WIDTH 3 /* AIF2DRC_LO_COMP - [2:0] */ + +/* + * R1347 (0x543) - AIF2 DRC (4) + */ +#define WM8994_AIF2DRC_KNEE_IP_MASK 0x07E0 /* AIF2DRC_KNEE_IP - [10:5] */ +#define WM8994_AIF2DRC_KNEE_IP_SHIFT 5 /* AIF2DRC_KNEE_IP - [10:5] */ +#define WM8994_AIF2DRC_KNEE_IP_WIDTH 6 /* AIF2DRC_KNEE_IP - [10:5] */ +#define WM8994_AIF2DRC_KNEE_OP_MASK 0x001F /* AIF2DRC_KNEE_OP - [4:0] */ +#define WM8994_AIF2DRC_KNEE_OP_SHIFT 0 /* AIF2DRC_KNEE_OP - [4:0] */ +#define WM8994_AIF2DRC_KNEE_OP_WIDTH 5 /* AIF2DRC_KNEE_OP - [4:0] */ + +/* + * R1348 (0x544) - AIF2 DRC (5) + */ +#define WM8994_AIF2DRC_KNEE2_IP_MASK 0x03E0 /* AIF2DRC_KNEE2_IP - [9:5] */ +#define WM8994_AIF2DRC_KNEE2_IP_SHIFT 5 /* AIF2DRC_KNEE2_IP - [9:5] */ +#define WM8994_AIF2DRC_KNEE2_IP_WIDTH 5 /* AIF2DRC_KNEE2_IP - [9:5] */ +#define WM8994_AIF2DRC_KNEE2_OP_MASK 0x001F /* AIF2DRC_KNEE2_OP - [4:0] */ +#define WM8994_AIF2DRC_KNEE2_OP_SHIFT 0 /* AIF2DRC_KNEE2_OP - [4:0] */ +#define WM8994_AIF2DRC_KNEE2_OP_WIDTH 5 /* AIF2DRC_KNEE2_OP - [4:0] */ + +/* + * R1408 (0x580) - AIF2 EQ Gains (1) + */ +#define WM8994_AIF2DAC_EQ_B1_GAIN_MASK 0xF800 /* AIF2DAC_EQ_B1_GAIN - [15:11] */ +#define WM8994_AIF2DAC_EQ_B1_GAIN_SHIFT 11 /* AIF2DAC_EQ_B1_GAIN - [15:11] */ +#define WM8994_AIF2DAC_EQ_B1_GAIN_WIDTH 5 /* AIF2DAC_EQ_B1_GAIN - [15:11] */ +#define WM8994_AIF2DAC_EQ_B2_GAIN_MASK 0x07C0 /* AIF2DAC_EQ_B2_GAIN - [10:6] */ +#define WM8994_AIF2DAC_EQ_B2_GAIN_SHIFT 6 /* AIF2DAC_EQ_B2_GAIN - [10:6] */ +#define WM8994_AIF2DAC_EQ_B2_GAIN_WIDTH 5 /* AIF2DAC_EQ_B2_GAIN - [10:6] */ +#define WM8994_AIF2DAC_EQ_B3_GAIN_MASK 0x003E /* AIF2DAC_EQ_B3_GAIN - [5:1] */ +#define WM8994_AIF2DAC_EQ_B3_GAIN_SHIFT 1 /* AIF2DAC_EQ_B3_GAIN - [5:1] */ +#define WM8994_AIF2DAC_EQ_B3_GAIN_WIDTH 5 /* AIF2DAC_EQ_B3_GAIN - [5:1] */ +#define WM8994_AIF2DAC_EQ_ENA 0x0001 /* AIF2DAC_EQ_ENA */ +#define WM8994_AIF2DAC_EQ_ENA_MASK 0x0001 /* AIF2DAC_EQ_ENA */ +#define WM8994_AIF2DAC_EQ_ENA_SHIFT 0 /* AIF2DAC_EQ_ENA */ +#define WM8994_AIF2DAC_EQ_ENA_WIDTH 1 /* AIF2DAC_EQ_ENA */ + +/* + * R1409 (0x581) - AIF2 EQ Gains (2) + */ +#define WM8994_AIF2DAC_EQ_B4_GAIN_MASK 0xF800 /* AIF2DAC_EQ_B4_GAIN - [15:11] */ +#define WM8994_AIF2DAC_EQ_B4_GAIN_SHIFT 11 /* AIF2DAC_EQ_B4_GAIN - [15:11] */ +#define WM8994_AIF2DAC_EQ_B4_GAIN_WIDTH 5 /* AIF2DAC_EQ_B4_GAIN - [15:11] */ +#define WM8994_AIF2DAC_EQ_B5_GAIN_MASK 0x07C0 /* AIF2DAC_EQ_B5_GAIN - [10:6] */ +#define WM8994_AIF2DAC_EQ_B5_GAIN_SHIFT 6 /* AIF2DAC_EQ_B5_GAIN - [10:6] */ +#define WM8994_AIF2DAC_EQ_B5_GAIN_WIDTH 5 /* AIF2DAC_EQ_B5_GAIN - [10:6] */ + +/* + * R1410 (0x582) - AIF2 EQ Band 1 A + */ +#define WM8994_AIF2DAC_EQ_B1_A_MASK 0xFFFF /* AIF2DAC_EQ_B1_A - [15:0] */ +#define WM8994_AIF2DAC_EQ_B1_A_SHIFT 0 /* AIF2DAC_EQ_B1_A - [15:0] */ +#define WM8994_AIF2DAC_EQ_B1_A_WIDTH 16 /* AIF2DAC_EQ_B1_A - [15:0] */ + +/* + * R1411 (0x583) - AIF2 EQ Band 1 B + */ +#define WM8994_AIF2DAC_EQ_B1_B_MASK 0xFFFF /* AIF2DAC_EQ_B1_B - [15:0] */ +#define WM8994_AIF2DAC_EQ_B1_B_SHIFT 0 /* AIF2DAC_EQ_B1_B - [15:0] */ +#define WM8994_AIF2DAC_EQ_B1_B_WIDTH 16 /* AIF2DAC_EQ_B1_B - [15:0] */ + +/* + * R1412 (0x584) - AIF2 EQ Band 1 PG + */ +#define WM8994_AIF2DAC_EQ_B1_PG_MASK 0xFFFF /* AIF2DAC_EQ_B1_PG - [15:0] */ +#define WM8994_AIF2DAC_EQ_B1_PG_SHIFT 0 /* AIF2DAC_EQ_B1_PG - [15:0] */ +#define WM8994_AIF2DAC_EQ_B1_PG_WIDTH 16 /* AIF2DAC_EQ_B1_PG - [15:0] */ + +/* + * R1413 (0x585) - AIF2 EQ Band 2 A + */ +#define WM8994_AIF2DAC_EQ_B2_A_MASK 0xFFFF /* AIF2DAC_EQ_B2_A - [15:0] */ +#define WM8994_AIF2DAC_EQ_B2_A_SHIFT 0 /* AIF2DAC_EQ_B2_A - [15:0] */ +#define WM8994_AIF2DAC_EQ_B2_A_WIDTH 16 /* AIF2DAC_EQ_B2_A - [15:0] */ + +/* + * R1414 (0x586) - AIF2 EQ Band 2 B + */ +#define WM8994_AIF2DAC_EQ_B2_B_MASK 0xFFFF /* AIF2DAC_EQ_B2_B - [15:0] */ +#define WM8994_AIF2DAC_EQ_B2_B_SHIFT 0 /* AIF2DAC_EQ_B2_B - [15:0] */ +#define WM8994_AIF2DAC_EQ_B2_B_WIDTH 16 /* AIF2DAC_EQ_B2_B - [15:0] */ + +/* + * R1415 (0x587) - AIF2 EQ Band 2 C + */ +#define WM8994_AIF2DAC_EQ_B2_C_MASK 0xFFFF /* AIF2DAC_EQ_B2_C - [15:0] */ +#define WM8994_AIF2DAC_EQ_B2_C_SHIFT 0 /* AIF2DAC_EQ_B2_C - [15:0] */ +#define WM8994_AIF2DAC_EQ_B2_C_WIDTH 16 /* AIF2DAC_EQ_B2_C - [15:0] */ + +/* + * R1416 (0x588) - AIF2 EQ Band 2 PG + */ +#define WM8994_AIF2DAC_EQ_B2_PG_MASK 0xFFFF /* AIF2DAC_EQ_B2_PG - [15:0] */ +#define WM8994_AIF2DAC_EQ_B2_PG_SHIFT 0 /* AIF2DAC_EQ_B2_PG - [15:0] */ +#define WM8994_AIF2DAC_EQ_B2_PG_WIDTH 16 /* AIF2DAC_EQ_B2_PG - [15:0] */ + +/* + * R1417 (0x589) - AIF2 EQ Band 3 A + */ +#define WM8994_AIF2DAC_EQ_B3_A_MASK 0xFFFF /* AIF2DAC_EQ_B3_A - [15:0] */ +#define WM8994_AIF2DAC_EQ_B3_A_SHIFT 0 /* AIF2DAC_EQ_B3_A - [15:0] */ +#define WM8994_AIF2DAC_EQ_B3_A_WIDTH 16 /* AIF2DAC_EQ_B3_A - [15:0] */ + +/* + * R1418 (0x58A) - AIF2 EQ Band 3 B + */ +#define WM8994_AIF2DAC_EQ_B3_B_MASK 0xFFFF /* AIF2DAC_EQ_B3_B - [15:0] */ +#define WM8994_AIF2DAC_EQ_B3_B_SHIFT 0 /* AIF2DAC_EQ_B3_B - [15:0] */ +#define WM8994_AIF2DAC_EQ_B3_B_WIDTH 16 /* AIF2DAC_EQ_B3_B - [15:0] */ + +/* + * R1419 (0x58B) - AIF2 EQ Band 3 C + */ +#define WM8994_AIF2DAC_EQ_B3_C_MASK 0xFFFF /* AIF2DAC_EQ_B3_C - [15:0] */ +#define WM8994_AIF2DAC_EQ_B3_C_SHIFT 0 /* AIF2DAC_EQ_B3_C - [15:0] */ +#define WM8994_AIF2DAC_EQ_B3_C_WIDTH 16 /* AIF2DAC_EQ_B3_C - [15:0] */ + +/* + * R1420 (0x58C) - AIF2 EQ Band 3 PG + */ +#define WM8994_AIF2DAC_EQ_B3_PG_MASK 0xFFFF /* AIF2DAC_EQ_B3_PG - [15:0] */ +#define WM8994_AIF2DAC_EQ_B3_PG_SHIFT 0 /* AIF2DAC_EQ_B3_PG - [15:0] */ +#define WM8994_AIF2DAC_EQ_B3_PG_WIDTH 16 /* AIF2DAC_EQ_B3_PG - [15:0] */ + +/* + * R1421 (0x58D) - AIF2 EQ Band 4 A + */ +#define WM8994_AIF2DAC_EQ_B4_A_MASK 0xFFFF /* AIF2DAC_EQ_B4_A - [15:0] */ +#define WM8994_AIF2DAC_EQ_B4_A_SHIFT 0 /* AIF2DAC_EQ_B4_A - [15:0] */ +#define WM8994_AIF2DAC_EQ_B4_A_WIDTH 16 /* AIF2DAC_EQ_B4_A - [15:0] */ + +/* + * R1422 (0x58E) - AIF2 EQ Band 4 B + */ +#define WM8994_AIF2DAC_EQ_B4_B_MASK 0xFFFF /* AIF2DAC_EQ_B4_B - [15:0] */ +#define WM8994_AIF2DAC_EQ_B4_B_SHIFT 0 /* AIF2DAC_EQ_B4_B - [15:0] */ +#define WM8994_AIF2DAC_EQ_B4_B_WIDTH 16 /* AIF2DAC_EQ_B4_B - [15:0] */ + +/* + * R1423 (0x58F) - AIF2 EQ Band 4 C + */ +#define WM8994_AIF2DAC_EQ_B4_C_MASK 0xFFFF /* AIF2DAC_EQ_B4_C - [15:0] */ +#define WM8994_AIF2DAC_EQ_B4_C_SHIFT 0 /* AIF2DAC_EQ_B4_C - [15:0] */ +#define WM8994_AIF2DAC_EQ_B4_C_WIDTH 16 /* AIF2DAC_EQ_B4_C - [15:0] */ + +/* + * R1424 (0x590) - AIF2 EQ Band 4 PG + */ +#define WM8994_AIF2DAC_EQ_B4_PG_MASK 0xFFFF /* AIF2DAC_EQ_B4_PG - [15:0] */ +#define WM8994_AIF2DAC_EQ_B4_PG_SHIFT 0 /* AIF2DAC_EQ_B4_PG - [15:0] */ +#define WM8994_AIF2DAC_EQ_B4_PG_WIDTH 16 /* AIF2DAC_EQ_B4_PG - [15:0] */ + +/* + * R1425 (0x591) - AIF2 EQ Band 5 A + */ +#define WM8994_AIF2DAC_EQ_B5_A_MASK 0xFFFF /* AIF2DAC_EQ_B5_A - [15:0] */ +#define WM8994_AIF2DAC_EQ_B5_A_SHIFT 0 /* AIF2DAC_EQ_B5_A - [15:0] */ +#define WM8994_AIF2DAC_EQ_B5_A_WIDTH 16 /* AIF2DAC_EQ_B5_A - [15:0] */ + +/* + * R1426 (0x592) - AIF2 EQ Band 5 B + */ +#define WM8994_AIF2DAC_EQ_B5_B_MASK 0xFFFF /* AIF2DAC_EQ_B5_B - [15:0] */ +#define WM8994_AIF2DAC_EQ_B5_B_SHIFT 0 /* AIF2DAC_EQ_B5_B - [15:0] */ +#define WM8994_AIF2DAC_EQ_B5_B_WIDTH 16 /* AIF2DAC_EQ_B5_B - [15:0] */ + +/* + * R1427 (0x593) - AIF2 EQ Band 5 PG + */ +#define WM8994_AIF2DAC_EQ_B5_PG_MASK 0xFFFF /* AIF2DAC_EQ_B5_PG - [15:0] */ +#define WM8994_AIF2DAC_EQ_B5_PG_SHIFT 0 /* AIF2DAC_EQ_B5_PG - [15:0] */ +#define WM8994_AIF2DAC_EQ_B5_PG_WIDTH 16 /* AIF2DAC_EQ_B5_PG - [15:0] */ + +/* + * R1536 (0x600) - DAC1 Mixer Volumes + */ +#define WM8994_ADCR_DAC1_VOL_MASK 0x01E0 /* ADCR_DAC1_VOL - [8:5] */ +#define WM8994_ADCR_DAC1_VOL_SHIFT 5 /* ADCR_DAC1_VOL - [8:5] */ +#define WM8994_ADCR_DAC1_VOL_WIDTH 4 /* ADCR_DAC1_VOL - [8:5] */ +#define WM8994_ADCL_DAC1_VOL_MASK 0x000F /* ADCL_DAC1_VOL - [3:0] */ +#define WM8994_ADCL_DAC1_VOL_SHIFT 0 /* ADCL_DAC1_VOL - [3:0] */ +#define WM8994_ADCL_DAC1_VOL_WIDTH 4 /* ADCL_DAC1_VOL - [3:0] */ + +/* + * R1537 (0x601) - DAC1 Left Mixer Routing + */ +#define WM8994_ADCR_TO_DAC1L 0x0020 /* ADCR_TO_DAC1L */ +#define WM8994_ADCR_TO_DAC1L_MASK 0x0020 /* ADCR_TO_DAC1L */ +#define WM8994_ADCR_TO_DAC1L_SHIFT 5 /* ADCR_TO_DAC1L */ +#define WM8994_ADCR_TO_DAC1L_WIDTH 1 /* ADCR_TO_DAC1L */ +#define WM8994_ADCL_TO_DAC1L 0x0010 /* ADCL_TO_DAC1L */ +#define WM8994_ADCL_TO_DAC1L_MASK 0x0010 /* ADCL_TO_DAC1L */ +#define WM8994_ADCL_TO_DAC1L_SHIFT 4 /* ADCL_TO_DAC1L */ +#define WM8994_ADCL_TO_DAC1L_WIDTH 1 /* ADCL_TO_DAC1L */ +#define WM8994_AIF2DACL_TO_DAC1L 0x0004 /* AIF2DACL_TO_DAC1L */ +#define WM8994_AIF2DACL_TO_DAC1L_MASK 0x0004 /* AIF2DACL_TO_DAC1L */ +#define WM8994_AIF2DACL_TO_DAC1L_SHIFT 2 /* AIF2DACL_TO_DAC1L */ +#define WM8994_AIF2DACL_TO_DAC1L_WIDTH 1 /* AIF2DACL_TO_DAC1L */ +#define WM8994_AIF1DAC2L_TO_DAC1L 0x0002 /* AIF1DAC2L_TO_DAC1L */ +#define WM8994_AIF1DAC2L_TO_DAC1L_MASK 0x0002 /* AIF1DAC2L_TO_DAC1L */ +#define WM8994_AIF1DAC2L_TO_DAC1L_SHIFT 1 /* AIF1DAC2L_TO_DAC1L */ +#define WM8994_AIF1DAC2L_TO_DAC1L_WIDTH 1 /* AIF1DAC2L_TO_DAC1L */ +#define WM8994_AIF1DAC1L_TO_DAC1L 0x0001 /* AIF1DAC1L_TO_DAC1L */ +#define WM8994_AIF1DAC1L_TO_DAC1L_MASK 0x0001 /* AIF1DAC1L_TO_DAC1L */ +#define WM8994_AIF1DAC1L_TO_DAC1L_SHIFT 0 /* AIF1DAC1L_TO_DAC1L */ +#define WM8994_AIF1DAC1L_TO_DAC1L_WIDTH 1 /* AIF1DAC1L_TO_DAC1L */ + +/* + * R1538 (0x602) - DAC1 Right Mixer Routing + */ +#define WM8994_ADCR_TO_DAC1R 0x0020 /* ADCR_TO_DAC1R */ +#define WM8994_ADCR_TO_DAC1R_MASK 0x0020 /* ADCR_TO_DAC1R */ +#define WM8994_ADCR_TO_DAC1R_SHIFT 5 /* ADCR_TO_DAC1R */ +#define WM8994_ADCR_TO_DAC1R_WIDTH 1 /* ADCR_TO_DAC1R */ +#define WM8994_ADCL_TO_DAC1R 0x0010 /* ADCL_TO_DAC1R */ +#define WM8994_ADCL_TO_DAC1R_MASK 0x0010 /* ADCL_TO_DAC1R */ +#define WM8994_ADCL_TO_DAC1R_SHIFT 4 /* ADCL_TO_DAC1R */ +#define WM8994_ADCL_TO_DAC1R_WIDTH 1 /* ADCL_TO_DAC1R */ +#define WM8994_AIF2DACR_TO_DAC1R 0x0004 /* AIF2DACR_TO_DAC1R */ +#define WM8994_AIF2DACR_TO_DAC1R_MASK 0x0004 /* AIF2DACR_TO_DAC1R */ +#define WM8994_AIF2DACR_TO_DAC1R_SHIFT 2 /* AIF2DACR_TO_DAC1R */ +#define WM8994_AIF2DACR_TO_DAC1R_WIDTH 1 /* AIF2DACR_TO_DAC1R */ +#define WM8994_AIF1DAC2R_TO_DAC1R 0x0002 /* AIF1DAC2R_TO_DAC1R */ +#define WM8994_AIF1DAC2R_TO_DAC1R_MASK 0x0002 /* AIF1DAC2R_TO_DAC1R */ +#define WM8994_AIF1DAC2R_TO_DAC1R_SHIFT 1 /* AIF1DAC2R_TO_DAC1R */ +#define WM8994_AIF1DAC2R_TO_DAC1R_WIDTH 1 /* AIF1DAC2R_TO_DAC1R */ +#define WM8994_AIF1DAC1R_TO_DAC1R 0x0001 /* AIF1DAC1R_TO_DAC1R */ +#define WM8994_AIF1DAC1R_TO_DAC1R_MASK 0x0001 /* AIF1DAC1R_TO_DAC1R */ +#define WM8994_AIF1DAC1R_TO_DAC1R_SHIFT 0 /* AIF1DAC1R_TO_DAC1R */ +#define WM8994_AIF1DAC1R_TO_DAC1R_WIDTH 1 /* AIF1DAC1R_TO_DAC1R */ + +/* + * R1539 (0x603) - DAC2 Mixer Volumes + */ +#define WM8994_ADCR_DAC2_VOL_MASK 0x01E0 /* ADCR_DAC2_VOL - [8:5] */ +#define WM8994_ADCR_DAC2_VOL_SHIFT 5 /* ADCR_DAC2_VOL - [8:5] */ +#define WM8994_ADCR_DAC2_VOL_WIDTH 4 /* ADCR_DAC2_VOL - [8:5] */ +#define WM8994_ADCL_DAC2_VOL_MASK 0x000F /* ADCL_DAC2_VOL - [3:0] */ +#define WM8994_ADCL_DAC2_VOL_SHIFT 0 /* ADCL_DAC2_VOL - [3:0] */ +#define WM8994_ADCL_DAC2_VOL_WIDTH 4 /* ADCL_DAC2_VOL - [3:0] */ + +/* + * R1540 (0x604) - DAC2 Left Mixer Routing + */ +#define WM8994_ADCR_TO_DAC2L 0x0020 /* ADCR_TO_DAC2L */ +#define WM8994_ADCR_TO_DAC2L_MASK 0x0020 /* ADCR_TO_DAC2L */ +#define WM8994_ADCR_TO_DAC2L_SHIFT 5 /* ADCR_TO_DAC2L */ +#define WM8994_ADCR_TO_DAC2L_WIDTH 1 /* ADCR_TO_DAC2L */ +#define WM8994_ADCL_TO_DAC2L 0x0010 /* ADCL_TO_DAC2L */ +#define WM8994_ADCL_TO_DAC2L_MASK 0x0010 /* ADCL_TO_DAC2L */ +#define WM8994_ADCL_TO_DAC2L_SHIFT 4 /* ADCL_TO_DAC2L */ +#define WM8994_ADCL_TO_DAC2L_WIDTH 1 /* ADCL_TO_DAC2L */ +#define WM8994_AIF2DACL_TO_DAC2L 0x0004 /* AIF2DACL_TO_DAC2L */ +#define WM8994_AIF2DACL_TO_DAC2L_MASK 0x0004 /* AIF2DACL_TO_DAC2L */ +#define WM8994_AIF2DACL_TO_DAC2L_SHIFT 2 /* AIF2DACL_TO_DAC2L */ +#define WM8994_AIF2DACL_TO_DAC2L_WIDTH 1 /* AIF2DACL_TO_DAC2L */ +#define WM8994_AIF1DAC2L_TO_DAC2L 0x0002 /* AIF1DAC2L_TO_DAC2L */ +#define WM8994_AIF1DAC2L_TO_DAC2L_MASK 0x0002 /* AIF1DAC2L_TO_DAC2L */ +#define WM8994_AIF1DAC2L_TO_DAC2L_SHIFT 1 /* AIF1DAC2L_TO_DAC2L */ +#define WM8994_AIF1DAC2L_TO_DAC2L_WIDTH 1 /* AIF1DAC2L_TO_DAC2L */ +#define WM8994_AIF1DAC1L_TO_DAC2L 0x0001 /* AIF1DAC1L_TO_DAC2L */ +#define WM8994_AIF1DAC1L_TO_DAC2L_MASK 0x0001 /* AIF1DAC1L_TO_DAC2L */ +#define WM8994_AIF1DAC1L_TO_DAC2L_SHIFT 0 /* AIF1DAC1L_TO_DAC2L */ +#define WM8994_AIF1DAC1L_TO_DAC2L_WIDTH 1 /* AIF1DAC1L_TO_DAC2L */ + +/* + * R1541 (0x605) - DAC2 Right Mixer Routing + */ +#define WM8994_ADCR_TO_DAC2R 0x0020 /* ADCR_TO_DAC2R */ +#define WM8994_ADCR_TO_DAC2R_MASK 0x0020 /* ADCR_TO_DAC2R */ +#define WM8994_ADCR_TO_DAC2R_SHIFT 5 /* ADCR_TO_DAC2R */ +#define WM8994_ADCR_TO_DAC2R_WIDTH 1 /* ADCR_TO_DAC2R */ +#define WM8994_ADCL_TO_DAC2R 0x0010 /* ADCL_TO_DAC2R */ +#define WM8994_ADCL_TO_DAC2R_MASK 0x0010 /* ADCL_TO_DAC2R */ +#define WM8994_ADCL_TO_DAC2R_SHIFT 4 /* ADCL_TO_DAC2R */ +#define WM8994_ADCL_TO_DAC2R_WIDTH 1 /* ADCL_TO_DAC2R */ +#define WM8994_AIF2DACR_TO_DAC2R 0x0004 /* AIF2DACR_TO_DAC2R */ +#define WM8994_AIF2DACR_TO_DAC2R_MASK 0x0004 /* AIF2DACR_TO_DAC2R */ +#define WM8994_AIF2DACR_TO_DAC2R_SHIFT 2 /* AIF2DACR_TO_DAC2R */ +#define WM8994_AIF2DACR_TO_DAC2R_WIDTH 1 /* AIF2DACR_TO_DAC2R */ +#define WM8994_AIF1DAC2R_TO_DAC2R 0x0002 /* AIF1DAC2R_TO_DAC2R */ +#define WM8994_AIF1DAC2R_TO_DAC2R_MASK 0x0002 /* AIF1DAC2R_TO_DAC2R */ +#define WM8994_AIF1DAC2R_TO_DAC2R_SHIFT 1 /* AIF1DAC2R_TO_DAC2R */ +#define WM8994_AIF1DAC2R_TO_DAC2R_WIDTH 1 /* AIF1DAC2R_TO_DAC2R */ +#define WM8994_AIF1DAC1R_TO_DAC2R 0x0001 /* AIF1DAC1R_TO_DAC2R */ +#define WM8994_AIF1DAC1R_TO_DAC2R_MASK 0x0001 /* AIF1DAC1R_TO_DAC2R */ +#define WM8994_AIF1DAC1R_TO_DAC2R_SHIFT 0 /* AIF1DAC1R_TO_DAC2R */ +#define WM8994_AIF1DAC1R_TO_DAC2R_WIDTH 1 /* AIF1DAC1R_TO_DAC2R */ + +/* + * R1542 (0x606) - AIF1 ADC1 Left Mixer Routing + */ +#define WM8994_ADC1L_TO_AIF1ADC1L 0x0002 /* ADC1L_TO_AIF1ADC1L */ +#define WM8994_ADC1L_TO_AIF1ADC1L_MASK 0x0002 /* ADC1L_TO_AIF1ADC1L */ +#define WM8994_ADC1L_TO_AIF1ADC1L_SHIFT 1 /* ADC1L_TO_AIF1ADC1L */ +#define WM8994_ADC1L_TO_AIF1ADC1L_WIDTH 1 /* ADC1L_TO_AIF1ADC1L */ +#define WM8994_AIF2DACL_TO_AIF1ADC1L 0x0001 /* AIF2DACL_TO_AIF1ADC1L */ +#define WM8994_AIF2DACL_TO_AIF1ADC1L_MASK 0x0001 /* AIF2DACL_TO_AIF1ADC1L */ +#define WM8994_AIF2DACL_TO_AIF1ADC1L_SHIFT 0 /* AIF2DACL_TO_AIF1ADC1L */ +#define WM8994_AIF2DACL_TO_AIF1ADC1L_WIDTH 1 /* AIF2DACL_TO_AIF1ADC1L */ + +/* + * R1543 (0x607) - AIF1 ADC1 Right Mixer Routing + */ +#define WM8994_ADC1R_TO_AIF1ADC1R 0x0002 /* ADC1R_TO_AIF1ADC1R */ +#define WM8994_ADC1R_TO_AIF1ADC1R_MASK 0x0002 /* ADC1R_TO_AIF1ADC1R */ +#define WM8994_ADC1R_TO_AIF1ADC1R_SHIFT 1 /* ADC1R_TO_AIF1ADC1R */ +#define WM8994_ADC1R_TO_AIF1ADC1R_WIDTH 1 /* ADC1R_TO_AIF1ADC1R */ +#define WM8994_AIF2DACR_TO_AIF1ADC1R 0x0001 /* AIF2DACR_TO_AIF1ADC1R */ +#define WM8994_AIF2DACR_TO_AIF1ADC1R_MASK 0x0001 /* AIF2DACR_TO_AIF1ADC1R */ +#define WM8994_AIF2DACR_TO_AIF1ADC1R_SHIFT 0 /* AIF2DACR_TO_AIF1ADC1R */ +#define WM8994_AIF2DACR_TO_AIF1ADC1R_WIDTH 1 /* AIF2DACR_TO_AIF1ADC1R */ + +/* + * R1544 (0x608) - AIF1 ADC2 Left Mixer Routing + */ +#define WM8994_ADC2L_TO_AIF1ADC2L 0x0002 /* ADC2L_TO_AIF1ADC2L */ +#define WM8994_ADC2L_TO_AIF1ADC2L_MASK 0x0002 /* ADC2L_TO_AIF1ADC2L */ +#define WM8994_ADC2L_TO_AIF1ADC2L_SHIFT 1 /* ADC2L_TO_AIF1ADC2L */ +#define WM8994_ADC2L_TO_AIF1ADC2L_WIDTH 1 /* ADC2L_TO_AIF1ADC2L */ +#define WM8994_AIF2DACL_TO_AIF1ADC2L 0x0001 /* AIF2DACL_TO_AIF1ADC2L */ +#define WM8994_AIF2DACL_TO_AIF1ADC2L_MASK 0x0001 /* AIF2DACL_TO_AIF1ADC2L */ +#define WM8994_AIF2DACL_TO_AIF1ADC2L_SHIFT 0 /* AIF2DACL_TO_AIF1ADC2L */ +#define WM8994_AIF2DACL_TO_AIF1ADC2L_WIDTH 1 /* AIF2DACL_TO_AIF1ADC2L */ + +/* + * R1545 (0x609) - AIF1 ADC2 Right mixer Routing + */ +#define WM8994_ADC2R_TO_AIF1ADC2R 0x0002 /* ADC2R_TO_AIF1ADC2R */ +#define WM8994_ADC2R_TO_AIF1ADC2R_MASK 0x0002 /* ADC2R_TO_AIF1ADC2R */ +#define WM8994_ADC2R_TO_AIF1ADC2R_SHIFT 1 /* ADC2R_TO_AIF1ADC2R */ +#define WM8994_ADC2R_TO_AIF1ADC2R_WIDTH 1 /* ADC2R_TO_AIF1ADC2R */ +#define WM8994_AIF2DACR_TO_AIF1ADC2R 0x0001 /* AIF2DACR_TO_AIF1ADC2R */ +#define WM8994_AIF2DACR_TO_AIF1ADC2R_MASK 0x0001 /* AIF2DACR_TO_AIF1ADC2R */ +#define WM8994_AIF2DACR_TO_AIF1ADC2R_SHIFT 0 /* AIF2DACR_TO_AIF1ADC2R */ +#define WM8994_AIF2DACR_TO_AIF1ADC2R_WIDTH 1 /* AIF2DACR_TO_AIF1ADC2R */ + +/* + * R1552 (0x610) - DAC1 Left Volume + */ +#define WM8994_DAC1L_MUTE 0x0200 /* DAC1L_MUTE */ +#define WM8994_DAC1L_MUTE_MASK 0x0200 /* DAC1L_MUTE */ +#define WM8994_DAC1L_MUTE_SHIFT 9 /* DAC1L_MUTE */ +#define WM8994_DAC1L_MUTE_WIDTH 1 /* DAC1L_MUTE */ +#define WM8994_DAC1_VU 0x0100 /* DAC1_VU */ +#define WM8994_DAC1_VU_MASK 0x0100 /* DAC1_VU */ +#define WM8994_DAC1_VU_SHIFT 8 /* DAC1_VU */ +#define WM8994_DAC1_VU_WIDTH 1 /* DAC1_VU */ +#define WM8994_DAC1L_VOL_MASK 0x00FF /* DAC1L_VOL - [7:0] */ +#define WM8994_DAC1L_VOL_SHIFT 0 /* DAC1L_VOL - [7:0] */ +#define WM8994_DAC1L_VOL_WIDTH 8 /* DAC1L_VOL - [7:0] */ + +/* + * R1553 (0x611) - DAC1 Right Volume + */ +#define WM8994_DAC1R_MUTE 0x0200 /* DAC1R_MUTE */ +#define WM8994_DAC1R_MUTE_MASK 0x0200 /* DAC1R_MUTE */ +#define WM8994_DAC1R_MUTE_SHIFT 9 /* DAC1R_MUTE */ +#define WM8994_DAC1R_MUTE_WIDTH 1 /* DAC1R_MUTE */ +#define WM8994_DAC1_VU 0x0100 /* DAC1_VU */ +#define WM8994_DAC1_VU_MASK 0x0100 /* DAC1_VU */ +#define WM8994_DAC1_VU_SHIFT 8 /* DAC1_VU */ +#define WM8994_DAC1_VU_WIDTH 1 /* DAC1_VU */ +#define WM8994_DAC1R_VOL_MASK 0x00FF /* DAC1R_VOL - [7:0] */ +#define WM8994_DAC1R_VOL_SHIFT 0 /* DAC1R_VOL - [7:0] */ +#define WM8994_DAC1R_VOL_WIDTH 8 /* DAC1R_VOL - [7:0] */ + +/* + * R1554 (0x612) - DAC2 Left Volume + */ +#define WM8994_DAC2L_MUTE 0x0200 /* DAC2L_MUTE */ +#define WM8994_DAC2L_MUTE_MASK 0x0200 /* DAC2L_MUTE */ +#define WM8994_DAC2L_MUTE_SHIFT 9 /* DAC2L_MUTE */ +#define WM8994_DAC2L_MUTE_WIDTH 1 /* DAC2L_MUTE */ +#define WM8994_DAC2_VU 0x0100 /* DAC2_VU */ +#define WM8994_DAC2_VU_MASK 0x0100 /* DAC2_VU */ +#define WM8994_DAC2_VU_SHIFT 8 /* DAC2_VU */ +#define WM8994_DAC2_VU_WIDTH 1 /* DAC2_VU */ +#define WM8994_DAC2L_VOL_MASK 0x00FF /* DAC2L_VOL - [7:0] */ +#define WM8994_DAC2L_VOL_SHIFT 0 /* DAC2L_VOL - [7:0] */ +#define WM8994_DAC2L_VOL_WIDTH 8 /* DAC2L_VOL - [7:0] */ + +/* + * R1555 (0x613) - DAC2 Right Volume + */ +#define WM8994_DAC2R_MUTE 0x0200 /* DAC2R_MUTE */ +#define WM8994_DAC2R_MUTE_MASK 0x0200 /* DAC2R_MUTE */ +#define WM8994_DAC2R_MUTE_SHIFT 9 /* DAC2R_MUTE */ +#define WM8994_DAC2R_MUTE_WIDTH 1 /* DAC2R_MUTE */ +#define WM8994_DAC2_VU 0x0100 /* DAC2_VU */ +#define WM8994_DAC2_VU_MASK 0x0100 /* DAC2_VU */ +#define WM8994_DAC2_VU_SHIFT 8 /* DAC2_VU */ +#define WM8994_DAC2_VU_WIDTH 1 /* DAC2_VU */ +#define WM8994_DAC2R_VOL_MASK 0x00FF /* DAC2R_VOL - [7:0] */ +#define WM8994_DAC2R_VOL_SHIFT 0 /* DAC2R_VOL - [7:0] */ +#define WM8994_DAC2R_VOL_WIDTH 8 /* DAC2R_VOL - [7:0] */ + +/* + * R1556 (0x614) - DAC Softmute + */ +#define WM8994_DAC_SOFTMUTEMODE 0x0002 /* DAC_SOFTMUTEMODE */ +#define WM8994_DAC_SOFTMUTEMODE_MASK 0x0002 /* DAC_SOFTMUTEMODE */ +#define WM8994_DAC_SOFTMUTEMODE_SHIFT 1 /* DAC_SOFTMUTEMODE */ +#define WM8994_DAC_SOFTMUTEMODE_WIDTH 1 /* DAC_SOFTMUTEMODE */ +#define WM8994_DAC_MUTERATE 0x0001 /* DAC_MUTERATE */ +#define WM8994_DAC_MUTERATE_MASK 0x0001 /* DAC_MUTERATE */ +#define WM8994_DAC_MUTERATE_SHIFT 0 /* DAC_MUTERATE */ +#define WM8994_DAC_MUTERATE_WIDTH 1 /* DAC_MUTERATE */ + +/* + * R1568 (0x620) - Oversampling + */ +#define WM8994_ADC_OSR128 0x0002 /* ADC_OSR128 */ +#define WM8994_ADC_OSR128_MASK 0x0002 /* ADC_OSR128 */ +#define WM8994_ADC_OSR128_SHIFT 1 /* ADC_OSR128 */ +#define WM8994_ADC_OSR128_WIDTH 1 /* ADC_OSR128 */ +#define WM8994_DAC_OSR128 0x0001 /* DAC_OSR128 */ +#define WM8994_DAC_OSR128_MASK 0x0001 /* DAC_OSR128 */ +#define WM8994_DAC_OSR128_SHIFT 0 /* DAC_OSR128 */ +#define WM8994_DAC_OSR128_WIDTH 1 /* DAC_OSR128 */ + +/* + * R1569 (0x621) - Sidetone + */ +#define WM8994_ST_HPF_CUT_MASK 0x0380 /* ST_HPF_CUT - [9:7] */ +#define WM8994_ST_HPF_CUT_SHIFT 7 /* ST_HPF_CUT - [9:7] */ +#define WM8994_ST_HPF_CUT_WIDTH 3 /* ST_HPF_CUT - [9:7] */ +#define WM8994_ST_HPF 0x0040 /* ST_HPF */ +#define WM8994_ST_HPF_MASK 0x0040 /* ST_HPF */ +#define WM8994_ST_HPF_SHIFT 6 /* ST_HPF */ +#define WM8994_ST_HPF_WIDTH 1 /* ST_HPF */ +#define WM8994_STR_SEL 0x0002 /* STR_SEL */ +#define WM8994_STR_SEL_MASK 0x0002 /* STR_SEL */ +#define WM8994_STR_SEL_SHIFT 1 /* STR_SEL */ +#define WM8994_STR_SEL_WIDTH 1 /* STR_SEL */ +#define WM8994_STL_SEL 0x0001 /* STL_SEL */ +#define WM8994_STL_SEL_MASK 0x0001 /* STL_SEL */ +#define WM8994_STL_SEL_SHIFT 0 /* STL_SEL */ +#define WM8994_STL_SEL_WIDTH 1 /* STL_SEL */ + +/* + * R1824 (0x720) - Pull Control (1) + */ +#define WM8994_DMICDAT2_PU 0x0800 /* DMICDAT2_PU */ +#define WM8994_DMICDAT2_PU_MASK 0x0800 /* DMICDAT2_PU */ +#define WM8994_DMICDAT2_PU_SHIFT 11 /* DMICDAT2_PU */ +#define WM8994_DMICDAT2_PU_WIDTH 1 /* DMICDAT2_PU */ +#define WM8994_DMICDAT2_PD 0x0400 /* DMICDAT2_PD */ +#define WM8994_DMICDAT2_PD_MASK 0x0400 /* DMICDAT2_PD */ +#define WM8994_DMICDAT2_PD_SHIFT 10 /* DMICDAT2_PD */ +#define WM8994_DMICDAT2_PD_WIDTH 1 /* DMICDAT2_PD */ +#define WM8994_DMICDAT1_PU 0x0200 /* DMICDAT1_PU */ +#define WM8994_DMICDAT1_PU_MASK 0x0200 /* DMICDAT1_PU */ +#define WM8994_DMICDAT1_PU_SHIFT 9 /* DMICDAT1_PU */ +#define WM8994_DMICDAT1_PU_WIDTH 1 /* DMICDAT1_PU */ +#define WM8994_DMICDAT1_PD 0x0100 /* DMICDAT1_PD */ +#define WM8994_DMICDAT1_PD_MASK 0x0100 /* DMICDAT1_PD */ +#define WM8994_DMICDAT1_PD_SHIFT 8 /* DMICDAT1_PD */ +#define WM8994_DMICDAT1_PD_WIDTH 1 /* DMICDAT1_PD */ +#define WM8994_MCLK1_PU 0x0080 /* MCLK1_PU */ +#define WM8994_MCLK1_PU_MASK 0x0080 /* MCLK1_PU */ +#define WM8994_MCLK1_PU_SHIFT 7 /* MCLK1_PU */ +#define WM8994_MCLK1_PU_WIDTH 1 /* MCLK1_PU */ +#define WM8994_MCLK1_PD 0x0040 /* MCLK1_PD */ +#define WM8994_MCLK1_PD_MASK 0x0040 /* MCLK1_PD */ +#define WM8994_MCLK1_PD_SHIFT 6 /* MCLK1_PD */ +#define WM8994_MCLK1_PD_WIDTH 1 /* MCLK1_PD */ +#define WM8994_DACDAT1_PU 0x0020 /* DACDAT1_PU */ +#define WM8994_DACDAT1_PU_MASK 0x0020 /* DACDAT1_PU */ +#define WM8994_DACDAT1_PU_SHIFT 5 /* DACDAT1_PU */ +#define WM8994_DACDAT1_PU_WIDTH 1 /* DACDAT1_PU */ +#define WM8994_DACDAT1_PD 0x0010 /* DACDAT1_PD */ +#define WM8994_DACDAT1_PD_MASK 0x0010 /* DACDAT1_PD */ +#define WM8994_DACDAT1_PD_SHIFT 4 /* DACDAT1_PD */ +#define WM8994_DACDAT1_PD_WIDTH 1 /* DACDAT1_PD */ +#define WM8994_DACLRCLK1_PU 0x0008 /* DACLRCLK1_PU */ +#define WM8994_DACLRCLK1_PU_MASK 0x0008 /* DACLRCLK1_PU */ +#define WM8994_DACLRCLK1_PU_SHIFT 3 /* DACLRCLK1_PU */ +#define WM8994_DACLRCLK1_PU_WIDTH 1 /* DACLRCLK1_PU */ +#define WM8994_DACLRCLK1_PD 0x0004 /* DACLRCLK1_PD */ +#define WM8994_DACLRCLK1_PD_MASK 0x0004 /* DACLRCLK1_PD */ +#define WM8994_DACLRCLK1_PD_SHIFT 2 /* DACLRCLK1_PD */ +#define WM8994_DACLRCLK1_PD_WIDTH 1 /* DACLRCLK1_PD */ +#define WM8994_BCLK1_PU 0x0002 /* BCLK1_PU */ +#define WM8994_BCLK1_PU_MASK 0x0002 /* BCLK1_PU */ +#define WM8994_BCLK1_PU_SHIFT 1 /* BCLK1_PU */ +#define WM8994_BCLK1_PU_WIDTH 1 /* BCLK1_PU */ +#define WM8994_BCLK1_PD 0x0001 /* BCLK1_PD */ +#define WM8994_BCLK1_PD_MASK 0x0001 /* BCLK1_PD */ +#define WM8994_BCLK1_PD_SHIFT 0 /* BCLK1_PD */ +#define WM8994_BCLK1_PD_WIDTH 1 /* BCLK1_PD */ + +/* + * R1825 (0x721) - Pull Control (2) + */ +#define WM8994_CSNADDR_PD 0x0100 /* CSNADDR_PD */ +#define WM8994_CSNADDR_PD_MASK 0x0100 /* CSNADDR_PD */ +#define WM8994_CSNADDR_PD_SHIFT 8 /* CSNADDR_PD */ +#define WM8994_CSNADDR_PD_WIDTH 1 /* CSNADDR_PD */ +#define WM8994_LDO2ENA_PD 0x0040 /* LDO2ENA_PD */ +#define WM8994_LDO2ENA_PD_MASK 0x0040 /* LDO2ENA_PD */ +#define WM8994_LDO2ENA_PD_SHIFT 6 /* LDO2ENA_PD */ +#define WM8994_LDO2ENA_PD_WIDTH 1 /* LDO2ENA_PD */ +#define WM8994_LDO1ENA_PD 0x0010 /* LDO1ENA_PD */ +#define WM8994_LDO1ENA_PD_MASK 0x0010 /* LDO1ENA_PD */ +#define WM8994_LDO1ENA_PD_SHIFT 4 /* LDO1ENA_PD */ +#define WM8994_LDO1ENA_PD_WIDTH 1 /* LDO1ENA_PD */ +#define WM8994_CIFMODE_PD 0x0004 /* CIFMODE_PD */ +#define WM8994_CIFMODE_PD_MASK 0x0004 /* CIFMODE_PD */ +#define WM8994_CIFMODE_PD_SHIFT 2 /* CIFMODE_PD */ +#define WM8994_CIFMODE_PD_WIDTH 1 /* CIFMODE_PD */ +#define WM8994_SPKMODE_PU 0x0002 /* SPKMODE_PU */ +#define WM8994_SPKMODE_PU_MASK 0x0002 /* SPKMODE_PU */ +#define WM8994_SPKMODE_PU_SHIFT 1 /* SPKMODE_PU */ +#define WM8994_SPKMODE_PU_WIDTH 1 /* SPKMODE_PU */ + +/* + * R1840 (0x730) - Interrupt Status 1 + */ +#define WM8994_GP11_EINT 0x0400 /* GP11_EINT */ +#define WM8994_GP11_EINT_MASK 0x0400 /* GP11_EINT */ +#define WM8994_GP11_EINT_SHIFT 10 /* GP11_EINT */ +#define WM8994_GP11_EINT_WIDTH 1 /* GP11_EINT */ +#define WM8994_GP10_EINT 0x0200 /* GP10_EINT */ +#define WM8994_GP10_EINT_MASK 0x0200 /* GP10_EINT */ +#define WM8994_GP10_EINT_SHIFT 9 /* GP10_EINT */ +#define WM8994_GP10_EINT_WIDTH 1 /* GP10_EINT */ +#define WM8994_GP9_EINT 0x0100 /* GP9_EINT */ +#define WM8994_GP9_EINT_MASK 0x0100 /* GP9_EINT */ +#define WM8994_GP9_EINT_SHIFT 8 /* GP9_EINT */ +#define WM8994_GP9_EINT_WIDTH 1 /* GP9_EINT */ +#define WM8994_GP8_EINT 0x0080 /* GP8_EINT */ +#define WM8994_GP8_EINT_MASK 0x0080 /* GP8_EINT */ +#define WM8994_GP8_EINT_SHIFT 7 /* GP8_EINT */ +#define WM8994_GP8_EINT_WIDTH 1 /* GP8_EINT */ +#define WM8994_GP7_EINT 0x0040 /* GP7_EINT */ +#define WM8994_GP7_EINT_MASK 0x0040 /* GP7_EINT */ +#define WM8994_GP7_EINT_SHIFT 6 /* GP7_EINT */ +#define WM8994_GP7_EINT_WIDTH 1 /* GP7_EINT */ +#define WM8994_GP6_EINT 0x0020 /* GP6_EINT */ +#define WM8994_GP6_EINT_MASK 0x0020 /* GP6_EINT */ +#define WM8994_GP6_EINT_SHIFT 5 /* GP6_EINT */ +#define WM8994_GP6_EINT_WIDTH 1 /* GP6_EINT */ +#define WM8994_GP5_EINT 0x0010 /* GP5_EINT */ +#define WM8994_GP5_EINT_MASK 0x0010 /* GP5_EINT */ +#define WM8994_GP5_EINT_SHIFT 4 /* GP5_EINT */ +#define WM8994_GP5_EINT_WIDTH 1 /* GP5_EINT */ +#define WM8994_GP4_EINT 0x0008 /* GP4_EINT */ +#define WM8994_GP4_EINT_MASK 0x0008 /* GP4_EINT */ +#define WM8994_GP4_EINT_SHIFT 3 /* GP4_EINT */ +#define WM8994_GP4_EINT_WIDTH 1 /* GP4_EINT */ +#define WM8994_GP3_EINT 0x0004 /* GP3_EINT */ +#define WM8994_GP3_EINT_MASK 0x0004 /* GP3_EINT */ +#define WM8994_GP3_EINT_SHIFT 2 /* GP3_EINT */ +#define WM8994_GP3_EINT_WIDTH 1 /* GP3_EINT */ +#define WM8994_GP2_EINT 0x0002 /* GP2_EINT */ +#define WM8994_GP2_EINT_MASK 0x0002 /* GP2_EINT */ +#define WM8994_GP2_EINT_SHIFT 1 /* GP2_EINT */ +#define WM8994_GP2_EINT_WIDTH 1 /* GP2_EINT */ +#define WM8994_GP1_EINT 0x0001 /* GP1_EINT */ +#define WM8994_GP1_EINT_MASK 0x0001 /* GP1_EINT */ +#define WM8994_GP1_EINT_SHIFT 0 /* GP1_EINT */ +#define WM8994_GP1_EINT_WIDTH 1 /* GP1_EINT */ + +/* + * R1841 (0x731) - Interrupt Status 2 + */ +#define WM8994_TEMP_WARN_EINT 0x8000 /* TEMP_WARN_EINT */ +#define WM8994_TEMP_WARN_EINT_MASK 0x8000 /* TEMP_WARN_EINT */ +#define WM8994_TEMP_WARN_EINT_SHIFT 15 /* TEMP_WARN_EINT */ +#define WM8994_TEMP_WARN_EINT_WIDTH 1 /* TEMP_WARN_EINT */ +#define WM8994_DCS_DONE_EINT 0x4000 /* DCS_DONE_EINT */ +#define WM8994_DCS_DONE_EINT_MASK 0x4000 /* DCS_DONE_EINT */ +#define WM8994_DCS_DONE_EINT_SHIFT 14 /* DCS_DONE_EINT */ +#define WM8994_DCS_DONE_EINT_WIDTH 1 /* DCS_DONE_EINT */ +#define WM8994_WSEQ_DONE_EINT 0x2000 /* WSEQ_DONE_EINT */ +#define WM8994_WSEQ_DONE_EINT_MASK 0x2000 /* WSEQ_DONE_EINT */ +#define WM8994_WSEQ_DONE_EINT_SHIFT 13 /* WSEQ_DONE_EINT */ +#define WM8994_WSEQ_DONE_EINT_WIDTH 1 /* WSEQ_DONE_EINT */ +#define WM8994_FIFOS_ERR_EINT 0x1000 /* FIFOS_ERR_EINT */ +#define WM8994_FIFOS_ERR_EINT_MASK 0x1000 /* FIFOS_ERR_EINT */ +#define WM8994_FIFOS_ERR_EINT_SHIFT 12 /* FIFOS_ERR_EINT */ +#define WM8994_FIFOS_ERR_EINT_WIDTH 1 /* FIFOS_ERR_EINT */ +#define WM8994_AIF2DRC_SIG_DET_EINT 0x0800 /* AIF2DRC_SIG_DET_EINT */ +#define WM8994_AIF2DRC_SIG_DET_EINT_MASK 0x0800 /* AIF2DRC_SIG_DET_EINT */ +#define WM8994_AIF2DRC_SIG_DET_EINT_SHIFT 11 /* AIF2DRC_SIG_DET_EINT */ +#define WM8994_AIF2DRC_SIG_DET_EINT_WIDTH 1 /* AIF2DRC_SIG_DET_EINT */ +#define WM8994_AIF1DRC2_SIG_DET_EINT 0x0400 /* AIF1DRC2_SIG_DET_EINT */ +#define WM8994_AIF1DRC2_SIG_DET_EINT_MASK 0x0400 /* AIF1DRC2_SIG_DET_EINT */ +#define WM8994_AIF1DRC2_SIG_DET_EINT_SHIFT 10 /* AIF1DRC2_SIG_DET_EINT */ +#define WM8994_AIF1DRC2_SIG_DET_EINT_WIDTH 1 /* AIF1DRC2_SIG_DET_EINT */ +#define WM8994_AIF1DRC1_SIG_DET_EINT 0x0200 /* AIF1DRC1_SIG_DET_EINT */ +#define WM8994_AIF1DRC1_SIG_DET_EINT_MASK 0x0200 /* AIF1DRC1_SIG_DET_EINT */ +#define WM8994_AIF1DRC1_SIG_DET_EINT_SHIFT 9 /* AIF1DRC1_SIG_DET_EINT */ +#define WM8994_AIF1DRC1_SIG_DET_EINT_WIDTH 1 /* AIF1DRC1_SIG_DET_EINT */ +#define WM8994_SRC2_LOCK_EINT 0x0100 /* SRC2_LOCK_EINT */ +#define WM8994_SRC2_LOCK_EINT_MASK 0x0100 /* SRC2_LOCK_EINT */ +#define WM8994_SRC2_LOCK_EINT_SHIFT 8 /* SRC2_LOCK_EINT */ +#define WM8994_SRC2_LOCK_EINT_WIDTH 1 /* SRC2_LOCK_EINT */ +#define WM8994_SRC1_LOCK_EINT 0x0080 /* SRC1_LOCK_EINT */ +#define WM8994_SRC1_LOCK_EINT_MASK 0x0080 /* SRC1_LOCK_EINT */ +#define WM8994_SRC1_LOCK_EINT_SHIFT 7 /* SRC1_LOCK_EINT */ +#define WM8994_SRC1_LOCK_EINT_WIDTH 1 /* SRC1_LOCK_EINT */ +#define WM8994_FLL2_LOCK_EINT 0x0040 /* FLL2_LOCK_EINT */ +#define WM8994_FLL2_LOCK_EINT_MASK 0x0040 /* FLL2_LOCK_EINT */ +#define WM8994_FLL2_LOCK_EINT_SHIFT 6 /* FLL2_LOCK_EINT */ +#define WM8994_FLL2_LOCK_EINT_WIDTH 1 /* FLL2_LOCK_EINT */ +#define WM8994_FLL1_LOCK_EINT 0x0020 /* FLL1_LOCK_EINT */ +#define WM8994_FLL1_LOCK_EINT_MASK 0x0020 /* FLL1_LOCK_EINT */ +#define WM8994_FLL1_LOCK_EINT_SHIFT 5 /* FLL1_LOCK_EINT */ +#define WM8994_FLL1_LOCK_EINT_WIDTH 1 /* FLL1_LOCK_EINT */ +#define WM8994_MIC2_SHRT_EINT 0x0010 /* MIC2_SHRT_EINT */ +#define WM8994_MIC2_SHRT_EINT_MASK 0x0010 /* MIC2_SHRT_EINT */ +#define WM8994_MIC2_SHRT_EINT_SHIFT 4 /* MIC2_SHRT_EINT */ +#define WM8994_MIC2_SHRT_EINT_WIDTH 1 /* MIC2_SHRT_EINT */ +#define WM8994_MIC2_DET_EINT 0x0008 /* MIC2_DET_EINT */ +#define WM8994_MIC2_DET_EINT_MASK 0x0008 /* MIC2_DET_EINT */ +#define WM8994_MIC2_DET_EINT_SHIFT 3 /* MIC2_DET_EINT */ +#define WM8994_MIC2_DET_EINT_WIDTH 1 /* MIC2_DET_EINT */ +#define WM8994_MIC1_SHRT_EINT 0x0004 /* MIC1_SHRT_EINT */ +#define WM8994_MIC1_SHRT_EINT_MASK 0x0004 /* MIC1_SHRT_EINT */ +#define WM8994_MIC1_SHRT_EINT_SHIFT 2 /* MIC1_SHRT_EINT */ +#define WM8994_MIC1_SHRT_EINT_WIDTH 1 /* MIC1_SHRT_EINT */ +#define WM8994_MIC1_DET_EINT 0x0002 /* MIC1_DET_EINT */ +#define WM8994_MIC1_DET_EINT_MASK 0x0002 /* MIC1_DET_EINT */ +#define WM8994_MIC1_DET_EINT_SHIFT 1 /* MIC1_DET_EINT */ +#define WM8994_MIC1_DET_EINT_WIDTH 1 /* MIC1_DET_EINT */ +#define WM8994_TEMP_SHUT_EINT 0x0001 /* TEMP_SHUT_EINT */ +#define WM8994_TEMP_SHUT_EINT_MASK 0x0001 /* TEMP_SHUT_EINT */ +#define WM8994_TEMP_SHUT_EINT_SHIFT 0 /* TEMP_SHUT_EINT */ +#define WM8994_TEMP_SHUT_EINT_WIDTH 1 /* TEMP_SHUT_EINT */ + +/* + * R1842 (0x732) - Interrupt Raw Status 2 + */ +#define WM8994_TEMP_WARN_STS 0x8000 /* TEMP_WARN_STS */ +#define WM8994_TEMP_WARN_STS_MASK 0x8000 /* TEMP_WARN_STS */ +#define WM8994_TEMP_WARN_STS_SHIFT 15 /* TEMP_WARN_STS */ +#define WM8994_TEMP_WARN_STS_WIDTH 1 /* TEMP_WARN_STS */ +#define WM8994_DCS_DONE_STS 0x4000 /* DCS_DONE_STS */ +#define WM8994_DCS_DONE_STS_MASK 0x4000 /* DCS_DONE_STS */ +#define WM8994_DCS_DONE_STS_SHIFT 14 /* DCS_DONE_STS */ +#define WM8994_DCS_DONE_STS_WIDTH 1 /* DCS_DONE_STS */ +#define WM8994_WSEQ_DONE_STS 0x2000 /* WSEQ_DONE_STS */ +#define WM8994_WSEQ_DONE_STS_MASK 0x2000 /* WSEQ_DONE_STS */ +#define WM8994_WSEQ_DONE_STS_SHIFT 13 /* WSEQ_DONE_STS */ +#define WM8994_WSEQ_DONE_STS_WIDTH 1 /* WSEQ_DONE_STS */ +#define WM8994_FIFOS_ERR_STS 0x1000 /* FIFOS_ERR_STS */ +#define WM8994_FIFOS_ERR_STS_MASK 0x1000 /* FIFOS_ERR_STS */ +#define WM8994_FIFOS_ERR_STS_SHIFT 12 /* FIFOS_ERR_STS */ +#define WM8994_FIFOS_ERR_STS_WIDTH 1 /* FIFOS_ERR_STS */ +#define WM8994_AIF2DRC_SIG_DET_STS 0x0800 /* AIF2DRC_SIG_DET_STS */ +#define WM8994_AIF2DRC_SIG_DET_STS_MASK 0x0800 /* AIF2DRC_SIG_DET_STS */ +#define WM8994_AIF2DRC_SIG_DET_STS_SHIFT 11 /* AIF2DRC_SIG_DET_STS */ +#define WM8994_AIF2DRC_SIG_DET_STS_WIDTH 1 /* AIF2DRC_SIG_DET_STS */ +#define WM8994_AIF1DRC2_SIG_DET_STS 0x0400 /* AIF1DRC2_SIG_DET_STS */ +#define WM8994_AIF1DRC2_SIG_DET_STS_MASK 0x0400 /* AIF1DRC2_SIG_DET_STS */ +#define WM8994_AIF1DRC2_SIG_DET_STS_SHIFT 10 /* AIF1DRC2_SIG_DET_STS */ +#define WM8994_AIF1DRC2_SIG_DET_STS_WIDTH 1 /* AIF1DRC2_SIG_DET_STS */ +#define WM8994_AIF1DRC1_SIG_DET_STS 0x0200 /* AIF1DRC1_SIG_DET_STS */ +#define WM8994_AIF1DRC1_SIG_DET_STS_MASK 0x0200 /* AIF1DRC1_SIG_DET_STS */ +#define WM8994_AIF1DRC1_SIG_DET_STS_SHIFT 9 /* AIF1DRC1_SIG_DET_STS */ +#define WM8994_AIF1DRC1_SIG_DET_STS_WIDTH 1 /* AIF1DRC1_SIG_DET_STS */ +#define WM8994_SRC2_LOCK_STS 0x0100 /* SRC2_LOCK_STS */ +#define WM8994_SRC2_LOCK_STS_MASK 0x0100 /* SRC2_LOCK_STS */ +#define WM8994_SRC2_LOCK_STS_SHIFT 8 /* SRC2_LOCK_STS */ +#define WM8994_SRC2_LOCK_STS_WIDTH 1 /* SRC2_LOCK_STS */ +#define WM8994_SRC1_LOCK_STS 0x0080 /* SRC1_LOCK_STS */ +#define WM8994_SRC1_LOCK_STS_MASK 0x0080 /* SRC1_LOCK_STS */ +#define WM8994_SRC1_LOCK_STS_SHIFT 7 /* SRC1_LOCK_STS */ +#define WM8994_SRC1_LOCK_STS_WIDTH 1 /* SRC1_LOCK_STS */ +#define WM8994_FLL2_LOCK_STS 0x0040 /* FLL2_LOCK_STS */ +#define WM8994_FLL2_LOCK_STS_MASK 0x0040 /* FLL2_LOCK_STS */ +#define WM8994_FLL2_LOCK_STS_SHIFT 6 /* FLL2_LOCK_STS */ +#define WM8994_FLL2_LOCK_STS_WIDTH 1 /* FLL2_LOCK_STS */ +#define WM8994_FLL1_LOCK_STS 0x0020 /* FLL1_LOCK_STS */ +#define WM8994_FLL1_LOCK_STS_MASK 0x0020 /* FLL1_LOCK_STS */ +#define WM8994_FLL1_LOCK_STS_SHIFT 5 /* FLL1_LOCK_STS */ +#define WM8994_FLL1_LOCK_STS_WIDTH 1 /* FLL1_LOCK_STS */ +#define WM8994_MIC2_SHRT_STS 0x0010 /* MIC2_SHRT_STS */ +#define WM8994_MIC2_SHRT_STS_MASK 0x0010 /* MIC2_SHRT_STS */ +#define WM8994_MIC2_SHRT_STS_SHIFT 4 /* MIC2_SHRT_STS */ +#define WM8994_MIC2_SHRT_STS_WIDTH 1 /* MIC2_SHRT_STS */ +#define WM8994_MIC2_DET_STS 0x0008 /* MIC2_DET_STS */ +#define WM8994_MIC2_DET_STS_MASK 0x0008 /* MIC2_DET_STS */ +#define WM8994_MIC2_DET_STS_SHIFT 3 /* MIC2_DET_STS */ +#define WM8994_MIC2_DET_STS_WIDTH 1 /* MIC2_DET_STS */ +#define WM8994_MIC1_SHRT_STS 0x0004 /* MIC1_SHRT_STS */ +#define WM8994_MIC1_SHRT_STS_MASK 0x0004 /* MIC1_SHRT_STS */ +#define WM8994_MIC1_SHRT_STS_SHIFT 2 /* MIC1_SHRT_STS */ +#define WM8994_MIC1_SHRT_STS_WIDTH 1 /* MIC1_SHRT_STS */ +#define WM8994_MIC1_DET_STS 0x0002 /* MIC1_DET_STS */ +#define WM8994_MIC1_DET_STS_MASK 0x0002 /* MIC1_DET_STS */ +#define WM8994_MIC1_DET_STS_SHIFT 1 /* MIC1_DET_STS */ +#define WM8994_MIC1_DET_STS_WIDTH 1 /* MIC1_DET_STS */ +#define WM8994_TEMP_SHUT_STS 0x0001 /* TEMP_SHUT_STS */ +#define WM8994_TEMP_SHUT_STS_MASK 0x0001 /* TEMP_SHUT_STS */ +#define WM8994_TEMP_SHUT_STS_SHIFT 0 /* TEMP_SHUT_STS */ +#define WM8994_TEMP_SHUT_STS_WIDTH 1 /* TEMP_SHUT_STS */ + +/* + * R1848 (0x738) - Interrupt Status 1 Mask + */ +#define WM8994_IM_GP11_EINT 0x0400 /* IM_GP11_EINT */ +#define WM8994_IM_GP11_EINT_MASK 0x0400 /* IM_GP11_EINT */ +#define WM8994_IM_GP11_EINT_SHIFT 10 /* IM_GP11_EINT */ +#define WM8994_IM_GP11_EINT_WIDTH 1 /* IM_GP11_EINT */ +#define WM8994_IM_GP10_EINT 0x0200 /* IM_GP10_EINT */ +#define WM8994_IM_GP10_EINT_MASK 0x0200 /* IM_GP10_EINT */ +#define WM8994_IM_GP10_EINT_SHIFT 9 /* IM_GP10_EINT */ +#define WM8994_IM_GP10_EINT_WIDTH 1 /* IM_GP10_EINT */ +#define WM8994_IM_GP9_EINT 0x0100 /* IM_GP9_EINT */ +#define WM8994_IM_GP9_EINT_MASK 0x0100 /* IM_GP9_EINT */ +#define WM8994_IM_GP9_EINT_SHIFT 8 /* IM_GP9_EINT */ +#define WM8994_IM_GP9_EINT_WIDTH 1 /* IM_GP9_EINT */ +#define WM8994_IM_GP8_EINT 0x0080 /* IM_GP8_EINT */ +#define WM8994_IM_GP8_EINT_MASK 0x0080 /* IM_GP8_EINT */ +#define WM8994_IM_GP8_EINT_SHIFT 7 /* IM_GP8_EINT */ +#define WM8994_IM_GP8_EINT_WIDTH 1 /* IM_GP8_EINT */ +#define WM8994_IM_GP7_EINT 0x0040 /* IM_GP7_EINT */ +#define WM8994_IM_GP7_EINT_MASK 0x0040 /* IM_GP7_EINT */ +#define WM8994_IM_GP7_EINT_SHIFT 6 /* IM_GP7_EINT */ +#define WM8994_IM_GP7_EINT_WIDTH 1 /* IM_GP7_EINT */ +#define WM8994_IM_GP6_EINT 0x0020 /* IM_GP6_EINT */ +#define WM8994_IM_GP6_EINT_MASK 0x0020 /* IM_GP6_EINT */ +#define WM8994_IM_GP6_EINT_SHIFT 5 /* IM_GP6_EINT */ +#define WM8994_IM_GP6_EINT_WIDTH 1 /* IM_GP6_EINT */ +#define WM8994_IM_GP5_EINT 0x0010 /* IM_GP5_EINT */ +#define WM8994_IM_GP5_EINT_MASK 0x0010 /* IM_GP5_EINT */ +#define WM8994_IM_GP5_EINT_SHIFT 4 /* IM_GP5_EINT */ +#define WM8994_IM_GP5_EINT_WIDTH 1 /* IM_GP5_EINT */ +#define WM8994_IM_GP4_EINT 0x0008 /* IM_GP4_EINT */ +#define WM8994_IM_GP4_EINT_MASK 0x0008 /* IM_GP4_EINT */ +#define WM8994_IM_GP4_EINT_SHIFT 3 /* IM_GP4_EINT */ +#define WM8994_IM_GP4_EINT_WIDTH 1 /* IM_GP4_EINT */ +#define WM8994_IM_GP3_EINT 0x0004 /* IM_GP3_EINT */ +#define WM8994_IM_GP3_EINT_MASK 0x0004 /* IM_GP3_EINT */ +#define WM8994_IM_GP3_EINT_SHIFT 2 /* IM_GP3_EINT */ +#define WM8994_IM_GP3_EINT_WIDTH 1 /* IM_GP3_EINT */ +#define WM8994_IM_GP2_EINT 0x0002 /* IM_GP2_EINT */ +#define WM8994_IM_GP2_EINT_MASK 0x0002 /* IM_GP2_EINT */ +#define WM8994_IM_GP2_EINT_SHIFT 1 /* IM_GP2_EINT */ +#define WM8994_IM_GP2_EINT_WIDTH 1 /* IM_GP2_EINT */ +#define WM8994_IM_GP1_EINT 0x0001 /* IM_GP1_EINT */ +#define WM8994_IM_GP1_EINT_MASK 0x0001 /* IM_GP1_EINT */ +#define WM8994_IM_GP1_EINT_SHIFT 0 /* IM_GP1_EINT */ +#define WM8994_IM_GP1_EINT_WIDTH 1 /* IM_GP1_EINT */ + +/* + * R1849 (0x739) - Interrupt Status 2 Mask + */ +#define WM8994_IM_TEMP_WARN_EINT 0x8000 /* IM_TEMP_WARN_EINT */ +#define WM8994_IM_TEMP_WARN_EINT_MASK 0x8000 /* IM_TEMP_WARN_EINT */ +#define WM8994_IM_TEMP_WARN_EINT_SHIFT 15 /* IM_TEMP_WARN_EINT */ +#define WM8994_IM_TEMP_WARN_EINT_WIDTH 1 /* IM_TEMP_WARN_EINT */ +#define WM8994_IM_DCS_DONE_EINT 0x4000 /* IM_DCS_DONE_EINT */ +#define WM8994_IM_DCS_DONE_EINT_MASK 0x4000 /* IM_DCS_DONE_EINT */ +#define WM8994_IM_DCS_DONE_EINT_SHIFT 14 /* IM_DCS_DONE_EINT */ +#define WM8994_IM_DCS_DONE_EINT_WIDTH 1 /* IM_DCS_DONE_EINT */ +#define WM8994_IM_WSEQ_DONE_EINT 0x2000 /* IM_WSEQ_DONE_EINT */ +#define WM8994_IM_WSEQ_DONE_EINT_MASK 0x2000 /* IM_WSEQ_DONE_EINT */ +#define WM8994_IM_WSEQ_DONE_EINT_SHIFT 13 /* IM_WSEQ_DONE_EINT */ +#define WM8994_IM_WSEQ_DONE_EINT_WIDTH 1 /* IM_WSEQ_DONE_EINT */ +#define WM8994_IM_FIFOS_ERR_EINT 0x1000 /* IM_FIFOS_ERR_EINT */ +#define WM8994_IM_FIFOS_ERR_EINT_MASK 0x1000 /* IM_FIFOS_ERR_EINT */ +#define WM8994_IM_FIFOS_ERR_EINT_SHIFT 12 /* IM_FIFOS_ERR_EINT */ +#define WM8994_IM_FIFOS_ERR_EINT_WIDTH 1 /* IM_FIFOS_ERR_EINT */ +#define WM8994_IM_AIF2DRC_SIG_DET_EINT 0x0800 /* IM_AIF2DRC_SIG_DET_EINT */ +#define WM8994_IM_AIF2DRC_SIG_DET_EINT_MASK 0x0800 /* IM_AIF2DRC_SIG_DET_EINT */ +#define WM8994_IM_AIF2DRC_SIG_DET_EINT_SHIFT 11 /* IM_AIF2DRC_SIG_DET_EINT */ +#define WM8994_IM_AIF2DRC_SIG_DET_EINT_WIDTH 1 /* IM_AIF2DRC_SIG_DET_EINT */ +#define WM8994_IM_AIF1DRC2_SIG_DET_EINT 0x0400 /* IM_AIF1DRC2_SIG_DET_EINT */ +#define WM8994_IM_AIF1DRC2_SIG_DET_EINT_MASK 0x0400 /* IM_AIF1DRC2_SIG_DET_EINT */ +#define WM8994_IM_AIF1DRC2_SIG_DET_EINT_SHIFT 10 /* IM_AIF1DRC2_SIG_DET_EINT */ +#define WM8994_IM_AIF1DRC2_SIG_DET_EINT_WIDTH 1 /* IM_AIF1DRC2_SIG_DET_EINT */ +#define WM8994_IM_AIF1DRC1_SIG_DET_EINT 0x0200 /* IM_AIF1DRC1_SIG_DET_EINT */ +#define WM8994_IM_AIF1DRC1_SIG_DET_EINT_MASK 0x0200 /* IM_AIF1DRC1_SIG_DET_EINT */ +#define WM8994_IM_AIF1DRC1_SIG_DET_EINT_SHIFT 9 /* IM_AIF1DRC1_SIG_DET_EINT */ +#define WM8994_IM_AIF1DRC1_SIG_DET_EINT_WIDTH 1 /* IM_AIF1DRC1_SIG_DET_EINT */ +#define WM8994_IM_SRC2_LOCK_EINT 0x0100 /* IM_SRC2_LOCK_EINT */ +#define WM8994_IM_SRC2_LOCK_EINT_MASK 0x0100 /* IM_SRC2_LOCK_EINT */ +#define WM8994_IM_SRC2_LOCK_EINT_SHIFT 8 /* IM_SRC2_LOCK_EINT */ +#define WM8994_IM_SRC2_LOCK_EINT_WIDTH 1 /* IM_SRC2_LOCK_EINT */ +#define WM8994_IM_SRC1_LOCK_EINT 0x0080 /* IM_SRC1_LOCK_EINT */ +#define WM8994_IM_SRC1_LOCK_EINT_MASK 0x0080 /* IM_SRC1_LOCK_EINT */ +#define WM8994_IM_SRC1_LOCK_EINT_SHIFT 7 /* IM_SRC1_LOCK_EINT */ +#define WM8994_IM_SRC1_LOCK_EINT_WIDTH 1 /* IM_SRC1_LOCK_EINT */ +#define WM8994_IM_FLL2_LOCK_EINT 0x0040 /* IM_FLL2_LOCK_EINT */ +#define WM8994_IM_FLL2_LOCK_EINT_MASK 0x0040 /* IM_FLL2_LOCK_EINT */ +#define WM8994_IM_FLL2_LOCK_EINT_SHIFT 6 /* IM_FLL2_LOCK_EINT */ +#define WM8994_IM_FLL2_LOCK_EINT_WIDTH 1 /* IM_FLL2_LOCK_EINT */ +#define WM8994_IM_FLL1_LOCK_EINT 0x0020 /* IM_FLL1_LOCK_EINT */ +#define WM8994_IM_FLL1_LOCK_EINT_MASK 0x0020 /* IM_FLL1_LOCK_EINT */ +#define WM8994_IM_FLL1_LOCK_EINT_SHIFT 5 /* IM_FLL1_LOCK_EINT */ +#define WM8994_IM_FLL1_LOCK_EINT_WIDTH 1 /* IM_FLL1_LOCK_EINT */ +#define WM8994_IM_MIC2_SHRT_EINT 0x0010 /* IM_MIC2_SHRT_EINT */ +#define WM8994_IM_MIC2_SHRT_EINT_MASK 0x0010 /* IM_MIC2_SHRT_EINT */ +#define WM8994_IM_MIC2_SHRT_EINT_SHIFT 4 /* IM_MIC2_SHRT_EINT */ +#define WM8994_IM_MIC2_SHRT_EINT_WIDTH 1 /* IM_MIC2_SHRT_EINT */ +#define WM8994_IM_MIC2_DET_EINT 0x0008 /* IM_MIC2_DET_EINT */ +#define WM8994_IM_MIC2_DET_EINT_MASK 0x0008 /* IM_MIC2_DET_EINT */ +#define WM8994_IM_MIC2_DET_EINT_SHIFT 3 /* IM_MIC2_DET_EINT */ +#define WM8994_IM_MIC2_DET_EINT_WIDTH 1 /* IM_MIC2_DET_EINT */ +#define WM8994_IM_MIC1_SHRT_EINT 0x0004 /* IM_MIC1_SHRT_EINT */ +#define WM8994_IM_MIC1_SHRT_EINT_MASK 0x0004 /* IM_MIC1_SHRT_EINT */ +#define WM8994_IM_MIC1_SHRT_EINT_SHIFT 2 /* IM_MIC1_SHRT_EINT */ +#define WM8994_IM_MIC1_SHRT_EINT_WIDTH 1 /* IM_MIC1_SHRT_EINT */ +#define WM8994_IM_MIC1_DET_EINT 0x0002 /* IM_MIC1_DET_EINT */ +#define WM8994_IM_MIC1_DET_EINT_MASK 0x0002 /* IM_MIC1_DET_EINT */ +#define WM8994_IM_MIC1_DET_EINT_SHIFT 1 /* IM_MIC1_DET_EINT */ +#define WM8994_IM_MIC1_DET_EINT_WIDTH 1 /* IM_MIC1_DET_EINT */ +#define WM8994_IM_TEMP_SHUT_EINT 0x0001 /* IM_TEMP_SHUT_EINT */ +#define WM8994_IM_TEMP_SHUT_EINT_MASK 0x0001 /* IM_TEMP_SHUT_EINT */ +#define WM8994_IM_TEMP_SHUT_EINT_SHIFT 0 /* IM_TEMP_SHUT_EINT */ +#define WM8994_IM_TEMP_SHUT_EINT_WIDTH 1 /* IM_TEMP_SHUT_EINT */ + +/* + * R1856 (0x740) - Interrupt Control + */ +#define WM8994_IM_IRQ 0x0001 /* IM_IRQ */ +#define WM8994_IM_IRQ_MASK 0x0001 /* IM_IRQ */ +#define WM8994_IM_IRQ_SHIFT 0 /* IM_IRQ */ +#define WM8994_IM_IRQ_WIDTH 1 /* IM_IRQ */ + +/* + * R1864 (0x748) - IRQ Debounce + */ +#define WM8994_TEMP_WARN_DB 0x0020 /* TEMP_WARN_DB */ +#define WM8994_TEMP_WARN_DB_MASK 0x0020 /* TEMP_WARN_DB */ +#define WM8994_TEMP_WARN_DB_SHIFT 5 /* TEMP_WARN_DB */ +#define WM8994_TEMP_WARN_DB_WIDTH 1 /* TEMP_WARN_DB */ +#define WM8994_MIC2_SHRT_DB 0x0010 /* MIC2_SHRT_DB */ +#define WM8994_MIC2_SHRT_DB_MASK 0x0010 /* MIC2_SHRT_DB */ +#define WM8994_MIC2_SHRT_DB_SHIFT 4 /* MIC2_SHRT_DB */ +#define WM8994_MIC2_SHRT_DB_WIDTH 1 /* MIC2_SHRT_DB */ +#define WM8994_MIC2_DET_DB 0x0008 /* MIC2_DET_DB */ +#define WM8994_MIC2_DET_DB_MASK 0x0008 /* MIC2_DET_DB */ +#define WM8994_MIC2_DET_DB_SHIFT 3 /* MIC2_DET_DB */ +#define WM8994_MIC2_DET_DB_WIDTH 1 /* MIC2_DET_DB */ +#define WM8994_MIC1_SHRT_DB 0x0004 /* MIC1_SHRT_DB */ +#define WM8994_MIC1_SHRT_DB_MASK 0x0004 /* MIC1_SHRT_DB */ +#define WM8994_MIC1_SHRT_DB_SHIFT 2 /* MIC1_SHRT_DB */ +#define WM8994_MIC1_SHRT_DB_WIDTH 1 /* MIC1_SHRT_DB */ +#define WM8994_MIC1_DET_DB 0x0002 /* MIC1_DET_DB */ +#define WM8994_MIC1_DET_DB_MASK 0x0002 /* MIC1_DET_DB */ +#define WM8994_MIC1_DET_DB_SHIFT 1 /* MIC1_DET_DB */ +#define WM8994_MIC1_DET_DB_WIDTH 1 /* MIC1_DET_DB */ +#define WM8994_TEMP_SHUT_DB 0x0001 /* TEMP_SHUT_DB */ +#define WM8994_TEMP_SHUT_DB_MASK 0x0001 /* TEMP_SHUT_DB */ +#define WM8994_TEMP_SHUT_DB_SHIFT 0 /* TEMP_SHUT_DB */ +#define WM8994_TEMP_SHUT_DB_WIDTH 1 /* TEMP_SHUT_DB */ + +#endif -- cgit v0.10.2 From 9e50108668a70a9927257298bd4e679300124420 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Jan 2010 18:20:29 +0000 Subject: mfd: Add initial WM8994 support The WM8994 is a highly integrated ultra low power audio hub CODEC. Since it includes on-board regulators and GPIOs it is represented as a multi-function device, though the overwhelming majority of the functionality is provided by the ASoC CODEC driver. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index a760dbe..64fbe33 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -295,6 +295,18 @@ config MFD_WM8350_I2C I2C as the control interface. Additional options must be selected to enable support for the functionality of the chip. +config MFD_WM8994 + tristate "Support Wolfson Microelectronics WM8994" + select MFD_CORE + depends on I2C + help + The WM8994 is a highly integrated hi-fi CODEC designed for + smartphone applicatiosn. As well as audio functionality it + has on board GPIO and regulator functionality which is + supported via the relevant subsystems. This driver provides + core support for the WM8994, in order to use the actual + functionaltiy of the device other drivers must be enabled. + config MFD_PCF50633 tristate "Support for NXP PCF50633" depends on I2C diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 142d312..878cac6 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -25,6 +25,7 @@ wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o wm8350-objs += wm8350-irq.o obj-$(CONFIG_MFD_WM8350) += wm8350.o obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o +obj-$(CONFIG_MFD_WM8994) += wm8994-core.o obj-$(CONFIG_TPS65010) += tps65010.o obj-$(CONFIG_MENELAUS) += menelaus.o diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c new file mode 100644 index 0000000..299c1af --- /dev/null +++ b/drivers/mfd/wm8994-core.c @@ -0,0 +1,537 @@ +/* + * wm8994-core.c -- Device access for Wolfson WM8994 + * + * Copyright 2009 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static int wm8994_read(struct wm8994 *wm8994, unsigned short reg, + int bytes, void *dest) +{ + int ret, i; + u16 *buf = dest; + + BUG_ON(bytes % 2); + BUG_ON(bytes <= 0); + + ret = wm8994->read_dev(wm8994, reg, bytes, dest); + if (ret < 0) + return ret; + + for (i = 0; i < bytes / 2; i++) { + buf[i] = be16_to_cpu(buf[i]); + + dev_vdbg(wm8994->dev, "Read %04x from R%d(0x%x)\n", + buf[i], reg + i, reg + i); + } + + return 0; +} + +/** + * wm8994_reg_read: Read a single WM8994 register. + * + * @wm8994: Device to read from. + * @reg: Register to read. + */ +int wm8994_reg_read(struct wm8994 *wm8994, unsigned short reg) +{ + unsigned short val; + int ret; + + mutex_lock(&wm8994->io_lock); + + ret = wm8994_read(wm8994, reg, 2, &val); + + mutex_unlock(&wm8994->io_lock); + + if (ret < 0) + return ret; + else + return val; +} +EXPORT_SYMBOL_GPL(wm8994_reg_read); + +/** + * wm8994_bulk_read: Read multiple WM8994 registers + * + * @wm8994: Device to read from + * @reg: First register + * @count: Number of registers + * @buf: Buffer to fill. + */ +int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg, + int count, u16 *buf) +{ + int ret; + + mutex_lock(&wm8994->io_lock); + + ret = wm8994_read(wm8994, reg, count * 2, buf); + + mutex_unlock(&wm8994->io_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm8994_bulk_read); + +static int wm8994_write(struct wm8994 *wm8994, unsigned short reg, + int bytes, void *src) +{ + u16 *buf = src; + int i; + + BUG_ON(bytes % 2); + BUG_ON(bytes <= 0); + + for (i = 0; i < bytes / 2; i++) { + dev_vdbg(wm8994->dev, "Write %04x to R%d(0x%x)\n", + buf[i], reg + i, reg + i); + + buf[i] = cpu_to_be16(buf[i]); + } + + return wm8994->write_dev(wm8994, reg, bytes, src); +} + +/** + * wm8994_reg_write: Write a single WM8994 register. + * + * @wm8994: Device to write to. + * @reg: Register to write to. + * @val: Value to write. + */ +int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg, + unsigned short val) +{ + int ret; + + mutex_lock(&wm8994->io_lock); + + ret = wm8994_write(wm8994, reg, 2, &val); + + mutex_unlock(&wm8994->io_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm8994_reg_write); + +/** + * wm8994_set_bits: Set the value of a bitfield in a WM8994 register + * + * @wm8994: Device to write to. + * @reg: Register to write to. + * @mask: Mask of bits to set. + * @val: Value to set (unshifted) + */ +int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg, + unsigned short mask, unsigned short val) +{ + int ret; + u16 r; + + mutex_lock(&wm8994->io_lock); + + ret = wm8994_read(wm8994, reg, 2, &r); + if (ret < 0) + goto out; + + r &= ~mask; + r |= val; + + ret = wm8994_write(wm8994, reg, 2, &r); + +out: + mutex_unlock(&wm8994->io_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm8994_set_bits); + +static struct mfd_cell wm8994_regulator_devs[] = { + { .name = "wm8994-ldo", .id = 1 }, + { .name = "wm8994-ldo", .id = 2 }, +}; + +static struct mfd_cell wm8994_devs[] = { + { .name = "wm8994-codec" }, + { .name = "wm8994-gpio" }, +}; + +/* + * Supplies for the main bulk of CODEC; the LDO supplies are ignored + * and should be handled via the standard regulator API supply + * management. + */ +static const char *wm8994_main_supplies[] = { + "DBVDD", + "DCVDD", + "AVDD1", + "AVDD2", + "CPVDD", + "SPKVDD1", + "SPKVDD2", +}; + +#ifdef CONFIG_PM +static int wm8994_device_suspend(struct device *dev) +{ + struct wm8994 *wm8994 = dev_get_drvdata(dev); + int ret; + + /* GPIO configuration state is saved here since we may be configuring + * the GPIO alternate functions even if we're not using the gpiolib + * driver for them. + */ + ret = wm8994_read(wm8994, WM8994_GPIO_1, WM8994_NUM_GPIO_REGS * 2, + &wm8994->gpio_regs); + if (ret < 0) + dev_err(dev, "Failed to save GPIO registers: %d\n", ret); + + /* For similar reasons we also stash the regulator states */ + ret = wm8994_read(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2, + &wm8994->ldo_regs); + if (ret < 0) + dev_err(dev, "Failed to save LDO registers: %d\n", ret); + + ret = regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies), + wm8994->supplies); + if (ret != 0) { + dev_err(dev, "Failed to disable supplies: %d\n", ret); + return ret; + } + + return 0; +} + +static int wm8994_device_resume(struct device *dev) +{ + struct wm8994 *wm8994 = dev_get_drvdata(dev); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies), + wm8994->supplies); + if (ret != 0) { + dev_err(dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + + ret = wm8994_write(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2, + &wm8994->ldo_regs); + if (ret < 0) + dev_err(dev, "Failed to restore LDO registers: %d\n", ret); + + ret = wm8994_write(wm8994, WM8994_GPIO_1, WM8994_NUM_GPIO_REGS * 2, + &wm8994->gpio_regs); + if (ret < 0) + dev_err(dev, "Failed to restore GPIO registers: %d\n", ret); + + return 0; +} +#endif + +#ifdef CONFIG_REGULATOR +static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo) +{ + struct wm8994_ldo_pdata *ldo_pdata; + + if (!pdata) + return 0; + + ldo_pdata = &pdata->ldo[ldo]; + + if (!ldo_pdata->init_data) + return 0; + + return ldo_pdata->init_data->num_consumer_supplies != 0; +} +#else +static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo) +{ + return 0; +} +#endif + +/* + * Instantiate the generic non-control parts of the device. + */ +static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) +{ + struct wm8994_pdata *pdata = wm8994->dev->platform_data; + int ret, i; + + mutex_init(&wm8994->io_lock); + dev_set_drvdata(wm8994->dev, wm8994); + + /* Add the on-chip regulators first for bootstrapping */ + ret = mfd_add_devices(wm8994->dev, -1, + wm8994_regulator_devs, + ARRAY_SIZE(wm8994_regulator_devs), + NULL, 0); + if (ret != 0) { + dev_err(wm8994->dev, "Failed to add children: %d\n", ret); + goto err; + } + + wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) * + ARRAY_SIZE(wm8994_main_supplies), + GFP_KERNEL); + if (!wm8994->supplies) + goto err; + + for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++) + wm8994->supplies[i].supply = wm8994_main_supplies[i]; + + ret = regulator_bulk_get(wm8994->dev, ARRAY_SIZE(wm8994_main_supplies), + wm8994->supplies); + if (ret != 0) { + dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret); + goto err_get; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies), + wm8994->supplies); + if (ret != 0) { + dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret); + goto err_supplies; + } + + ret = wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET); + if (ret < 0) { + dev_err(wm8994->dev, "Failed to read ID register\n"); + goto err_enable; + } + if (ret != 0x8994) { + dev_err(wm8994->dev, "Device is not a WM8994, ID is %x\n", + ret); + ret = -EINVAL; + goto err_enable; + } + + ret = wm8994_reg_read(wm8994, WM8994_CHIP_REVISION); + if (ret < 0) { + dev_err(wm8994->dev, "Failed to read revision register: %d\n", + ret); + goto err_enable; + } + + switch (ret) { + case 0: + case 1: + dev_warn(wm8994->dev, "revision %c not fully supported\n", + 'A' + ret); + break; + default: + dev_info(wm8994->dev, "revision %c\n", 'A' + ret); + break; + } + + + if (pdata) { + wm8994->gpio_base = pdata->gpio_base; + + /* GPIO configuration is only applied if it's non-zero */ + for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { + if (pdata->gpio_defaults[i]) { + wm8994_set_bits(wm8994, WM8994_GPIO_1 + i, + 0xffff, + pdata->gpio_defaults[i]); + } + } + } + + /* In some system designs where the regulators are not in use, + * we can achieve a small reduction in leakage currents by + * floating LDO outputs. This bit makes no difference if the + * LDOs are enabled, it only affects cases where the LDOs were + * in operation and are then disabled. + */ + for (i = 0; i < WM8994_NUM_LDO_REGS; i++) { + if (wm8994_ldo_in_use(pdata, i)) + wm8994_set_bits(wm8994, WM8994_LDO_1 + i, + WM8994_LDO1_DISCH, WM8994_LDO1_DISCH); + else + wm8994_set_bits(wm8994, WM8994_LDO_1 + i, + WM8994_LDO1_DISCH, 0); + } + + ret = mfd_add_devices(wm8994->dev, -1, + wm8994_devs, ARRAY_SIZE(wm8994_devs), + NULL, 0); + if (ret != 0) { + dev_err(wm8994->dev, "Failed to add children: %d\n", ret); + goto err_enable; + } + + return 0; + +err_enable: + regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies), + wm8994->supplies); +err_get: + regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies); +err_supplies: + kfree(wm8994->supplies); +err: + mfd_remove_devices(wm8994->dev); + kfree(wm8994); + return ret; +} + +static void wm8994_device_exit(struct wm8994 *wm8994) +{ + mfd_remove_devices(wm8994->dev); + regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies), + wm8994->supplies); + regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies); + kfree(wm8994->supplies); + kfree(wm8994); +} + +static int wm8994_i2c_read_device(struct wm8994 *wm8994, unsigned short reg, + int bytes, void *dest) +{ + struct i2c_client *i2c = wm8994->control_data; + int ret; + u16 r = cpu_to_be16(reg); + + ret = i2c_master_send(i2c, (unsigned char *)&r, 2); + if (ret < 0) + return ret; + if (ret != 2) + return -EIO; + + ret = i2c_master_recv(i2c, dest, bytes); + if (ret < 0) + return ret; + if (ret != bytes) + return -EIO; + return 0; +} + +/* Currently we allocate the write buffer on the stack; this is OK for + * small writes - if we need to do large writes this will need to be + * revised. + */ +static int wm8994_i2c_write_device(struct wm8994 *wm8994, unsigned short reg, + int bytes, void *src) +{ + struct i2c_client *i2c = wm8994->control_data; + unsigned char msg[bytes + 2]; + int ret; + + reg = cpu_to_be16(reg); + memcpy(&msg[0], ®, 2); + memcpy(&msg[2], src, bytes); + + ret = i2c_master_send(i2c, msg, bytes + 2); + if (ret < 0) + return ret; + if (ret < bytes + 2) + return -EIO; + + return 0; +} + +static int wm8994_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct wm8994 *wm8994; + + wm8994 = kzalloc(sizeof(struct wm8994), GFP_KERNEL); + if (wm8994 == NULL) { + kfree(i2c); + return -ENOMEM; + } + + i2c_set_clientdata(i2c, wm8994); + wm8994->dev = &i2c->dev; + wm8994->control_data = i2c; + wm8994->read_dev = wm8994_i2c_read_device; + wm8994->write_dev = wm8994_i2c_write_device; + + return wm8994_device_init(wm8994, id->driver_data, i2c->irq); +} + +static int wm8994_i2c_remove(struct i2c_client *i2c) +{ + struct wm8994 *wm8994 = i2c_get_clientdata(i2c); + + wm8994_device_exit(wm8994); + + return 0; +} + +#ifdef CONFIG_PM +static int wm8994_i2c_suspend(struct i2c_client *i2c, pm_message_t state) +{ + return wm8994_device_suspend(&i2c->dev); +} + +static int wm8994_i2c_resume(struct i2c_client *i2c) +{ + return wm8994_device_resume(&i2c->dev); +} +#else +#define wm8994_i2c_suspend NULL +#define wm8994_i2c_resume NULL +#endif + +static const struct i2c_device_id wm8994_i2c_id[] = { + { "wm8994", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); + +static struct i2c_driver wm8994_i2c_driver = { + .driver = { + .name = "wm8994", + .owner = THIS_MODULE, + }, + .probe = wm8994_i2c_probe, + .remove = wm8994_i2c_remove, + .suspend = wm8994_i2c_suspend, + .resume = wm8994_i2c_resume, + .id_table = wm8994_i2c_id, +}; + +static int __init wm8994_i2c_init(void) +{ + int ret; + + ret = i2c_add_driver(&wm8994_i2c_driver); + if (ret != 0) + pr_err("Failed to register wm8994 I2C driver: %d\n", ret); + + return ret; +} +module_init(wm8994_i2c_init); + +static void __exit wm8994_i2c_exit(void) +{ + i2c_del_driver(&wm8994_i2c_driver); +} +module_exit(wm8994_i2c_exit); + +MODULE_DESCRIPTION("Core support for the WM8994 audio CODEC"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mark Brown "); diff --git a/include/linux/mfd/wm8994/core.h b/include/linux/mfd/wm8994/core.h new file mode 100644 index 0000000..b06ff28 --- /dev/null +++ b/include/linux/mfd/wm8994/core.h @@ -0,0 +1,54 @@ +/* + * include/linux/mfd/wm8994/core.h -- Core interface for WM8994 + * + * Copyright 2009 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MFD_WM8994_CORE_H__ +#define __MFD_WM8994_CORE_H__ + +struct regulator_dev; +struct regulator_bulk_data; + +#define WM8994_NUM_GPIO_REGS 11 +#define WM8994_NUM_LDO_REGS 2 + +struct wm8994 { + struct mutex io_lock; + + struct device *dev; + int (*read_dev)(struct wm8994 *wm8994, unsigned short reg, + int bytes, void *dest); + int (*write_dev)(struct wm8994 *wm8994, unsigned short reg, + int bytes, void *src); + + void *control_data; + + int gpio_base; + + /* Used over suspend/resume */ + u16 ldo_regs[WM8994_NUM_LDO_REGS]; + u16 gpio_regs[WM8994_NUM_GPIO_REGS]; + + struct regulator_dev *dbvdd; + struct regulator_bulk_data *supplies; +}; + +/* Device I/O API */ +int wm8994_reg_read(struct wm8994 *wm8994, unsigned short reg); +int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg, + unsigned short val); +int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg, + unsigned short mask, unsigned short val); +int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg, + int count, u16 *buf); + +#endif diff --git a/include/linux/mfd/wm8994/gpio.h b/include/linux/mfd/wm8994/gpio.h new file mode 100644 index 0000000..b4d4c22 --- /dev/null +++ b/include/linux/mfd/wm8994/gpio.h @@ -0,0 +1,72 @@ +/* + * include/linux/mfd/wm8994/gpio.h - GPIO configuration for WM8994 + * + * Copyright 2009 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MFD_WM8994_GPIO_H__ +#define __MFD_WM8994_GPIO_H__ + +#define WM8994_GPIO_MAX 11 + +#define WM8994_GP_FN_PIN_SPECIFIC 0 +#define WM8994_GP_FN_GPIO 1 +#define WM8994_GP_FN_SDOUT 2 +#define WM8994_GP_FN_IRQ 3 +#define WM8994_GP_FN_TEMPERATURE 4 +#define WM8994_GP_FN_MICBIAS1_DET 5 +#define WM8994_GP_FN_MICBIAS1_SHORT 6 +#define WM8994_GP_FN_MICBIAS2_DET 7 +#define WM8994_GP_FN_MICBIAS2_SHORT 8 +#define WM8994_GP_FN_FLL1_LOCK 9 +#define WM8994_GP_FN_FLL2_LOCK 10 +#define WM8994_GP_FN_SRC1_LOCK 11 +#define WM8994_GP_FN_SRC2_LOCK 12 +#define WM8994_GP_FN_DRC1_ACT 13 +#define WM8994_GP_FN_DRC2_ACT 14 +#define WM8994_GP_FN_DRC3_ACT 15 +#define WM8994_GP_FN_WSEQ_STATUS 16 +#define WM8994_GP_FN_FIFO_ERROR 17 +#define WM8994_GP_FN_OPCLK 18 + +#define WM8994_GPN_DIR 0x8000 /* GPN_DIR */ +#define WM8994_GPN_DIR_MASK 0x8000 /* GPN_DIR */ +#define WM8994_GPN_DIR_SHIFT 15 /* GPN_DIR */ +#define WM8994_GPN_DIR_WIDTH 1 /* GPN_DIR */ +#define WM8994_GPN_PU 0x4000 /* GPN_PU */ +#define WM8994_GPN_PU_MASK 0x4000 /* GPN_PU */ +#define WM8994_GPN_PU_SHIFT 14 /* GPN_PU */ +#define WM8994_GPN_PU_WIDTH 1 /* GPN_PU */ +#define WM8994_GPN_PD 0x2000 /* GPN_PD */ +#define WM8994_GPN_PD_MASK 0x2000 /* GPN_PD */ +#define WM8994_GPN_PD_SHIFT 13 /* GPN_PD */ +#define WM8994_GPN_PD_WIDTH 1 /* GPN_PD */ +#define WM8994_GPN_POL 0x0400 /* GPN_POL */ +#define WM8994_GPN_POL_MASK 0x0400 /* GPN_POL */ +#define WM8994_GPN_POL_SHIFT 10 /* GPN_POL */ +#define WM8994_GPN_POL_WIDTH 1 /* GPN_POL */ +#define WM8994_GPN_OP_CFG 0x0200 /* GPN_OP_CFG */ +#define WM8994_GPN_OP_CFG_MASK 0x0200 /* GPN_OP_CFG */ +#define WM8994_GPN_OP_CFG_SHIFT 9 /* GPN_OP_CFG */ +#define WM8994_GPN_OP_CFG_WIDTH 1 /* GPN_OP_CFG */ +#define WM8994_GPN_DB 0x0100 /* GPN_DB */ +#define WM8994_GPN_DB_MASK 0x0100 /* GPN_DB */ +#define WM8994_GPN_DB_SHIFT 8 /* GPN_DB */ +#define WM8994_GPN_DB_WIDTH 1 /* GPN_DB */ +#define WM8994_GPN_LVL 0x0040 /* GPN_LVL */ +#define WM8994_GPN_LVL_MASK 0x0040 /* GPN_LVL */ +#define WM8994_GPN_LVL_SHIFT 6 /* GPN_LVL */ +#define WM8994_GPN_LVL_WIDTH 1 /* GPN_LVL */ +#define WM8994_GPN_FN_MASK 0x001F /* GPN_FN - [4:0] */ +#define WM8994_GPN_FN_SHIFT 0 /* GPN_FN - [4:0] */ +#define WM8994_GPN_FN_WIDTH 5 /* GPN_FN - [4:0] */ + +#endif diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h new file mode 100644 index 0000000..70d6a86 --- /dev/null +++ b/include/linux/mfd/wm8994/pdata.h @@ -0,0 +1,97 @@ +/* + * include/linux/mfd/wm8994/pdata.h -- Platform data for WM8994 + * + * Copyright 2009 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __MFD_WM8994_PDATA_H__ +#define __MFD_WM8994_PDATA_H__ + +#define WM8994_NUM_LDO 2 +#define WM8994_NUM_GPIO 11 + +struct wm8994_ldo_pdata { + /** GPIOs to enable regulator, 0 or less if not available */ + int enable; + + const char *supply; + struct regulator_init_data *init_data; +}; + +#define WM8994_CONFIGURE_GPIO 0x8000 + +#define WM8994_DRC_REGS 5 +#define WM8994_EQ_REGS 19 + +/** + * DRC configurations are specified with a label and a set of register + * values to write (the enable bits will be ignored). At runtime an + * enumerated control will be presented for each DRC block allowing + * the user to choose the configration to use. + * + * Configurations may be generated by hand or by using the DRC control + * panel provided by the WISCE - see http://www.wolfsonmicro.com/wisce/ + * for details. + */ +struct wm8994_drc_cfg { + const char *name; + u16 regs[WM8994_DRC_REGS]; +}; + +/** + * ReTune Mobile configurations are specified with a label, sample + * rate and set of values to write (the enable bits will be ignored). + * + * Configurations are expected to be generated using the ReTune Mobile + * control panel in WISCE - see http://www.wolfsonmicro.com/wisce/ + */ +struct wm8994_retune_mobile_cfg { + const char *name; + unsigned int rate; + u16 regs[WM8994_EQ_REGS]; +}; + +struct wm8994_pdata { + int gpio_base; + + /** + * Default values for GPIOs if non-zero, WM8994_CONFIGURE_GPIO + * can be used for all zero values. + */ + int gpio_defaults[WM8994_NUM_GPIO]; + + struct wm8994_ldo_pdata ldo[WM8994_NUM_LDO]; + + + int num_drc_cfgs; + struct wm8994_drc_cfg *drc_cfgs; + + int num_retune_mobile_cfgs; + struct wm8994_retune_mobile_cfg *retune_mobile_cfgs; + + /* LINEOUT can be differential or single ended */ + unsigned int lineout1_diff:1; + unsigned int lineout2_diff:1; + + /* Common mode feedback */ + unsigned int lineout1fb:1; + unsigned int lineout2fb:1; + + /* Microphone biases: 0=0.9*AVDD1 1=0.65*AVVD1 */ + unsigned int micbias1_lvl:1; + unsigned int micbias2_lvl:1; + + /* Jack detect threashold levels, see datasheet for values */ + unsigned int jd_scthr:2; + unsigned int jd_thr:2; +}; + +#endif -- cgit v0.10.2 From 2955c309921e23d592ef585cf8e7ded1e11565b7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Jan 2010 18:20:30 +0000 Subject: gpiolib: Add WM8994 GPIO support The WM8994 has 11 GPIO lines. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index acac9f6..f42cb31 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -192,6 +192,13 @@ config GPIO_WM8350 Say yes here to access the GPIO signals of WM8350 power management chips from Wolfson Microelectronics. +config GPIO_WM8994 + tristate "WM8994 GPIOs" + depends on MFD_WM8994 + help + Say yes here to access the GPIO signals of WM8994 audio hub + CODECs from Wolfson Microelectronics. + config GPIO_ADP5520 tristate "GPIO Support for ADP5520 PMIC" depends on PMIC_ADP5520 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 90b0880..594bb70 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -26,3 +26,4 @@ obj-$(CONFIG_GPIO_IT8761E) += it8761e_gpio.o obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o obj-$(CONFIG_GPIO_WM8350) += wm8350-gpiolib.o +obj-$(CONFIG_GPIO_WM8994) += wm8994-gpio.o diff --git a/drivers/gpio/wm8994-gpio.c b/drivers/gpio/wm8994-gpio.c new file mode 100644 index 0000000..de28b4a4 --- /dev/null +++ b/drivers/gpio/wm8994-gpio.c @@ -0,0 +1,204 @@ +/* + * wm8994-gpio.c -- gpiolib support for Wolfson WM8994 + * + * Copyright 2009 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct wm8994_gpio { + struct wm8994 *wm8994; + struct gpio_chip gpio_chip; +}; + +static inline struct wm8994_gpio *to_wm8994_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct wm8994_gpio, gpio_chip); +} + +static int wm8994_gpio_direction_in(struct gpio_chip *chip, unsigned offset) +{ + struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip); + struct wm8994 *wm8994 = wm8994_gpio->wm8994; + + return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, + WM8994_GPN_DIR, WM8994_GPN_DIR); +} + +static int wm8994_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip); + struct wm8994 *wm8994 = wm8994_gpio->wm8994; + int ret; + + ret = wm8994_reg_read(wm8994, WM8994_GPIO_1 + offset); + if (ret < 0) + return ret; + + if (ret & WM8994_GPN_LVL) + return 1; + else + return 0; +} + +static int wm8994_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip); + struct wm8994 *wm8994 = wm8994_gpio->wm8994; + + return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, + WM8994_GPN_DIR, 0); +} + +static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip); + struct wm8994 *wm8994 = wm8994_gpio->wm8994; + + if (value) + value = WM8994_GPN_LVL; + + wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, WM8994_GPN_LVL, value); +} + +#ifdef CONFIG_DEBUG_FS +static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip); + struct wm8994 *wm8994 = wm8994_gpio->wm8994; + int i; + + for (i = 0; i < chip->ngpio; i++) { + int gpio = i + chip->base; + int reg; + const char *label; + + /* We report the GPIO even if it's not requested since + * we're also reporting things like alternate + * functions which apply even when the GPIO is not in + * use as a GPIO. + */ + label = gpiochip_is_requested(chip, i); + if (!label) + label = "Unrequested"; + + seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, label); + + reg = wm8994_reg_read(wm8994, WM8994_GPIO_1 + i); + if (reg < 0) { + dev_err(wm8994->dev, + "GPIO control %d read failed: %d\n", + gpio, reg); + seq_printf(s, "\n"); + continue; + } + + /* No decode yet; note that GPIO2 is special */ + seq_printf(s, "(%x)\n", reg); + } +} +#else +#define wm8994_gpio_dbg_show NULL +#endif + +static struct gpio_chip template_chip = { + .label = "wm8994", + .owner = THIS_MODULE, + .direction_input = wm8994_gpio_direction_in, + .get = wm8994_gpio_get, + .direction_output = wm8994_gpio_direction_out, + .set = wm8994_gpio_set, + .dbg_show = wm8994_gpio_dbg_show, + .can_sleep = 1, +}; + +static int __devinit wm8994_gpio_probe(struct platform_device *pdev) +{ + struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent); + struct wm8994_pdata *pdata = wm8994->dev->platform_data; + struct wm8994_gpio *wm8994_gpio; + int ret; + + wm8994_gpio = kzalloc(sizeof(*wm8994_gpio), GFP_KERNEL); + if (wm8994_gpio == NULL) + return -ENOMEM; + + wm8994_gpio->wm8994 = wm8994; + wm8994_gpio->gpio_chip = template_chip; + wm8994_gpio->gpio_chip.ngpio = WM8994_GPIO_MAX; + wm8994_gpio->gpio_chip.dev = &pdev->dev; + if (pdata && pdata->gpio_base) + wm8994_gpio->gpio_chip.base = pdata->gpio_base; + else + wm8994_gpio->gpio_chip.base = -1; + + ret = gpiochip_add(&wm8994_gpio->gpio_chip); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", + ret); + goto err; + } + + platform_set_drvdata(pdev, wm8994_gpio); + + return ret; + +err: + kfree(wm8994_gpio); + return ret; +} + +static int __devexit wm8994_gpio_remove(struct platform_device *pdev) +{ + struct wm8994_gpio *wm8994_gpio = platform_get_drvdata(pdev); + int ret; + + ret = gpiochip_remove(&wm8994_gpio->gpio_chip); + if (ret == 0) + kfree(wm8994_gpio); + + return ret; +} + +static struct platform_driver wm8994_gpio_driver = { + .driver.name = "wm8994-gpio", + .driver.owner = THIS_MODULE, + .probe = wm8994_gpio_probe, + .remove = __devexit_p(wm8994_gpio_remove), +}; + +static int __init wm8994_gpio_init(void) +{ + return platform_driver_register(&wm8994_gpio_driver); +} +subsys_initcall(wm8994_gpio_init); + +static void __exit wm8994_gpio_exit(void) +{ + platform_driver_unregister(&wm8994_gpio_driver); +} +module_exit(wm8994_gpio_exit); + +MODULE_AUTHOR("Mark Brown "); +MODULE_DESCRIPTION("GPIO interface for WM8994"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:wm8994-gpio"); -- cgit v0.10.2 From 1ea933f4cdbb88197139b9e62778beba0120e229 Mon Sep 17 00:00:00 2001 From: Mike Turquette Date: Fri, 5 Feb 2010 09:51:37 +0100 Subject: mfd: Program twl4030 remap_sleep correctly Variable remap was incorrectly referencing remap_off for the remap_sleep case when configuring TWL4030 power scripts. Signed-off-by: Mike Turquette Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 0815292..5b045ff 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -405,7 +405,7 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig) if (rconfig->remap_sleep != TWL4030_RESCONFIG_UNDEF) { remap &= ~SLEEP_STATE_MASK; - remap |= rconfig->remap_off << SLEEP_STATE_SHIFT; + remap |= rconfig->remap_sleep << SLEEP_STATE_SHIFT; } err = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, -- cgit v0.10.2 From b13c0df517bedbc40cff4ab5f797b08b1111918b Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 25 Jan 2010 06:26:34 -0500 Subject: mfd: Update i2c driver for max8925 Update I2C driver in order to fit all of three I2C components in max8925. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index 942068e..c0b883c 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -14,27 +14,23 @@ #include #include +#define RTC_I2C_ADDR 0x68 +#define ADC_I2C_ADDR 0x47 + static inline int max8925_read_device(struct i2c_client *i2c, int reg, int bytes, void *dest) { - unsigned char data; - unsigned char *buf; int ret; - buf = kzalloc(bytes + 1, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - data = (unsigned char)reg; - ret = i2c_master_send(i2c, &data, 1); - if (ret < 0) - return ret; - - ret = i2c_master_recv(i2c, buf, bytes + 1); - if (ret < 0) - return ret; - memcpy(dest, buf, bytes); - return 0; + if (bytes > 1) + ret = i2c_smbus_read_i2c_block_data(i2c, reg, bytes, dest); + else { + ret = i2c_smbus_read_byte_data(i2c, reg); + if (ret < 0) + return ret; + *(unsigned char *)dest = (unsigned char)ret; + } + return ret; } static inline int max8925_write_device(struct i2c_client *i2c, @@ -55,7 +51,7 @@ static inline int max8925_write_device(struct i2c_client *i2c, int max8925_reg_read(struct i2c_client *i2c, int reg) { struct max8925_chip *chip = i2c_get_clientdata(i2c); - unsigned char data; + unsigned char data = 0; int ret; mutex_lock(&chip->io_lock); @@ -134,7 +130,7 @@ EXPORT_SYMBOL(max8925_set_bits); static const struct i2c_device_id max8925_id_table[] = { { "max8925", 0 }, - {} + { }, }; MODULE_DEVICE_TABLE(i2c, max8925_id_table); @@ -142,27 +138,28 @@ static int __devinit max8925_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max8925_platform_data *pdata = client->dev.platform_data; - struct max8925_chip *chip; + static struct max8925_chip *chip; if (!pdata) { pr_info("%s: platform data is missing\n", __func__); return -EINVAL; } - if ((pdata->chip_id <= MAX8925_INVALID) - || (pdata->chip_id >= MAX8925_MAX)) { - pr_info("#%s: wrong chip identification\n", __func__); - return -EINVAL; - } chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->i2c = client; - chip->chip_id = pdata->chip_id; - i2c_set_clientdata(client, chip); chip->dev = &client->dev; - mutex_init(&chip->io_lock); + i2c_set_clientdata(client, chip); dev_set_drvdata(chip->dev, chip); + mutex_init(&chip->io_lock); + + chip->rtc = i2c_new_dummy(chip->i2c->adapter, RTC_I2C_ADDR); + i2c_set_clientdata(chip->rtc, chip); + + chip->adc = i2c_new_dummy(chip->i2c->adapter, ADC_I2C_ADDR); + i2c_set_clientdata(chip->adc, chip); + max8925_device_init(chip, pdata); return 0; @@ -173,7 +170,11 @@ static int __devexit max8925_remove(struct i2c_client *client) struct max8925_chip *chip = i2c_get_clientdata(client); max8925_device_exit(chip); - i2c_set_clientdata(client, NULL); + i2c_unregister_device(chip->adc); + i2c_unregister_device(chip->rtc); + i2c_set_clientdata(chip->adc, NULL); + i2c_set_clientdata(chip->rtc, NULL); + i2c_set_clientdata(chip->i2c, NULL); kfree(chip); return 0; } -- cgit v0.10.2 From 1f1cf8f98cf6588365efeaab8e7e7758aaa77f6e Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 5 Feb 2010 16:07:54 +0100 Subject: mfd: Update irq handler in max8925 Update thread irq handler. Simply the interface of using thread irq. Signed-off-by: Haojian Zhuang Acked-by: Mark Brown Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 64fbe33..84a68d2 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -204,8 +204,8 @@ config PMIC_ADP5520 under the corresponding menus. config MFD_MAX8925 - tristate "Maxim Semiconductor MAX8925 PMIC Support" - depends on I2C + bool "Maxim Semiconductor MAX8925 PMIC Support" + depends on I2C=y select MFD_CORE help Say yes here to support for Maxim Semiconductor MAX8925. This is diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index f36c494..85d63c0 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -1,7 +1,7 @@ /* * Base driver for Maxim MAX8925 * - * Copyright (C) 2009 Marvell International Ltd. + * Copyright (C) 2009-2010 Marvell International Ltd. * Haojian Zhuang * * This program is free software; you can redistribute it and/or modify @@ -12,14 +12,12 @@ #include #include #include +#include #include #include #include #include -#define IRQ_MODE_STATUS 0 -#define IRQ_MODE_MASK 1 - static struct resource backlight_resources[] = { { .name = "max8925-backlight", @@ -56,6 +54,42 @@ static struct mfd_cell touch_devs[] = { }, }; +static struct resource power_supply_resources[] = { + { + .name = "max8925-power", + .start = MAX8925_CHG_IRQ1, + .end = MAX8925_CHG_IRQ1_MASK, + .flags = IORESOURCE_IO, + }, +}; + +static struct mfd_cell power_devs[] = { + { + .name = "max8925-power", + .num_resources = 1, + .resources = &power_supply_resources[0], + .id = -1, + }, +}; + +static struct resource rtc_resources[] = { + { + .name = "max8925-rtc", + .start = MAX8925_RTC_IRQ, + .end = MAX8925_RTC_IRQ_MASK, + .flags = IORESOURCE_IO, + }, +}; + +static struct mfd_cell rtc_devs[] = { + { + .name = "max8925-rtc", + .num_resources = 1, + .resources = &rtc_resources[0], + .id = -1, + }, +}; + #define MAX8925_REG_RESOURCE(_start, _end) \ { \ .start = MAX8925_##_start, \ @@ -123,203 +157,450 @@ static struct mfd_cell regulator_devs[] = { MAX8925_REG_DEVS(LDO20), }; -static int __get_irq_offset(struct max8925_chip *chip, int irq, int mode, - int *offset, int *bit) +enum { + FLAGS_ADC = 1, /* register in ADC component */ + FLAGS_RTC, /* register in RTC component */ +}; + +struct max8925_irq_data { + int reg; + int mask_reg; + int enable; /* enable or not */ + int offs; /* bit offset in mask register */ + int flags; + int tsc_irq; +}; + +static struct max8925_irq_data max8925_irqs[] = { + [MAX8925_IRQ_VCHG_DC_OVP] = { + .reg = MAX8925_CHG_IRQ1, + .mask_reg = MAX8925_CHG_IRQ1_MASK, + .offs = 1 << 0, + }, + [MAX8925_IRQ_VCHG_DC_F] = { + .reg = MAX8925_CHG_IRQ1, + .mask_reg = MAX8925_CHG_IRQ1_MASK, + .offs = 1 << 1, + }, + [MAX8925_IRQ_VCHG_DC_R] = { + .reg = MAX8925_CHG_IRQ1, + .mask_reg = MAX8925_CHG_IRQ1_MASK, + .offs = 1 << 2, + }, + [MAX8925_IRQ_VCHG_USB_OVP] = { + .reg = MAX8925_CHG_IRQ1, + .mask_reg = MAX8925_CHG_IRQ1_MASK, + .offs = 1 << 3, + }, + [MAX8925_IRQ_VCHG_USB_F] = { + .reg = MAX8925_CHG_IRQ1, + .mask_reg = MAX8925_CHG_IRQ1_MASK, + .offs = 1 << 4, + }, + [MAX8925_IRQ_VCHG_USB_R] = { + .reg = MAX8925_CHG_IRQ1, + .mask_reg = MAX8925_CHG_IRQ1_MASK, + .offs = 1 << 5, + }, + [MAX8925_IRQ_VCHG_THM_OK_R] = { + .reg = MAX8925_CHG_IRQ2, + .mask_reg = MAX8925_CHG_IRQ2_MASK, + .offs = 1 << 0, + }, + [MAX8925_IRQ_VCHG_THM_OK_F] = { + .reg = MAX8925_CHG_IRQ2, + .mask_reg = MAX8925_CHG_IRQ2_MASK, + .offs = 1 << 1, + }, + [MAX8925_IRQ_VCHG_SYSLOW_F] = { + .reg = MAX8925_CHG_IRQ2, + .mask_reg = MAX8925_CHG_IRQ2_MASK, + .offs = 1 << 2, + }, + [MAX8925_IRQ_VCHG_SYSLOW_R] = { + .reg = MAX8925_CHG_IRQ2, + .mask_reg = MAX8925_CHG_IRQ2_MASK, + .offs = 1 << 3, + }, + [MAX8925_IRQ_VCHG_RST] = { + .reg = MAX8925_CHG_IRQ2, + .mask_reg = MAX8925_CHG_IRQ2_MASK, + .offs = 1 << 4, + }, + [MAX8925_IRQ_VCHG_DONE] = { + .reg = MAX8925_CHG_IRQ2, + .mask_reg = MAX8925_CHG_IRQ2_MASK, + .offs = 1 << 5, + }, + [MAX8925_IRQ_VCHG_TOPOFF] = { + .reg = MAX8925_CHG_IRQ2, + .mask_reg = MAX8925_CHG_IRQ2_MASK, + .offs = 1 << 6, + }, + [MAX8925_IRQ_VCHG_TMR_FAULT] = { + .reg = MAX8925_CHG_IRQ2, + .mask_reg = MAX8925_CHG_IRQ2_MASK, + .offs = 1 << 7, + }, + [MAX8925_IRQ_GPM_RSTIN] = { + .reg = MAX8925_ON_OFF_IRQ1, + .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, + .offs = 1 << 0, + }, + [MAX8925_IRQ_GPM_MPL] = { + .reg = MAX8925_ON_OFF_IRQ1, + .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, + .offs = 1 << 1, + }, + [MAX8925_IRQ_GPM_SW_3SEC] = { + .reg = MAX8925_ON_OFF_IRQ1, + .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, + .offs = 1 << 2, + }, + [MAX8925_IRQ_GPM_EXTON_F] = { + .reg = MAX8925_ON_OFF_IRQ1, + .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, + .offs = 1 << 3, + }, + [MAX8925_IRQ_GPM_EXTON_R] = { + .reg = MAX8925_ON_OFF_IRQ1, + .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, + .offs = 1 << 4, + }, + [MAX8925_IRQ_GPM_SW_1SEC] = { + .reg = MAX8925_ON_OFF_IRQ1, + .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, + .offs = 1 << 5, + }, + [MAX8925_IRQ_GPM_SW_F] = { + .reg = MAX8925_ON_OFF_IRQ1, + .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, + .offs = 1 << 6, + }, + [MAX8925_IRQ_GPM_SW_R] = { + .reg = MAX8925_ON_OFF_IRQ1, + .mask_reg = MAX8925_ON_OFF_IRQ1_MASK, + .offs = 1 << 7, + }, + [MAX8925_IRQ_GPM_SYSCKEN_F] = { + .reg = MAX8925_ON_OFF_IRQ2, + .mask_reg = MAX8925_ON_OFF_IRQ2_MASK, + .offs = 1 << 0, + }, + [MAX8925_IRQ_GPM_SYSCKEN_R] = { + .reg = MAX8925_ON_OFF_IRQ2, + .mask_reg = MAX8925_ON_OFF_IRQ2_MASK, + .offs = 1 << 1, + }, + [MAX8925_IRQ_RTC_ALARM1] = { + .reg = MAX8925_RTC_IRQ, + .mask_reg = MAX8925_RTC_IRQ_MASK, + .offs = 1 << 2, + .flags = FLAGS_RTC, + }, + [MAX8925_IRQ_RTC_ALARM0] = { + .reg = MAX8925_RTC_IRQ, + .mask_reg = MAX8925_RTC_IRQ_MASK, + .offs = 1 << 3, + .flags = FLAGS_RTC, + }, + [MAX8925_IRQ_TSC_STICK] = { + .reg = MAX8925_TSC_IRQ, + .mask_reg = MAX8925_TSC_IRQ_MASK, + .offs = 1 << 0, + .flags = FLAGS_ADC, + .tsc_irq = 1, + }, + [MAX8925_IRQ_TSC_NSTICK] = { + .reg = MAX8925_TSC_IRQ, + .mask_reg = MAX8925_TSC_IRQ_MASK, + .offs = 1 << 1, + .flags = FLAGS_ADC, + .tsc_irq = 1, + }, +}; + +static inline struct max8925_irq_data *irq_to_max8925(struct max8925_chip *chip, + int irq) { - if (!offset || !bit) - return -EINVAL; + return &max8925_irqs[irq - chip->irq_base]; +} - switch (chip->chip_id) { - case MAX8925_GPM: - *bit = irq % BITS_PER_BYTE; - if (irq < (BITS_PER_BYTE << 1)) { /* irq = [0,15] */ - *offset = (mode) ? MAX8925_CHG_IRQ1_MASK - : MAX8925_CHG_IRQ1; - if (irq >= BITS_PER_BYTE) - (*offset)++; - } else { /* irq = [16,31] */ - *offset = (mode) ? MAX8925_ON_OFF_IRQ1_MASK - : MAX8925_ON_OFF_IRQ1; - if (irq >= (BITS_PER_BYTE * 3)) - (*offset)++; +static irqreturn_t max8925_irq(int irq, void *data) +{ + struct max8925_chip *chip = data; + struct max8925_irq_data *irq_data; + struct i2c_client *i2c; + int read_reg = -1, value = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { + irq_data = &max8925_irqs[i]; + /* TSC IRQ should be serviced in max8925_tsc_irq() */ + if (irq_data->tsc_irq) + continue; + if (irq_data->flags == FLAGS_RTC) + i2c = chip->rtc; + else if (irq_data->flags == FLAGS_ADC) + i2c = chip->adc; + else + i2c = chip->i2c; + if (read_reg != irq_data->reg) { + read_reg = irq_data->reg; + value = max8925_reg_read(i2c, irq_data->reg); } - break; - case MAX8925_ADC: - *bit = irq % BITS_PER_BYTE; - *offset = (mode) ? MAX8925_TSC_IRQ_MASK : MAX8925_TSC_IRQ; - break; - default: - goto out; + if (value & irq_data->enable) + handle_nested_irq(chip->irq_base + i); } - return 0; -out: - dev_err(chip->dev, "Wrong irq #%d is assigned\n", irq); - return -EINVAL; + return IRQ_HANDLED; } -static int __check_irq(int irq) +static irqreturn_t max8925_tsc_irq(int irq, void *data) { - if ((irq < 0) || (irq >= MAX8925_NUM_IRQ)) - return -EINVAL; - return 0; + struct max8925_chip *chip = data; + struct max8925_irq_data *irq_data; + struct i2c_client *i2c; + int read_reg = -1, value = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { + irq_data = &max8925_irqs[i]; + /* non TSC IRQ should be serviced in max8925_irq() */ + if (!irq_data->tsc_irq) + continue; + if (irq_data->flags == FLAGS_RTC) + i2c = chip->rtc; + else if (irq_data->flags == FLAGS_ADC) + i2c = chip->adc; + else + i2c = chip->i2c; + if (read_reg != irq_data->reg) { + read_reg = irq_data->reg; + value = max8925_reg_read(i2c, irq_data->reg); + } + if (value & irq_data->enable) + handle_nested_irq(chip->irq_base + i); + } + return IRQ_HANDLED; } -int max8925_mask_irq(struct max8925_chip *chip, int irq) +static void max8925_irq_lock(unsigned int irq) { - int offset, bit, ret; + struct max8925_chip *chip = get_irq_chip_data(irq); - ret = __get_irq_offset(chip, irq, IRQ_MODE_MASK, &offset, &bit); - if (ret < 0) - return ret; - ret = max8925_set_bits(chip->i2c, offset, 1 << bit, 1 << bit); - return ret; + mutex_lock(&chip->irq_lock); } -int max8925_unmask_irq(struct max8925_chip *chip, int irq) +static void max8925_irq_sync_unlock(unsigned int irq) { - int offset, bit, ret; + struct max8925_chip *chip = get_irq_chip_data(irq); + struct max8925_irq_data *irq_data; + static unsigned char cache_chg[2] = {0xff, 0xff}; + static unsigned char cache_on[2] = {0xff, 0xff}; + static unsigned char cache_rtc = 0xff, cache_tsc = 0xff; + unsigned char irq_chg[2], irq_on[2]; + unsigned char irq_rtc, irq_tsc; + int i; + + /* Load cached value. In initial, all IRQs are masked */ + irq_chg[0] = cache_chg[0]; + irq_chg[1] = cache_chg[1]; + irq_on[0] = cache_on[0]; + irq_on[1] = cache_on[1]; + irq_rtc = cache_rtc; + irq_tsc = cache_tsc; + for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { + irq_data = &max8925_irqs[i]; + switch (irq_data->mask_reg) { + case MAX8925_CHG_IRQ1_MASK: + irq_chg[0] &= irq_data->enable; + break; + case MAX8925_CHG_IRQ2_MASK: + irq_chg[1] &= irq_data->enable; + break; + case MAX8925_ON_OFF_IRQ1_MASK: + irq_on[0] &= irq_data->enable; + break; + case MAX8925_ON_OFF_IRQ2_MASK: + irq_on[1] &= irq_data->enable; + break; + case MAX8925_RTC_IRQ_MASK: + irq_rtc &= irq_data->enable; + break; + case MAX8925_TSC_IRQ_MASK: + irq_tsc &= irq_data->enable; + break; + default: + dev_err(chip->dev, "wrong IRQ\n"); + break; + } + } + /* update mask into registers */ + if (cache_chg[0] != irq_chg[0]) { + cache_chg[0] = irq_chg[0]; + max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ1_MASK, + irq_chg[0]); + } + if (cache_chg[1] != irq_chg[1]) { + cache_chg[1] = irq_chg[1]; + max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ2_MASK, + irq_chg[1]); + } + if (cache_on[0] != irq_on[0]) { + cache_on[0] = irq_on[0]; + max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ1_MASK, + irq_on[0]); + } + if (cache_on[1] != irq_on[1]) { + cache_on[1] = irq_on[1]; + max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ2_MASK, + irq_on[1]); + } + if (cache_rtc != irq_rtc) { + cache_rtc = irq_rtc; + max8925_reg_write(chip->rtc, MAX8925_RTC_IRQ_MASK, irq_rtc); + } + if (cache_tsc != irq_tsc) { + cache_tsc = irq_tsc; + max8925_reg_write(chip->adc, MAX8925_TSC_IRQ_MASK, irq_tsc); + } - ret = __get_irq_offset(chip, irq, IRQ_MODE_MASK, &offset, &bit); - if (ret < 0) - return ret; - ret = max8925_set_bits(chip->i2c, offset, 1 << bit, 0); - return ret; + mutex_unlock(&chip->irq_lock); } -#define INT_STATUS_NUM (MAX8925_NUM_IRQ / BITS_PER_BYTE) - -static irqreturn_t max8925_irq_thread(int irq, void *data) +static void max8925_irq_enable(unsigned int irq) { - struct max8925_chip *chip = data; - unsigned long irq_status[INT_STATUS_NUM]; - unsigned char status_buf[INT_STATUS_NUM << 1]; - int i, ret; - - memset(irq_status, 0, sizeof(unsigned long) * INT_STATUS_NUM); - - /* all these interrupt status registers are read-only */ - switch (chip->chip_id) { - case MAX8925_GPM: - ret = max8925_bulk_read(chip->i2c, MAX8925_CHG_IRQ1, - 4, status_buf); - if (ret < 0) - goto out; - ret = max8925_bulk_read(chip->i2c, MAX8925_ON_OFF_IRQ1, - 2, &status_buf[4]); - if (ret < 0) - goto out; - ret = max8925_bulk_read(chip->i2c, MAX8925_ON_OFF_IRQ2, - 2, &status_buf[6]); - if (ret < 0) - goto out; - /* clear masked interrupt status */ - status_buf[0] &= (~status_buf[2] & CHG_IRQ1_MASK); - irq_status[0] |= status_buf[0]; - status_buf[1] &= (~status_buf[3] & CHG_IRQ2_MASK); - irq_status[0] |= (status_buf[1] << BITS_PER_BYTE); - status_buf[4] &= (~status_buf[5] & ON_OFF_IRQ1_MASK); - irq_status[0] |= (status_buf[4] << (BITS_PER_BYTE * 2)); - status_buf[6] &= (~status_buf[7] & ON_OFF_IRQ2_MASK); - irq_status[0] |= (status_buf[6] << (BITS_PER_BYTE * 3)); - break; - case MAX8925_ADC: - ret = max8925_bulk_read(chip->i2c, MAX8925_TSC_IRQ, - 2, status_buf); - if (ret < 0) - goto out; - /* clear masked interrupt status */ - status_buf[0] &= (~status_buf[1] & TSC_IRQ_MASK); - irq_status[0] |= status_buf[0]; - break; - default: - goto out; - } - - for_each_bit(i, &irq_status[0], MAX8925_NUM_IRQ) { - clear_bit(i, irq_status); - dev_dbg(chip->dev, "Servicing IRQ #%d in %s\n", i, chip->name); - - mutex_lock(&chip->irq_lock); - if (chip->irq[i].handler) - chip->irq[i].handler(i, chip->irq[i].data); - else { - max8925_mask_irq(chip, i); - dev_err(chip->dev, "Noboday cares IRQ #%d in %s. " - "Now mask it.\n", i, chip->name); - } - mutex_unlock(&chip->irq_lock); - } -out: - return IRQ_HANDLED; + struct max8925_chip *chip = get_irq_chip_data(irq); + max8925_irqs[irq - chip->irq_base].enable + = max8925_irqs[irq - chip->irq_base].offs; } -int max8925_request_irq(struct max8925_chip *chip, int irq, - irq_handler_t handler, void *data) +static void max8925_irq_disable(unsigned int irq) { - if ((__check_irq(irq) < 0) || !handler) - return -EINVAL; - - mutex_lock(&chip->irq_lock); - chip->irq[irq].handler = handler; - chip->irq[irq].data = data; - mutex_unlock(&chip->irq_lock); - return 0; + struct max8925_chip *chip = get_irq_chip_data(irq); + max8925_irqs[irq - chip->irq_base].enable = 0; } -EXPORT_SYMBOL(max8925_request_irq); -int max8925_free_irq(struct max8925_chip *chip, int irq) +static struct irq_chip max8925_irq_chip = { + .name = "max8925", + .bus_lock = max8925_irq_lock, + .bus_sync_unlock = max8925_irq_sync_unlock, + .enable = max8925_irq_enable, + .disable = max8925_irq_disable, +}; + +static int max8925_irq_init(struct max8925_chip *chip, int irq, + struct max8925_platform_data *pdata) { - if (__check_irq(irq) < 0) + unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + struct irq_desc *desc; + int i, ret; + int __irq; + + if (!pdata || !pdata->irq_base) { + dev_warn(chip->dev, "No interrupt support on IRQ base\n"); return -EINVAL; + } + /* clear all interrupts */ + max8925_reg_read(chip->i2c, MAX8925_CHG_IRQ1); + max8925_reg_read(chip->i2c, MAX8925_CHG_IRQ2); + max8925_reg_read(chip->i2c, MAX8925_ON_OFF_IRQ1); + max8925_reg_read(chip->i2c, MAX8925_ON_OFF_IRQ2); + max8925_reg_read(chip->rtc, MAX8925_RTC_IRQ); + max8925_reg_read(chip->adc, MAX8925_TSC_IRQ); + /* mask all interrupts */ + max8925_reg_write(chip->rtc, MAX8925_ALARM0_CNTL, 0); + max8925_reg_write(chip->rtc, MAX8925_ALARM1_CNTL, 0); + max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ1_MASK, 0xff); + max8925_reg_write(chip->i2c, MAX8925_CHG_IRQ2_MASK, 0xff); + max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ1_MASK, 0xff); + max8925_reg_write(chip->i2c, MAX8925_ON_OFF_IRQ2_MASK, 0xff); + max8925_reg_write(chip->rtc, MAX8925_RTC_IRQ_MASK, 0xff); + max8925_reg_write(chip->adc, MAX8925_TSC_IRQ_MASK, 0xff); + + mutex_init(&chip->irq_lock); + chip->core_irq = irq; + chip->irq_base = pdata->irq_base; + desc = irq_to_desc(chip->core_irq); + + /* register with genirq */ + for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { + __irq = i + chip->irq_base; + set_irq_chip_data(__irq, chip); + set_irq_chip_and_handler(__irq, &max8925_irq_chip, + handle_edge_irq); + set_irq_nested_thread(__irq, 1); +#ifdef CONFIG_ARM + set_irq_flags(__irq, IRQF_VALID); +#else + set_irq_noprobe(__irq); +#endif + } + if (!irq) { + dev_warn(chip->dev, "No interrupt support on core IRQ\n"); + goto tsc_irq; + } - mutex_lock(&chip->irq_lock); - chip->irq[irq].handler = NULL; - chip->irq[irq].data = NULL; - mutex_unlock(&chip->irq_lock); + ret = request_threaded_irq(irq, NULL, max8925_irq, flags, + "max8925", chip); + if (ret) { + dev_err(chip->dev, "Failed to request core IRQ: %d\n", ret); + chip->core_irq = 0; + } +tsc_irq: + if (!pdata->tsc_irq) { + dev_warn(chip->dev, "No interrupt support on TSC IRQ\n"); + return 0; + } + chip->tsc_irq = pdata->tsc_irq; + + ret = request_threaded_irq(chip->tsc_irq, NULL, max8925_tsc_irq, + flags, "max8925-tsc", chip); + if (ret) { + dev_err(chip->dev, "Failed to request TSC IRQ: %d\n", ret); + chip->tsc_irq = 0; + } return 0; } -EXPORT_SYMBOL(max8925_free_irq); -static int __devinit device_gpm_init(struct max8925_chip *chip, - struct i2c_client *i2c, - struct max8925_platform_data *pdata) +int __devinit max8925_device_init(struct max8925_chip *chip, + struct max8925_platform_data *pdata) { int ret; - /* mask all IRQs */ - ret = max8925_set_bits(i2c, MAX8925_CHG_IRQ1_MASK, 0x7, 0x7); - if (ret < 0) - goto out; - ret = max8925_set_bits(i2c, MAX8925_CHG_IRQ2_MASK, 0xff, 0xff); - if (ret < 0) - goto out; - ret = max8925_set_bits(i2c, MAX8925_ON_OFF_IRQ1_MASK, 0xff, 0xff); - if (ret < 0) - goto out; - ret = max8925_set_bits(i2c, MAX8925_ON_OFF_IRQ2_MASK, 0x3, 0x3); - if (ret < 0) - goto out; - - chip->name = "GPM"; - memset(chip->irq, 0, sizeof(struct max8925_irq) * MAX8925_NUM_IRQ); - ret = request_threaded_irq(i2c->irq, NULL, max8925_irq_thread, - IRQF_ONESHOT | IRQF_TRIGGER_LOW, - "max8925-gpm", chip); - if (ret < 0) { - dev_err(chip->dev, "Failed to request IRQ #%d.\n", i2c->irq); - goto out; + max8925_irq_init(chip, chip->i2c->irq, pdata); + + if (pdata && (pdata->power || pdata->touch)) { + /* enable ADC to control internal reference */ + max8925_set_bits(chip->i2c, MAX8925_RESET_CNFG, 1, 1); + /* enable internal reference for ADC */ + max8925_set_bits(chip->adc, MAX8925_TSC_CNFG1, 3, 2); + /* check for internal reference IRQ */ + do { + ret = max8925_reg_read(chip->adc, MAX8925_TSC_IRQ); + } while (ret & MAX8925_NREF_OK); + /* enaable ADC scheduler, interval is 1 second */ + max8925_set_bits(chip->adc, MAX8925_ADC_SCHED, 3, 2); } - chip->chip_irq = i2c->irq; - /* enable hard-reset for ONKEY power-off */ - max8925_set_bits(i2c, MAX8925_SYSENSEL, 0x80, 0x80); + /* enable Momentary Power Loss */ + max8925_set_bits(chip->rtc, MAX8925_MPL_CNTL, 1 << 4, 1 << 4); - ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], - ARRAY_SIZE(regulator_devs), - ®ulator_resources[0], 0); + ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0], + ARRAY_SIZE(rtc_devs), + &rtc_resources[0], 0); if (ret < 0) { - dev_err(chip->dev, "Failed to add regulator subdev\n"); - goto out_irq; + dev_err(chip->dev, "Failed to add rtc subdev\n"); + goto out; + } + if (pdata && pdata->regulator[0]) { + ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], + ARRAY_SIZE(regulator_devs), + ®ulator_resources[0], 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add regulator subdev\n"); + goto out_dev; + } } if (pdata && pdata->backlight) { @@ -331,35 +612,17 @@ static int __devinit device_gpm_init(struct max8925_chip *chip, goto out_dev; } } - return 0; -out_dev: - mfd_remove_devices(chip->dev); -out_irq: - if (chip->chip_irq) - free_irq(chip->chip_irq, chip); -out: - return ret; -} - -static int __devinit device_adc_init(struct max8925_chip *chip, - struct i2c_client *i2c, - struct max8925_platform_data *pdata) -{ - int ret; - - /* mask all IRQs */ - ret = max8925_set_bits(i2c, MAX8925_TSC_IRQ_MASK, 3, 3); - chip->name = "ADC"; - memset(chip->irq, 0, sizeof(struct max8925_irq) * MAX8925_NUM_IRQ); - ret = request_threaded_irq(i2c->irq, NULL, max8925_irq_thread, - IRQF_ONESHOT | IRQF_TRIGGER_LOW, - "max8925-adc", chip); - if (ret < 0) { - dev_err(chip->dev, "Failed to request IRQ #%d.\n", i2c->irq); - goto out; + if (pdata && pdata->power) { + ret = mfd_add_devices(chip->dev, 0, &power_devs[0], + ARRAY_SIZE(power_devs), + &power_supply_resources[0], 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add power supply " + "subdev\n"); + goto out_dev; + } } - chip->chip_irq = i2c->irq; if (pdata && pdata->touch) { ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], @@ -367,38 +630,27 @@ static int __devinit device_adc_init(struct max8925_chip *chip, &touch_resources[0], 0); if (ret < 0) { dev_err(chip->dev, "Failed to add touch subdev\n"); - goto out_irq; + goto out_dev; } } + return 0; -out_irq: - if (chip->chip_irq) - free_irq(chip->chip_irq, chip); +out_dev: + mfd_remove_devices(chip->dev); out: return ret; } -int __devinit max8925_device_init(struct max8925_chip *chip, - struct max8925_platform_data *pdata) +void __devexit max8925_device_exit(struct max8925_chip *chip) { - switch (chip->chip_id) { - case MAX8925_GPM: - device_gpm_init(chip, chip->i2c, pdata); - break; - case MAX8925_ADC: - device_adc_init(chip, chip->i2c, pdata); - break; - } - return 0; -} - -void max8925_device_exit(struct max8925_chip *chip) -{ - if (chip->chip_irq >= 0) - free_irq(chip->chip_irq, chip); + if (chip->core_irq) + free_irq(chip->core_irq, chip); + if (chip->tsc_irq) + free_irq(chip->tsc_irq, chip); mfd_remove_devices(chip->dev); } + MODULE_DESCRIPTION("PMIC Driver for Maxim MAX8925"); MODULE_AUTHOR("Haojian Zhuang #include /* Unified sub device IDs for MAX8925 */ @@ -39,6 +40,30 @@ enum { MAX8925_ID_LDO18, MAX8925_ID_LDO19, MAX8925_ID_LDO20, + MAX8925_ID_MAX, +}; + +enum { + /* + * Charging current threshold trigger going from fast charge + * to TOPOFF charge. From 5% to 20% of fasting charging current. + */ + MAX8925_TOPOFF_THR_5PER, + MAX8925_TOPOFF_THR_10PER, + MAX8925_TOPOFF_THR_15PER, + MAX8925_TOPOFF_THR_20PER, +}; + +enum { + /* Fast charging current */ + MAX8925_FCHG_85MA, + MAX8925_FCHG_300MA, + MAX8925_FCHG_460MA, + MAX8925_FCHG_600MA, + MAX8925_FCHG_700MA, + MAX8925_FCHG_800MA, + MAX8925_FCHG_900MA, + MAX8925_FCHG_1000MA, }; /* Charger registers */ @@ -46,12 +71,13 @@ enum { #define MAX8925_CHG_IRQ2 (0x7f) #define MAX8925_CHG_IRQ1_MASK (0x80) #define MAX8925_CHG_IRQ2_MASK (0x81) +#define MAX8925_CHG_STATUS (0x82) /* GPM registers */ #define MAX8925_SYSENSEL (0x00) #define MAX8925_ON_OFF_IRQ1 (0x01) #define MAX8925_ON_OFF_IRQ1_MASK (0x02) -#define MAX8925_ON_OFF_STAT (0x03) +#define MAX8925_ON_OFF_STATUS (0x03) #define MAX8925_ON_OFF_IRQ2 (0x0d) #define MAX8925_ON_OFF_IRQ2_MASK (0x0e) #define MAX8925_RESET_CNFG (0x0f) @@ -59,12 +85,18 @@ enum { /* Touch registers */ #define MAX8925_TSC_IRQ (0x00) #define MAX8925_TSC_IRQ_MASK (0x01) +#define MAX8925_TSC_CNFG1 (0x02) +#define MAX8925_ADC_SCHED (0x10) #define MAX8925_ADC_RES_END (0x6f) +#define MAX8925_NREF_OK (1 << 4) + /* RTC registers */ -#define MAX8925_RTC_STATUS (0x1a) +#define MAX8925_ALARM0_CNTL (0x18) +#define MAX8925_ALARM1_CNTL (0x19) #define MAX8925_RTC_IRQ (0x1c) #define MAX8925_RTC_IRQ_MASK (0x1d) +#define MAX8925_MPL_CNTL (0x1e) /* WLED registers */ #define MAX8925_WLED_MODE_CNTL (0x84) @@ -126,45 +158,48 @@ enum { #define TSC_IRQ_MASK (0x03) #define RTC_IRQ_MASK (0x0c) -#define MAX8925_NUM_IRQ (32) +#define MAX8925_GPM_NUM_IRQ (40) +#define MAX8925_ADC_NUM_IRQ (8) +#define MAX8925_NUM_IRQ (MAX8925_GPM_NUM_IRQ \ + + MAX8925_ADC_NUM_IRQ) + +#define MAX8925_MAX_REGULATOR (23) #define MAX8925_NAME_SIZE (32) +/* IRQ definitions */ enum { - MAX8925_INVALID = 0, - MAX8925_RTC, - MAX8925_ADC, - MAX8925_GPM, /* general power management */ - MAX8925_MAX, + MAX8925_IRQ_VCHG_DC_OVP, + MAX8925_IRQ_VCHG_DC_F, + MAX8925_IRQ_VCHG_DC_R, + MAX8925_IRQ_VCHG_USB_OVP, + MAX8925_IRQ_VCHG_USB_F, + MAX8925_IRQ_VCHG_USB_R, + MAX8925_IRQ_VCHG_THM_OK_R, + MAX8925_IRQ_VCHG_THM_OK_F, + MAX8925_IRQ_VCHG_SYSLOW_F, + MAX8925_IRQ_VCHG_SYSLOW_R, + MAX8925_IRQ_VCHG_RST, + MAX8925_IRQ_VCHG_DONE, + MAX8925_IRQ_VCHG_TOPOFF, + MAX8925_IRQ_VCHG_TMR_FAULT, + MAX8925_IRQ_GPM_RSTIN, + MAX8925_IRQ_GPM_MPL, + MAX8925_IRQ_GPM_SW_3SEC, + MAX8925_IRQ_GPM_EXTON_F, + MAX8925_IRQ_GPM_EXTON_R, + MAX8925_IRQ_GPM_SW_1SEC, + MAX8925_IRQ_GPM_SW_F, + MAX8925_IRQ_GPM_SW_R, + MAX8925_IRQ_GPM_SYSCKEN_F, + MAX8925_IRQ_GPM_SYSCKEN_R, + MAX8925_IRQ_RTC_ALARM1, + MAX8925_IRQ_RTC_ALARM0, + MAX8925_IRQ_TSC_STICK, + MAX8925_IRQ_TSC_NSTICK, + MAX8925_NR_IRQS, }; -#define MAX8925_IRQ_VCHG_OVP (0) -#define MAX8925_IRQ_VCHG_F (1) -#define MAX8925_IRQ_VCHG_R (2) -#define MAX8925_IRQ_VCHG_THM_OK_R (8) -#define MAX8925_IRQ_VCHG_THM_OK_F (9) -#define MAX8925_IRQ_VCHG_BATTLOW_F (10) -#define MAX8925_IRQ_VCHG_BATTLOW_R (11) -#define MAX8925_IRQ_VCHG_RST (12) -#define MAX8925_IRQ_VCHG_DONE (13) -#define MAX8925_IRQ_VCHG_TOPOFF (14) -#define MAX8925_IRQ_VCHG_TMR_FAULT (15) -#define MAX8925_IRQ_GPM_RSTIN (16) -#define MAX8925_IRQ_GPM_MPL (17) -#define MAX8925_IRQ_GPM_SW_3SEC (18) -#define MAX8925_IRQ_GPM_EXTON_F (19) -#define MAX8925_IRQ_GPM_EXTON_R (20) -#define MAX8925_IRQ_GPM_SW_1SEC (21) -#define MAX8925_IRQ_GPM_SW_F (22) -#define MAX8925_IRQ_GPM_SW_R (23) -#define MAX8925_IRQ_GPM_SYSCKEN_F (24) -#define MAX8925_IRQ_GPM_SYSCKEN_R (25) - -#define MAX8925_IRQ_TSC_STICK (0) -#define MAX8925_IRQ_TSC_NSTICK (1) - -#define MAX8925_MAX_REGULATOR (23) - struct max8925_irq { irq_handler_t handler; void *data; @@ -172,14 +207,16 @@ struct max8925_irq { struct max8925_chip { struct device *dev; + struct i2c_client *i2c; + struct i2c_client *adc; + struct i2c_client *rtc; + struct max8925_irq irqs[MAX8925_NUM_IRQ]; struct mutex io_lock; struct mutex irq_lock; - struct i2c_client *i2c; - struct max8925_irq irq[MAX8925_NUM_IRQ]; - const char *name; - int chip_id; - int chip_irq; + int irq_base; + int core_irq; + int tsc_irq; }; struct max8925_backlight_pdata { @@ -192,13 +229,25 @@ struct max8925_touch_pdata { unsigned int flags; }; +struct max8925_power_pdata { + int (*set_charger)(int); + unsigned batt_detect:1; + unsigned topoff_threshold:2; + unsigned fast_charge:3; /* charge current */ +}; + +/* + * irq_base: stores IRQ base number of MAX8925 in platform + * tsc_irq: stores IRQ number of MAX8925 TSC + */ struct max8925_platform_data { struct max8925_backlight_pdata *backlight; struct max8925_touch_pdata *touch; + struct max8925_power_pdata *power; struct regulator_init_data *regulator[MAX8925_MAX_REGULATOR]; - int chip_id; - int chip_irq; + int irq_base; + int tsc_irq; }; extern int max8925_reg_read(struct i2c_client *, int); @@ -208,6 +257,12 @@ extern int max8925_bulk_write(struct i2c_client *, int, int, unsigned char *); extern int max8925_set_bits(struct i2c_client *, int, unsigned char, unsigned char); +extern int max8925_request_irq(struct max8925_chip *, int, + irq_handler_t, void *); +extern int max8925_free_irq(struct max8925_chip *, int); +extern int max8925_mask_irq(struct max8925_chip *, int); +extern int max8925_unmask_irq(struct max8925_chip *, int); + extern int max8925_device_init(struct max8925_chip *, struct max8925_platform_data *); extern void max8925_device_exit(struct max8925_chip *); -- cgit v0.10.2 From a39069f6ce6500a5ca39e534108247f25169d8e0 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 25 Jan 2010 06:30:29 -0500 Subject: rtc: Enable rtc in max8925 MAX8925 is a PMIC that contains RTC component. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2bb8a8b..6a13037 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -175,6 +175,16 @@ config RTC_DRV_MAX6900 This driver can also be built as a module. If so, the module will be called rtc-max6900. +config RTC_DRV_MAX8925 + tristate "Maxim MAX8925" + depends on MFD_MAX8925 + help + If you say yes here you will get support for the + RTC of Maxim MAX8925 PMIC. + + This driver can also be built as a module. If so, the module + will be called rtc-max8925. + config RTC_DRV_RS5C372 tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index b7148af..44ef194 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o obj-$(CONFIG_RTC_MXC) += rtc-mxc.o obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o +obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o obj-$(CONFIG_RTC_DRV_MC13783) += rtc-mc13783.o obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c new file mode 100644 index 0000000..acdbb17 --- /dev/null +++ b/drivers/rtc/rtc-max8925.c @@ -0,0 +1,314 @@ +/* + * RTC driver for Maxim MAX8925 + * + * Copyright (C) 2009-2010 Marvell International Ltd. + * Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +enum { + RTC_SEC = 0, + RTC_MIN, + RTC_HOUR, + RTC_WEEKDAY, + RTC_DATE, + RTC_MONTH, + RTC_YEAR1, + RTC_YEAR2, +}; + +#define MAX8925_RTC_SEC 0x00 +#define MAX8925_RTC_MIN 0x01 +#define MAX8925_RTC_HOUR 0x02 +#define MAX8925_RTC_WEEKDAY 0x03 +#define MAX8925_RTC_DATE 0x04 +#define MAX8925_RTC_MONTH 0x05 +#define MAX8925_RTC_YEAR1 0x06 +#define MAX8925_RTC_YEAR2 0x07 +#define MAX8925_ALARM0_SEC 0x08 +#define MAX8925_ALARM0_MIN 0x09 +#define MAX8925_ALARM0_HOUR 0x0a +#define MAX8925_ALARM0_WEEKDAY 0x0b +#define MAX8925_ALARM0_DATE 0x0c +#define MAX8925_ALARM0_MON 0x0d +#define MAX8925_ALARM0_YEAR1 0x0e +#define MAX8925_ALARM0_YEAR2 0x0f +#define MAX8925_ALARM1_SEC 0x10 +#define MAX8925_ALARM1_MIN 0x11 +#define MAX8925_ALARM1_HOUR 0x12 +#define MAX8925_ALARM1_WEEKDAY 0x13 +#define MAX8925_ALARM1_DATE 0x14 +#define MAX8925_ALARM1_MON 0x15 +#define MAX8925_ALARM1_YEAR1 0x16 +#define MAX8925_ALARM1_YEAR2 0x17 +#define MAX8925_RTC_CNTL 0x1b +#define MAX8925_RTC_STATUS 0x20 + +#define TIME_NUM 8 +#define ALARM_1SEC (1 << 7) +#define HOUR_12 (1 << 7) +#define HOUR_AM_PM (1 << 5) +#define ALARM0_IRQ (1 << 3) +#define ALARM1_IRQ (1 << 2) +#define ALARM0_STATUS (1 << 2) +#define ALARM1_STATUS (1 << 1) + + +struct max8925_rtc_info { + struct rtc_device *rtc_dev; + struct max8925_chip *chip; + struct i2c_client *rtc; + struct device *dev; +}; + +static irqreturn_t rtc_update_handler(int irq, void *data) +{ + struct max8925_rtc_info *info = (struct max8925_rtc_info *)data; + + /* disable ALARM0 except for 1SEC alarm */ + max8925_set_bits(info->rtc, MAX8925_ALARM0_CNTL, 0x7f, 0); + rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); + return IRQ_HANDLED; +} + +static int tm_calc(struct rtc_time *tm, unsigned char *buf, int len) +{ + if (len < TIME_NUM) + return -EINVAL; + tm->tm_year = (buf[RTC_YEAR2] >> 4) * 1000 + + (buf[RTC_YEAR2] & 0xf) * 100 + + (buf[RTC_YEAR1] >> 4) * 10 + + (buf[RTC_YEAR1] & 0xf); + tm->tm_year -= 1900; + tm->tm_mon = ((buf[RTC_MONTH] >> 4) & 0x01) * 10 + + (buf[RTC_MONTH] & 0x0f); + tm->tm_mday = ((buf[RTC_DATE] >> 4) & 0x03) * 10 + + (buf[RTC_DATE] & 0x0f); + tm->tm_wday = buf[RTC_WEEKDAY] & 0x07; + if (buf[RTC_HOUR] & HOUR_12) { + tm->tm_hour = ((buf[RTC_HOUR] >> 4) & 0x1) * 10 + + (buf[RTC_HOUR] & 0x0f); + if (buf[RTC_HOUR] & HOUR_AM_PM) + tm->tm_hour += 12; + } else + tm->tm_hour = ((buf[RTC_HOUR] >> 4) & 0x03) * 10 + + (buf[RTC_HOUR] & 0x0f); + tm->tm_min = ((buf[RTC_MIN] >> 4) & 0x7) * 10 + + (buf[RTC_MIN] & 0x0f); + tm->tm_sec = ((buf[RTC_SEC] >> 4) & 0x7) * 10 + + (buf[RTC_SEC] & 0x0f); + return 0; +} + +static int data_calc(unsigned char *buf, struct rtc_time *tm, int len) +{ + unsigned char high, low; + + if (len < TIME_NUM) + return -EINVAL; + + high = (tm->tm_year + 1900) / 1000; + low = (tm->tm_year + 1900) / 100; + low = low - high * 10; + buf[RTC_YEAR2] = (high << 4) + low; + high = (tm->tm_year + 1900) / 10; + low = tm->tm_year + 1900; + low = low - high * 10; + high = high - (high / 10) * 10; + buf[RTC_YEAR1] = (high << 4) + low; + high = tm->tm_mon / 10; + low = tm->tm_mon; + low = low - high * 10; + buf[RTC_MONTH] = (high << 4) + low; + high = tm->tm_mday / 10; + low = tm->tm_mday; + low = low - high * 10; + buf[RTC_DATE] = (high << 4) + low; + buf[RTC_WEEKDAY] = tm->tm_wday; + high = tm->tm_hour / 10; + low = tm->tm_hour; + low = low - high * 10; + buf[RTC_HOUR] = (high << 4) + low; + high = tm->tm_min / 10; + low = tm->tm_min; + low = low - high * 10; + buf[RTC_MIN] = (high << 4) + low; + high = tm->tm_sec / 10; + low = tm->tm_sec; + low = low - high * 10; + buf[RTC_SEC] = (high << 4) + low; + return 0; +} + +static int max8925_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct max8925_rtc_info *info = dev_get_drvdata(dev); + unsigned char buf[TIME_NUM]; + int ret; + + ret = max8925_bulk_read(info->rtc, MAX8925_RTC_SEC, TIME_NUM, buf); + if (ret < 0) + goto out; + ret = tm_calc(tm, buf, TIME_NUM); +out: + return ret; +} + +static int max8925_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct max8925_rtc_info *info = dev_get_drvdata(dev); + unsigned char buf[TIME_NUM]; + int ret; + + ret = data_calc(buf, tm, TIME_NUM); + if (ret < 0) + goto out; + ret = max8925_bulk_write(info->rtc, MAX8925_RTC_SEC, TIME_NUM, buf); +out: + return ret; +} + +static int max8925_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max8925_rtc_info *info = dev_get_drvdata(dev); + unsigned char buf[TIME_NUM]; + int ret; + + ret = max8925_bulk_read(info->rtc, MAX8925_ALARM0_SEC, TIME_NUM, buf); + if (ret < 0) + goto out; + ret = tm_calc(&alrm->time, buf, TIME_NUM); + if (ret < 0) + goto out; + ret = max8925_reg_read(info->rtc, MAX8925_RTC_IRQ_MASK); + if (ret < 0) + goto out; + if ((ret & ALARM0_IRQ) == 0) + alrm->enabled = 1; + else + alrm->enabled = 0; + ret = max8925_reg_read(info->rtc, MAX8925_RTC_STATUS); + if (ret < 0) + goto out; + if (ret & ALARM0_STATUS) + alrm->pending = 1; + else + alrm->pending = 0; +out: + return ret; +} + +static int max8925_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct max8925_rtc_info *info = dev_get_drvdata(dev); + unsigned char buf[TIME_NUM]; + int ret; + + ret = data_calc(buf, &alrm->time, TIME_NUM); + if (ret < 0) + goto out; + ret = max8925_bulk_write(info->rtc, MAX8925_ALARM0_SEC, TIME_NUM, buf); + if (ret < 0) + goto out; + /* only enable alarm on year/month/day/hour/min/sec */ + ret = max8925_reg_write(info->rtc, MAX8925_ALARM0_CNTL, 0x77); + if (ret < 0) + goto out; +out: + return ret; +} + +static const struct rtc_class_ops max8925_rtc_ops = { + .read_time = max8925_rtc_read_time, + .set_time = max8925_rtc_set_time, + .read_alarm = max8925_rtc_read_alarm, + .set_alarm = max8925_rtc_set_alarm, +}; + +static int __devinit max8925_rtc_probe(struct platform_device *pdev) +{ + struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct max8925_rtc_info *info; + int irq, ret; + + info = kzalloc(sizeof(struct max8925_rtc_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + info->chip = chip; + info->rtc = chip->rtc; + info->dev = &pdev->dev; + irq = chip->irq_base + MAX8925_IRQ_RTC_ALARM0; + + ret = request_threaded_irq(irq, NULL, rtc_update_handler, + IRQF_ONESHOT, "rtc-alarm0", info); + if (ret < 0) { + dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", + irq, ret); + goto out_irq; + } + + info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev, + &max8925_rtc_ops, THIS_MODULE); + ret = PTR_ERR(info->rtc_dev); + if (IS_ERR(info->rtc_dev)) { + dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); + goto out_rtc; + } + + dev_set_drvdata(&pdev->dev, info); + platform_set_drvdata(pdev, info); + + return 0; +out_rtc: + free_irq(chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info); +out_irq: + kfree(info); + return ret; +} + +static int __devexit max8925_rtc_remove(struct platform_device *pdev) +{ + struct max8925_rtc_info *info = platform_get_drvdata(pdev); + + if (info) { + free_irq(info->chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info); + rtc_device_unregister(info->rtc_dev); + kfree(info); + } + return 0; +} + +static struct platform_driver max8925_rtc_driver = { + .driver = { + .name = "max8925-rtc", + .owner = THIS_MODULE, + }, + .probe = max8925_rtc_probe, + .remove = __devexit_p(max8925_rtc_remove), +}; + +static int __init max8925_rtc_init(void) +{ + return platform_driver_register(&max8925_rtc_driver); +} +module_init(max8925_rtc_init); + +static void __exit max8925_rtc_exit(void) +{ + platform_driver_unregister(&max8925_rtc_driver); +} +module_exit(max8925_rtc_exit); + +MODULE_DESCRIPTION("Maxim MAX8925 RTC driver"); +MODULE_AUTHOR("Haojian Zhuang "); +MODULE_LICENSE("GPL"); + -- cgit v0.10.2 From 28db38888b2a53b6bdd70104c2d2a199632ca507 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 25 Jan 2010 10:38:35 -0500 Subject: power_supply: Enable power supply of max8925 MAX8925 is a PMIC that contains charger component Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index bf14672..faaa9b4 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -29,6 +29,13 @@ config APM_POWER Say Y here to enable support APM status emulation using battery class devices. +config MAX8925_POWER + tristate "MAX8925 battery charger support" + depends on MFD_MAX8925 + help + Say Y here to enable support for the battery charger in the Maxim + MAX8925 PMIC. + config WM831X_BACKUP tristate "WM831X backup battery charger support" depends on MFD_WM831X diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 573597c..a2ba7c8 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_POWER_SUPPLY) += power_supply.o obj-$(CONFIG_PDA_POWER) += pda_power.o obj-$(CONFIG_APM_POWER) += apm_power.o +obj-$(CONFIG_MAX8925_POWER) += max8925_power.o obj-$(CONFIG_WM831X_BACKUP) += wm831x_backup.o obj-$(CONFIG_WM831X_POWER) += wm831x_power.o obj-$(CONFIG_WM8350_POWER) += wm8350_power.o diff --git a/drivers/power/max8925_power.c b/drivers/power/max8925_power.c new file mode 100644 index 0000000..a1b4410 --- /dev/null +++ b/drivers/power/max8925_power.c @@ -0,0 +1,534 @@ +/* + * Battery driver for Maxim MAX8925 + * + * Copyright (c) 2009-2010 Marvell International Ltd. + * Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* registers in GPM */ +#define MAX8925_OUT5VEN 0x54 +#define MAX8925_OUT3VEN 0x58 +#define MAX8925_CHG_CNTL1 0x7c + +/* bits definition */ +#define MAX8925_CHG_STAT_VSYSLOW (1 << 0) +#define MAX8925_CHG_STAT_MODE_MASK (3 << 2) +#define MAX8925_CHG_STAT_EN_MASK (1 << 4) +#define MAX8925_CHG_MBDET (1 << 1) +#define MAX8925_CHG_AC_RANGE_MASK (3 << 6) + +/* registers in ADC */ +#define MAX8925_ADC_RES_CNFG1 0x06 +#define MAX8925_ADC_AVG_CNFG1 0x07 +#define MAX8925_ADC_ACQ_CNFG1 0x08 +#define MAX8925_ADC_ACQ_CNFG2 0x09 +/* 2 bytes registers in below. MSB is 1st, LSB is 2nd. */ +#define MAX8925_ADC_AUX2 0x62 +#define MAX8925_ADC_VCHG 0x64 +#define MAX8925_ADC_VBBATT 0x66 +#define MAX8925_ADC_VMBATT 0x68 +#define MAX8925_ADC_ISNS 0x6a +#define MAX8925_ADC_THM 0x6c +#define MAX8925_ADC_TDIE 0x6e +#define MAX8925_CMD_AUX2 0xc8 +#define MAX8925_CMD_VCHG 0xd0 +#define MAX8925_CMD_VBBATT 0xd8 +#define MAX8925_CMD_VMBATT 0xe0 +#define MAX8925_CMD_ISNS 0xe8 +#define MAX8925_CMD_THM 0xf0 +#define MAX8925_CMD_TDIE 0xf8 + +enum { + MEASURE_AUX2, + MEASURE_VCHG, + MEASURE_VBBATT, + MEASURE_VMBATT, + MEASURE_ISNS, + MEASURE_THM, + MEASURE_TDIE, + MEASURE_MAX, +}; + +struct max8925_power_info { + struct max8925_chip *chip; + struct i2c_client *gpm; + struct i2c_client *adc; + + struct power_supply ac; + struct power_supply usb; + struct power_supply battery; + int irq_base; + unsigned ac_online:1; + unsigned usb_online:1; + unsigned bat_online:1; + unsigned chg_mode:2; + unsigned batt_detect:1; /* detecing MB by ID pin */ + unsigned topoff_threshold:2; + unsigned fast_charge:3; + + int (*set_charger) (int); +}; + +static int __set_charger(struct max8925_power_info *info, int enable) +{ + struct max8925_chip *chip = info->chip; + if (enable) { + /* enable charger in platform */ + if (info->set_charger) + info->set_charger(1); + /* enable charger */ + max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 0); + } else { + /* disable charge */ + max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 1 << 7); + if (info->set_charger) + info->set_charger(0); + } + dev_dbg(chip->dev, "%s\n", (enable) ? "Enable charger" + : "Disable charger"); + return 0; +} + +static irqreturn_t max8925_charger_handler(int irq, void *data) +{ + struct max8925_power_info *info = (struct max8925_power_info *)data; + struct max8925_chip *chip = info->chip; + + switch (irq - chip->irq_base) { + case MAX8925_IRQ_VCHG_DC_R: + info->ac_online = 1; + __set_charger(info, 1); + dev_dbg(chip->dev, "Adapter inserted\n"); + break; + case MAX8925_IRQ_VCHG_DC_F: + info->ac_online = 0; + __set_charger(info, 0); + dev_dbg(chip->dev, "Adapter is removal\n"); + break; + case MAX8925_IRQ_VCHG_USB_R: + info->usb_online = 1; + __set_charger(info, 1); + dev_dbg(chip->dev, "USB inserted\n"); + break; + case MAX8925_IRQ_VCHG_USB_F: + info->usb_online = 0; + __set_charger(info, 0); + dev_dbg(chip->dev, "USB is removal\n"); + break; + case MAX8925_IRQ_VCHG_THM_OK_F: + /* Battery is not ready yet */ + dev_dbg(chip->dev, "Battery temperature is out of range\n"); + case MAX8925_IRQ_VCHG_DC_OVP: + dev_dbg(chip->dev, "Error detection\n"); + __set_charger(info, 0); + break; + case MAX8925_IRQ_VCHG_THM_OK_R: + /* Battery is ready now */ + dev_dbg(chip->dev, "Battery temperature is in range\n"); + break; + case MAX8925_IRQ_VCHG_SYSLOW_R: + /* VSYS is low */ + dev_info(chip->dev, "Sys power is too low\n"); + break; + case MAX8925_IRQ_VCHG_SYSLOW_F: + dev_dbg(chip->dev, "Sys power is above low threshold\n"); + break; + case MAX8925_IRQ_VCHG_DONE: + __set_charger(info, 0); + dev_dbg(chip->dev, "Charging is done\n"); + break; + case MAX8925_IRQ_VCHG_TOPOFF: + dev_dbg(chip->dev, "Charging in top-off mode\n"); + break; + case MAX8925_IRQ_VCHG_TMR_FAULT: + __set_charger(info, 0); + dev_dbg(chip->dev, "Safe timer is expired\n"); + break; + case MAX8925_IRQ_VCHG_RST: + __set_charger(info, 0); + dev_dbg(chip->dev, "Charger is reset\n"); + break; + } + return IRQ_HANDLED; +} + +static int start_measure(struct max8925_power_info *info, int type) +{ + unsigned char buf[2] = {0, 0}; + int meas_reg = 0, ret; + + switch (type) { + case MEASURE_VCHG: + meas_reg = MAX8925_ADC_VCHG; + break; + case MEASURE_VBBATT: + meas_reg = MAX8925_ADC_VBBATT; + break; + case MEASURE_VMBATT: + meas_reg = MAX8925_ADC_VMBATT; + break; + case MEASURE_ISNS: + meas_reg = MAX8925_ADC_ISNS; + break; + default: + return -EINVAL; + } + + max8925_bulk_read(info->adc, meas_reg, 2, buf); + ret = (buf[0] << 4) | (buf[1] >> 4); + + return ret; +} + +static int max8925_ac_get_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = info->ac_online; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + if (info->ac_online) { + ret = start_measure(info, MEASURE_VCHG); + if (ret >= 0) { + val->intval = ret << 1; /* unit is mV */ + goto out; + } + } + ret = -ENODATA; + break; + default: + ret = -ENODEV; + break; + } +out: + return ret; +} + +static enum power_supply_property max8925_ac_props[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, +}; + +static int max8925_usb_get_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = info->usb_online; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + if (info->usb_online) { + ret = start_measure(info, MEASURE_VCHG); + if (ret >= 0) { + val->intval = ret << 1; /* unit is mV */ + goto out; + } + } + ret = -ENODATA; + break; + default: + ret = -ENODEV; + break; + } +out: + return ret; +} + +static enum power_supply_property max8925_usb_props[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, +}; + +static int max8925_bat_get_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct max8925_power_info *info = dev_get_drvdata(psy->dev->parent); + long long int tmp = 0; + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = info->bat_online; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + if (info->bat_online) { + ret = start_measure(info, MEASURE_VMBATT); + if (ret >= 0) { + val->intval = ret << 1; /* unit is mV */ + ret = 0; + break; + } + } + ret = -ENODATA; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + if (info->bat_online) { + ret = start_measure(info, MEASURE_ISNS); + if (ret >= 0) { + tmp = (long long int)ret * 6250 / 4096 - 3125; + ret = (int)tmp; + val->intval = 0; + if (ret > 0) + val->intval = ret; /* unit is mA */ + ret = 0; + break; + } + } + ret = -ENODATA; + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + if (!info->bat_online) { + ret = -ENODATA; + break; + } + ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS); + ret = (ret & MAX8925_CHG_STAT_MODE_MASK) >> 2; + switch (ret) { + case 1: + val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; + break; + case 0: + case 2: + val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + break; + case 3: + val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; + break; + } + ret = 0; + break; + case POWER_SUPPLY_PROP_STATUS: + if (!info->bat_online) { + ret = -ENODATA; + break; + } + ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS); + if (info->usb_online || info->ac_online) { + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + if (ret & MAX8925_CHG_STAT_EN_MASK) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + } else + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + ret = 0; + break; + default: + ret = -ENODEV; + break; + } + return ret; +} + +static enum power_supply_property max8925_battery_props[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_STATUS, +}; + +#define REQUEST_IRQ(_irq, _name) \ +do { \ + ret = request_threaded_irq(chip->irq_base + _irq, NULL, \ + max8925_charger_handler, \ + IRQF_ONESHOT, _name, info); \ + if (ret) \ + dev_err(chip->dev, "Failed to request IRQ #%d: %d\n", \ + _irq, ret); \ +} while (0) + +static __devinit int max8925_init_charger(struct max8925_chip *chip, + struct max8925_power_info *info) +{ + int ret; + + REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_OVP, "ac-ovp"); + REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_F, "ac-remove"); + REQUEST_IRQ(MAX8925_IRQ_VCHG_DC_R, "ac-insert"); + REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_OVP, "usb-ovp"); + REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_F, "usb-remove"); + REQUEST_IRQ(MAX8925_IRQ_VCHG_USB_R, "usb-insert"); + REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_R, "batt-temp-in-range"); + REQUEST_IRQ(MAX8925_IRQ_VCHG_THM_OK_F, "batt-temp-out-range"); + REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_F, "vsys-high"); + REQUEST_IRQ(MAX8925_IRQ_VCHG_SYSLOW_R, "vsys-low"); + REQUEST_IRQ(MAX8925_IRQ_VCHG_RST, "charger-reset"); + REQUEST_IRQ(MAX8925_IRQ_VCHG_DONE, "charger-done"); + REQUEST_IRQ(MAX8925_IRQ_VCHG_TOPOFF, "charger-topoff"); + REQUEST_IRQ(MAX8925_IRQ_VCHG_TMR_FAULT, "charger-timer-expire"); + + info->ac_online = 0; + info->usb_online = 0; + info->bat_online = 0; + ret = max8925_reg_read(info->gpm, MAX8925_CHG_STATUS); + if (ret >= 0) { + /* + * If battery detection is enabled, ID pin of battery is + * connected to MBDET pin of MAX8925. It could be used to + * detect battery presence. + * Otherwise, we have to assume that battery is always on. + */ + if (info->batt_detect) + info->bat_online = (ret & MAX8925_CHG_MBDET) ? 0 : 1; + else + info->bat_online = 1; + if (ret & MAX8925_CHG_AC_RANGE_MASK) + info->ac_online = 1; + else + info->ac_online = 0; + } + /* disable charge */ + max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 1 << 7, 1 << 7); + /* set charging current in charge topoff mode */ + max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 3 << 5, + info->topoff_threshold << 5); + /* set charing current in fast charge mode */ + max8925_set_bits(info->gpm, MAX8925_CHG_CNTL1, 7, info->fast_charge); + + return 0; +} + +static __devexit int max8925_deinit_charger(struct max8925_power_info *info) +{ + struct max8925_chip *chip = info->chip; + int irq; + + irq = chip->irq_base + MAX8925_IRQ_VCHG_DC_OVP; + for (; irq <= chip->irq_base + MAX8925_IRQ_VCHG_TMR_FAULT; irq++) + free_irq(irq, info); + + return 0; +} + +static __devinit int max8925_power_probe(struct platform_device *pdev) +{ + struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct max8925_platform_data *max8925_pdata; + struct max8925_power_pdata *pdata = NULL; + struct max8925_power_info *info; + int ret; + + if (pdev->dev.parent->platform_data) { + max8925_pdata = pdev->dev.parent->platform_data; + pdata = max8925_pdata->power; + } + + if (!pdata) { + dev_err(&pdev->dev, "platform data isn't assigned to " + "power supply\n"); + return -EINVAL; + } + + info = kzalloc(sizeof(struct max8925_power_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + info->chip = chip; + info->gpm = chip->i2c; + info->adc = chip->adc; + + info->ac.name = "max8925-ac"; + info->ac.type = POWER_SUPPLY_TYPE_MAINS; + info->ac.properties = max8925_ac_props; + info->ac.num_properties = ARRAY_SIZE(max8925_ac_props); + info->ac.get_property = max8925_ac_get_prop; + ret = power_supply_register(&pdev->dev, &info->ac); + if (ret) + goto out; + info->ac.dev->parent = &pdev->dev; + + info->usb.name = "max8925-usb"; + info->usb.type = POWER_SUPPLY_TYPE_USB; + info->usb.properties = max8925_usb_props; + info->usb.num_properties = ARRAY_SIZE(max8925_usb_props); + info->usb.get_property = max8925_usb_get_prop; + ret = power_supply_register(&pdev->dev, &info->usb); + if (ret) + goto out_usb; + info->usb.dev->parent = &pdev->dev; + + info->battery.name = "max8925-battery"; + info->battery.type = POWER_SUPPLY_TYPE_BATTERY; + info->battery.properties = max8925_battery_props; + info->battery.num_properties = ARRAY_SIZE(max8925_battery_props); + info->battery.get_property = max8925_bat_get_prop; + ret = power_supply_register(&pdev->dev, &info->battery); + if (ret) + goto out_battery; + info->battery.dev->parent = &pdev->dev; + + info->batt_detect = pdata->batt_detect; + info->topoff_threshold = pdata->topoff_threshold; + info->fast_charge = pdata->fast_charge; + info->set_charger = pdata->set_charger; + dev_set_drvdata(&pdev->dev, info); + platform_set_drvdata(pdev, info); + + max8925_init_charger(chip, info); + return 0; +out_battery: + power_supply_unregister(&info->battery); +out_usb: + power_supply_unregister(&info->ac); +out: + kfree(info); + return ret; +} + +static __devexit int max8925_power_remove(struct platform_device *pdev) +{ + struct max8925_power_info *info = platform_get_drvdata(pdev); + + if (info) { + power_supply_unregister(&info->ac); + power_supply_unregister(&info->usb); + power_supply_unregister(&info->battery); + max8925_deinit_charger(info); + kfree(info); + } + return 0; +} + +static struct platform_driver max8925_power_driver = { + .probe = max8925_power_probe, + .remove = __devexit_p(max8925_power_remove), + .driver = { + .name = "max8925-power", + }, +}; + +static int __init max8925_power_init(void) +{ + return platform_driver_register(&max8925_power_driver); +} +module_init(max8925_power_init); + +static void __exit max8925_power_exit(void) +{ + platform_driver_unregister(&max8925_power_driver); +} +module_exit(max8925_power_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Power supply driver for MAX8925"); +MODULE_ALIAS("platform:max8925-power"); -- cgit v0.10.2 From 34c9120805ff4b3f7a8053bd64157ba564774433 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 3 Feb 2010 15:37:23 -0500 Subject: mfd: Clean code in max8925 Remove unused definitions. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/include/linux/mfd/max8925.h b/include/linux/mfd/max8925.h index 18c1844..5259dfe 100644 --- a/include/linux/mfd/max8925.h +++ b/include/linux/mfd/max8925.h @@ -158,11 +158,6 @@ enum { #define TSC_IRQ_MASK (0x03) #define RTC_IRQ_MASK (0x0c) -#define MAX8925_GPM_NUM_IRQ (40) -#define MAX8925_ADC_NUM_IRQ (8) -#define MAX8925_NUM_IRQ (MAX8925_GPM_NUM_IRQ \ - + MAX8925_ADC_NUM_IRQ) - #define MAX8925_MAX_REGULATOR (23) #define MAX8925_NAME_SIZE (32) @@ -200,17 +195,11 @@ enum { MAX8925_NR_IRQS, }; -struct max8925_irq { - irq_handler_t handler; - void *data; -}; - struct max8925_chip { struct device *dev; struct i2c_client *i2c; struct i2c_client *adc; struct i2c_client *rtc; - struct max8925_irq irqs[MAX8925_NUM_IRQ]; struct mutex io_lock; struct mutex irq_lock; @@ -257,12 +246,6 @@ extern int max8925_bulk_write(struct i2c_client *, int, int, unsigned char *); extern int max8925_set_bits(struct i2c_client *, int, unsigned char, unsigned char); -extern int max8925_request_irq(struct max8925_chip *, int, - irq_handler_t, void *); -extern int max8925_free_irq(struct max8925_chip *, int); -extern int max8925_mask_irq(struct max8925_chip *, int); -extern int max8925_unmask_irq(struct max8925_chip *, int); - extern int max8925_device_init(struct max8925_chip *, struct max8925_platform_data *); extern void max8925_device_exit(struct max8925_chip *); -- cgit v0.10.2 From e8343ddaccb322b1a2a989ac362cabd1e94597ad Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 3 Feb 2010 15:38:12 -0500 Subject: mfd: Use i2c_dummy in 88pm860x Use i2c_dummy in 88pm860x driver to avoid using static in probe function. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index 6d7dba2..c37e12b 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c @@ -157,18 +157,24 @@ static int __devinit pm860x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pm860x_platform_data *pdata = client->dev.platform_data; - static struct pm860x_chip *chip; - struct i2c_board_info i2c_info = { - .type = "88PM860x", - .platform_data = client->dev.platform_data, - }; - int addr_c, found_companion = 0; - - if (pdata == NULL) { + struct pm860x_chip *chip; + + if (!pdata) { pr_info("No platform data in %s!\n", __func__); return -EINVAL; } + chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + chip->id = verify_addr(client); + chip->client = client; + i2c_set_clientdata(client, chip); + chip->dev = &client->dev; + mutex_init(&chip->io_lock); + dev_set_drvdata(chip->dev, chip); + /* * Both client and companion client shares same platform driver. * Driver distinguishes them by pdata->companion_addr. @@ -176,46 +182,14 @@ static int __devinit pm860x_probe(struct i2c_client *client, * At the same time, the companion_addr shouldn't equal to client * address. */ - addr_c = pdata->companion_addr; - if (addr_c && (addr_c != client->addr)) { - i2c_info.addr = addr_c; - found_companion = 1; - } - - if (found_companion || (addr_c == 0)) { - chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; - - chip->id = verify_addr(client); - chip->companion_addr = addr_c; - chip->client = client; - i2c_set_clientdata(client, chip); - chip->dev = &client->dev; - mutex_init(&chip->io_lock); - dev_set_drvdata(chip->dev, chip); - - if (found_companion) { - /* - * If this driver is built in, probe function is - * recursive. - * If this driver is built as module, the next probe - * function is called after the first one finished. - */ - chip->companion = i2c_new_device(client->adapter, - &i2c_info); - } - } - - /* - * If companion chip existes, it's called by companion probe. - * If there's no companion chip, it's called by client probe. - */ - if ((addr_c == 0) || (addr_c == client->addr)) { - chip->companion = client; + if (pdata->companion_addr && (pdata->companion_addr != client->addr)) { + chip->companion_addr = pdata->companion_addr; + chip->companion = i2c_new_dummy(chip->client->adapter, + chip->companion_addr); i2c_set_clientdata(chip->companion, chip); - pm860x_device_init(chip, pdata); } + + pm860x_device_init(chip, pdata); return 0; } @@ -223,12 +197,6 @@ static int __devexit pm860x_remove(struct i2c_client *client) { struct pm860x_chip *chip = i2c_get_clientdata(client); - /* - * If companion existes, companion client is removed first. - * Because companion client is registered last and removed first. - */ - if (chip->companion_addr == client->addr) - return 0; pm860x_device_exit(chip); i2c_unregister_device(chip->companion); i2c_set_clientdata(chip->companion, NULL); -- cgit v0.10.2 From 7731074ab21745cde00578148ce760df107eaf27 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Sun, 7 Feb 2010 10:16:14 +0900 Subject: mfd: Fix WM8994 error handling This patch fixes wrong goto statement for error handling on probe. Signed-off-by: Myungjoo Ham Signed-off-by: Joonyoung Shim Acked-by: Mark Brown Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 299c1af..844e1c1 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -305,14 +305,14 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) wm8994->supplies); if (ret != 0) { dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret); - goto err_get; + goto err_supplies; } ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies); if (ret != 0) { dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret); - goto err_supplies; + goto err_get; } ret = wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET); -- cgit v0.10.2 From 2afa62ea76027b00e472ddb672191e6e15425b43 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 8 Feb 2010 05:02:00 -0500 Subject: mfd: Use genirq in 88pm860x Use genirq to simplify IRQ handling in 88pm860x. Remove the interface of mask/free IRQs on 88pm860x. All these work is taken by genirq. Update the touchscreen driver of 88pm860x since IRQ handling is changed. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index 56254d2..286bb49 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c @@ -54,7 +54,6 @@ static irqreturn_t pm860x_touch_handler(int irq, void *data) int z1, z2, rt = 0; int ret; - pm860x_mask_irq(chip, irq); ret = pm860x_bulk_read(touch->i2c, MEAS_TSIX_1, MEAS_LEN, buf); if (ret < 0) goto out; @@ -83,7 +82,6 @@ static irqreturn_t pm860x_touch_handler(int irq, void *data) dev_dbg(chip->dev, "pen release\n"); } input_sync(touch->idev); - pm860x_unmask_irq(chip, irq); out: return IRQ_HANDLED; @@ -92,7 +90,6 @@ out: static int pm860x_touch_open(struct input_dev *dev) { struct pm860x_touch *touch = input_get_drvdata(dev); - struct pm860x_chip *chip = touch->chip; int data, ret; data = MEAS_PD_EN | MEAS_TSIX_EN | MEAS_TSIY_EN @@ -100,7 +97,6 @@ static int pm860x_touch_open(struct input_dev *dev) ret = pm860x_set_bits(touch->i2c, MEAS_EN3, data, data); if (ret < 0) goto out; - pm860x_unmask_irq(chip, touch->irq); return 0; out: return ret; @@ -109,13 +105,11 @@ out: static void pm860x_touch_close(struct input_dev *dev) { struct pm860x_touch *touch = input_get_drvdata(dev); - struct pm860x_chip *chip = touch->chip; int data; data = MEAS_PD_EN | MEAS_TSIX_EN | MEAS_TSIY_EN | MEAS_TSIZ1_EN | MEAS_TSIZ2_EN; pm860x_set_bits(touch->i2c, MEAS_EN3, data, 0); - pm860x_mask_irq(chip, touch->irq); } static int __devinit pm860x_touch_probe(struct platform_device *pdev) @@ -164,11 +158,12 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev) touch->idev->close = pm860x_touch_close; touch->chip = chip; touch->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; - touch->irq = irq; + touch->irq = irq + chip->irq_base; touch->res_x = pdata->res_x; input_set_drvdata(touch->idev, touch); - ret = pm860x_request_irq(chip, irq, pm860x_touch_handler, touch); + ret = request_threaded_irq(touch->irq, NULL, pm860x_touch_handler, + IRQF_ONESHOT, "touch", touch); if (ret < 0) goto out_irq; @@ -194,7 +189,7 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev) platform_set_drvdata(pdev, touch); return 0; out_rg: - pm860x_free_irq(chip, irq); + free_irq(touch->irq, touch); out_irq: input_free_device(touch->idev); out: @@ -207,7 +202,7 @@ static int __devexit pm860x_touch_remove(struct platform_device *pdev) struct pm860x_touch *touch = platform_get_drvdata(pdev); input_unregister_device(touch->idev); - pm860x_free_irq(touch->chip, touch->irq); + free_irq(touch->irq, touch); platform_set_drvdata(pdev, NULL); kfree(touch); return 0; diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 16f0dca..6a14d2b 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -12,11 +12,14 @@ #include #include #include +#include #include #include #include #include +#define INT_STATUS_NUM 3 + char pm860x_backlight_name[][MFD_NAME_SIZE] = { "backlight-0", "backlight-1", @@ -119,6 +122,42 @@ static struct mfd_cell touch_devs[] = { .flags = IORESOURCE_IO, \ } +static struct resource power_supply_resources[] = { + { + .name = "88pm860x-power", + .start = PM8607_IRQ_CHG, + .end = PM8607_IRQ_CHG, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mfd_cell power_devs[] = { + { + .name = "88pm860x-power", + .num_resources = 1, + .resources = &power_supply_resources[0], + .id = -1, + }, +}; + +static struct resource onkey_resources[] = { + { + .name = "88pm860x-onkey", + .start = PM8607_IRQ_ONKEY, + .end = PM8607_IRQ_ONKEY, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mfd_cell onkey_devs[] = { + { + .name = "88pm860x-onkey", + .num_resources = 1, + .resources = &onkey_resources[0], + .id = -1, + }, +}; + static struct resource regulator_resources[] = { PM8607_REG_RESOURCE(BUCK1, BUCK1), PM8607_REG_RESOURCE(BUCK2, BUCK2), @@ -163,129 +202,224 @@ static struct mfd_cell regulator_devs[] = { PM8607_REG_DEVS(ldo14, LDO14), }; -#define CHECK_IRQ(irq) \ -do { \ - if ((irq < 0) || (irq >= PM860X_NUM_IRQ)) \ - return -EINVAL; \ -} while (0) - -/* IRQs only occur on 88PM8607 */ -int pm860x_mask_irq(struct pm860x_chip *chip, int irq) -{ - struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ - : chip->companion; - int offset, data, ret; - - CHECK_IRQ(irq); - - offset = (irq >> 3) + PM8607_INT_MASK_1; - data = 1 << (irq % 8); - ret = pm860x_set_bits(i2c, offset, data, 0); +struct pm860x_irq_data { + int reg; + int mask_reg; + int enable; /* enable or not */ + int offs; /* bit offset in mask register */ +}; - return ret; -} -EXPORT_SYMBOL(pm860x_mask_irq); +static struct pm860x_irq_data pm860x_irqs[] = { + [PM8607_IRQ_ONKEY] = { + .reg = PM8607_INT_STATUS1, + .mask_reg = PM8607_INT_MASK_1, + .offs = 1 << 0, + }, + [PM8607_IRQ_EXTON] = { + .reg = PM8607_INT_STATUS1, + .mask_reg = PM8607_INT_MASK_1, + .offs = 1 << 1, + }, + [PM8607_IRQ_CHG] = { + .reg = PM8607_INT_STATUS1, + .mask_reg = PM8607_INT_MASK_1, + .offs = 1 << 2, + }, + [PM8607_IRQ_BAT] = { + .reg = PM8607_INT_STATUS1, + .mask_reg = PM8607_INT_MASK_1, + .offs = 1 << 3, + }, + [PM8607_IRQ_RTC] = { + .reg = PM8607_INT_STATUS1, + .mask_reg = PM8607_INT_MASK_1, + .offs = 1 << 4, + }, + [PM8607_IRQ_CC] = { + .reg = PM8607_INT_STATUS1, + .mask_reg = PM8607_INT_MASK_1, + .offs = 1 << 5, + }, + [PM8607_IRQ_VBAT] = { + .reg = PM8607_INT_STATUS2, + .mask_reg = PM8607_INT_MASK_2, + .offs = 1 << 0, + }, + [PM8607_IRQ_VCHG] = { + .reg = PM8607_INT_STATUS2, + .mask_reg = PM8607_INT_MASK_2, + .offs = 1 << 1, + }, + [PM8607_IRQ_VSYS] = { + .reg = PM8607_INT_STATUS2, + .mask_reg = PM8607_INT_MASK_2, + .offs = 1 << 2, + }, + [PM8607_IRQ_TINT] = { + .reg = PM8607_INT_STATUS2, + .mask_reg = PM8607_INT_MASK_2, + .offs = 1 << 3, + }, + [PM8607_IRQ_GPADC0] = { + .reg = PM8607_INT_STATUS2, + .mask_reg = PM8607_INT_MASK_2, + .offs = 1 << 4, + }, + [PM8607_IRQ_GPADC1] = { + .reg = PM8607_INT_STATUS2, + .mask_reg = PM8607_INT_MASK_2, + .offs = 1 << 5, + }, + [PM8607_IRQ_GPADC2] = { + .reg = PM8607_INT_STATUS2, + .mask_reg = PM8607_INT_MASK_2, + .offs = 1 << 6, + }, + [PM8607_IRQ_GPADC3] = { + .reg = PM8607_INT_STATUS2, + .mask_reg = PM8607_INT_MASK_2, + .offs = 1 << 7, + }, + [PM8607_IRQ_AUDIO_SHORT] = { + .reg = PM8607_INT_STATUS3, + .mask_reg = PM8607_INT_MASK_3, + .offs = 1 << 0, + }, + [PM8607_IRQ_PEN] = { + .reg = PM8607_INT_STATUS3, + .mask_reg = PM8607_INT_MASK_3, + .offs = 1 << 1, + }, + [PM8607_IRQ_HEADSET] = { + .reg = PM8607_INT_STATUS3, + .mask_reg = PM8607_INT_MASK_3, + .offs = 1 << 2, + }, + [PM8607_IRQ_HOOK] = { + .reg = PM8607_INT_STATUS3, + .mask_reg = PM8607_INT_MASK_3, + .offs = 1 << 3, + }, + [PM8607_IRQ_MICIN] = { + .reg = PM8607_INT_STATUS3, + .mask_reg = PM8607_INT_MASK_3, + .offs = 1 << 4, + }, + [PM8607_IRQ_CHG_FAIL] = { + .reg = PM8607_INT_STATUS3, + .mask_reg = PM8607_INT_MASK_3, + .offs = 1 << 5, + }, + [PM8607_IRQ_CHG_DONE] = { + .reg = PM8607_INT_STATUS3, + .mask_reg = PM8607_INT_MASK_3, + .offs = 1 << 6, + }, + [PM8607_IRQ_CHG_FAULT] = { + .reg = PM8607_INT_STATUS3, + .mask_reg = PM8607_INT_MASK_3, + .offs = 1 << 7, + }, +}; -int pm860x_unmask_irq(struct pm860x_chip *chip, int irq) +static inline struct pm860x_irq_data *irq_to_pm860x(struct pm860x_chip *chip, + int irq) { - struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ - : chip->companion; - int offset, data, ret; - - CHECK_IRQ(irq); - - offset = (irq >> 3) + PM8607_INT_MASK_1; - data = 1 << (irq % 8); - ret = pm860x_set_bits(i2c, offset, data, data); - - return ret; + return &pm860x_irqs[irq - chip->irq_base]; } -EXPORT_SYMBOL(pm860x_unmask_irq); -#define INT_STATUS_NUM (3) - -static irqreturn_t pm8607_irq_thread(int irq, void *data) +static irqreturn_t pm860x_irq(int irq, void *data) { - DECLARE_BITMAP(irq_status, PM860X_NUM_IRQ); struct pm860x_chip *chip = data; - struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ - : chip->companion; - unsigned char status_buf[INT_STATUS_NUM << 1]; - unsigned long value; - int i, ret; - - irq_status[0] = 0; - - /* read out status register */ - ret = pm860x_bulk_read(i2c, PM8607_INT_STATUS1, - INT_STATUS_NUM << 1, status_buf); - if (ret < 0) - goto out; - if (chip->irq_mode) { - /* 0, clear by read. 1, clear by write */ - ret = pm860x_bulk_write(i2c, PM8607_INT_STATUS1, - INT_STATUS_NUM, status_buf); - if (ret < 0) - goto out; - } - - /* clear masked interrupt status */ - for (i = 0, value = 0; i < INT_STATUS_NUM; i++) { - status_buf[i] &= status_buf[i + INT_STATUS_NUM]; - irq_status[0] |= status_buf[i] << (i * 8); - } - - while (!bitmap_empty(irq_status, PM860X_NUM_IRQ)) { - irq = find_first_bit(irq_status, PM860X_NUM_IRQ); - clear_bit(irq, irq_status); - dev_dbg(chip->dev, "Servicing IRQ #%d\n", irq); - - mutex_lock(&chip->irq_lock); - if (chip->irq[irq].handler) - chip->irq[irq].handler(irq, chip->irq[irq].data); - else { - pm860x_mask_irq(chip, irq); - dev_err(chip->dev, "Nobody cares IRQ %d. " - "Now mask it.\n", irq); - for (i = 0; i < (INT_STATUS_NUM << 1); i++) { - dev_err(chip->dev, "status[%d]:%x\n", i, - status_buf[i]); - } + struct pm860x_irq_data *irq_data; + struct i2c_client *i2c; + int read_reg = -1, value = 0; + int i; + + i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; + for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { + irq_data = &pm860x_irqs[i]; + if (read_reg != irq_data->reg) { + read_reg = irq_data->reg; + value = pm860x_reg_read(i2c, irq_data->reg); } - mutex_unlock(&chip->irq_lock); + if (value & irq_data->enable) + handle_nested_irq(chip->irq_base + i); } -out: return IRQ_HANDLED; } -int pm860x_request_irq(struct pm860x_chip *chip, int irq, - irq_handler_t handler, void *data) +static void pm860x_irq_lock(unsigned int irq) { - CHECK_IRQ(irq); - if (!handler) - return -EINVAL; + struct pm860x_chip *chip = get_irq_chip_data(irq); mutex_lock(&chip->irq_lock); - chip->irq[irq].handler = handler; - chip->irq[irq].data = data; - mutex_unlock(&chip->irq_lock); - - return 0; } -EXPORT_SYMBOL(pm860x_request_irq); -int pm860x_free_irq(struct pm860x_chip *chip, int irq) +static void pm860x_irq_sync_unlock(unsigned int irq) { - CHECK_IRQ(irq); + struct pm860x_chip *chip = get_irq_chip_data(irq); + struct pm860x_irq_data *irq_data; + struct i2c_client *i2c; + static unsigned char cached[3] = {0x0, 0x0, 0x0}; + unsigned char mask[3]; + int i; + + i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; + /* Load cached value. In initial, all IRQs are masked */ + for (i = 0; i < 3; i++) + mask[i] = cached[i]; + for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { + irq_data = &pm860x_irqs[i]; + switch (irq_data->mask_reg) { + case PM8607_INT_MASK_1: + mask[0] &= ~irq_data->offs; + mask[0] |= irq_data->enable; + break; + case PM8607_INT_MASK_2: + mask[1] &= ~irq_data->offs; + mask[1] |= irq_data->enable; + break; + case PM8607_INT_MASK_3: + mask[2] &= ~irq_data->offs; + mask[2] |= irq_data->enable; + break; + default: + dev_err(chip->dev, "wrong IRQ\n"); + break; + } + } + /* update mask into registers */ + for (i = 0; i < 3; i++) { + if (mask[i] != cached[i]) { + cached[i] = mask[i]; + pm860x_reg_write(i2c, PM8607_INT_MASK_1 + i, mask[i]); + } + } - mutex_lock(&chip->irq_lock); - chip->irq[irq].handler = NULL; - chip->irq[irq].data = NULL; mutex_unlock(&chip->irq_lock); +} - return 0; +static void pm860x_irq_enable(unsigned int irq) +{ + struct pm860x_chip *chip = get_irq_chip_data(irq); + pm860x_irqs[irq - chip->irq_base].enable + = pm860x_irqs[irq - chip->irq_base].offs; } -EXPORT_SYMBOL(pm860x_free_irq); + +static void pm860x_irq_disable(unsigned int irq) +{ + struct pm860x_chip *chip = get_irq_chip_data(irq); + pm860x_irqs[irq - chip->irq_base].enable = 0; +} + +static struct irq_chip pm860x_irq_chip = { + .name = "88pm860x", + .bus_lock = pm860x_irq_lock, + .bus_sync_unlock = pm860x_irq_sync_unlock, + .enable = pm860x_irq_enable, + .disable = pm860x_irq_disable, +}; static int __devinit device_gpadc_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) @@ -348,9 +482,15 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ : chip->companion; unsigned char status_buf[INT_STATUS_NUM]; - int data, mask, ret = -EINVAL; + unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + struct irq_desc *desc; + int i, data, mask, ret = -EINVAL; + int __irq; - mutex_init(&chip->irq_lock); + if (!pdata || !pdata->irq_base) { + dev_warn(chip->dev, "No interrupt support on IRQ base\n"); + return -EINVAL; + } mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR | PM8607_B0_MISC1_INT_MASK; @@ -389,25 +529,45 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, if (ret < 0) goto out; - memset(chip->irq, 0, sizeof(struct pm860x_irq) * PM860X_NUM_IRQ); - - ret = request_threaded_irq(i2c->irq, NULL, pm8607_irq_thread, - IRQF_ONESHOT | IRQF_TRIGGER_LOW, - "88PM8607", chip); - if (ret < 0) { - dev_err(chip->dev, "Failed to request IRQ #%d.\n", i2c->irq); + mutex_init(&chip->irq_lock); + chip->irq_base = pdata->irq_base; + chip->core_irq = i2c->irq; + if (!chip->core_irq) goto out; + + desc = irq_to_desc(chip->core_irq); + + /* register IRQ by genirq */ + for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { + __irq = i + chip->irq_base; + set_irq_chip_data(__irq, chip); + set_irq_chip_and_handler(__irq, &pm860x_irq_chip, + handle_edge_irq); + set_irq_nested_thread(__irq, 1); +#ifdef CONFIG_ARM + set_irq_flags(__irq, IRQF_VALID); +#else + set_irq_noprobe(__irq); +#endif } - chip->chip_irq = i2c->irq; + + ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags, + "88pm860x", chip); + if (ret) { + dev_err(chip->dev, "Failed to request IRQ: %d\n", ret); + chip->core_irq = 0; + } + return 0; out: + chip->core_irq = 0; return ret; } static void __devexit device_irq_exit(struct pm860x_chip *chip) { - if (chip->chip_irq >= 0) - free_irq(chip->chip_irq, chip); + if (chip->core_irq) + free_irq(chip->core_irq, chip); } static void __devinit device_8606_init(struct pm860x_chip *chip, @@ -513,6 +673,26 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, goto out_dev; } } + + if (pdata && pdata->power) { + ret = mfd_add_devices(chip->dev, 0, &power_devs[0], + ARRAY_SIZE(power_devs), + &power_supply_resources[0], 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add power supply " + "subdev\n"); + goto out_dev; + } + } + + ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], + ARRAY_SIZE(onkey_devs), + &onkey_resources[0], 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add onkey subdev\n"); + goto out_dev; + } + return; out_dev: mfd_remove_devices(chip->dev); @@ -524,7 +704,7 @@ out: int pm860x_device_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { - chip->chip_irq = -EINVAL; + chip->core_irq = 0; switch (chip->id) { case CHIP_PM8606: diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h index 80bc82a..73f92c5 100644 --- a/include/linux/mfd/88pm860x.h +++ b/include/linux/mfd/88pm860x.h @@ -262,12 +262,13 @@ enum { /* Interrupt Number in 88PM8607 */ enum { - PM8607_IRQ_ONKEY = 0, + PM8607_IRQ_ONKEY, PM8607_IRQ_EXTON, PM8607_IRQ_CHG, PM8607_IRQ_BAT, PM8607_IRQ_RTC, - PM8607_IRQ_VBAT = 8, + PM8607_IRQ_CC, + PM8607_IRQ_VBAT, PM8607_IRQ_VCHG, PM8607_IRQ_VSYS, PM8607_IRQ_TINT, @@ -275,7 +276,7 @@ enum { PM8607_IRQ_GPADC1, PM8607_IRQ_GPADC2, PM8607_IRQ_GPADC3, - PM8607_IRQ_AUDIO_SHORT = 16, + PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_PEN, PM8607_IRQ_HEADSET, PM8607_IRQ_HOOK, @@ -291,26 +292,19 @@ enum { PM8607_CHIP_B0 = 0x48, }; -#define PM860X_NUM_IRQ 24 - -struct pm860x_irq { - irq_handler_t handler; - void *data; -}; - struct pm860x_chip { struct device *dev; struct mutex io_lock; struct mutex irq_lock; struct i2c_client *client; struct i2c_client *companion; /* companion chip client */ - struct pm860x_irq irq[PM860X_NUM_IRQ]; int buck3_double; /* DVC ramp slope double */ unsigned short companion_addr; int id; int irq_mode; - int chip_irq; + int irq_base; + int core_irq; unsigned char chip_version; }; @@ -347,14 +341,20 @@ struct pm860x_touch_pdata { unsigned long flags; }; +struct pm860x_power_pdata { + unsigned fast_charge; /* charge current */ +}; + struct pm860x_platform_data { struct pm860x_backlight_pdata *backlight; struct pm860x_led_pdata *led; struct pm860x_touch_pdata *touch; + struct pm860x_power_pdata *power; unsigned short companion_addr; /* I2C address of companion chip */ int i2c_port; /* Controlled by GI2C or PI2C */ int irq_mode; /* Clear interrupt by read/write(0/1) */ + int irq_base; /* IRQ base number of 88pm860x */ struct regulator_init_data *regulator[PM8607_MAX_REGULATOR]; }; @@ -368,12 +368,6 @@ extern int pm860x_bulk_write(struct i2c_client *, int, int, unsigned char *); extern int pm860x_set_bits(struct i2c_client *, int, unsigned char, unsigned char); -extern int pm860x_mask_irq(struct pm860x_chip *, int); -extern int pm860x_unmask_irq(struct pm860x_chip *, int); -extern int pm860x_request_irq(struct pm860x_chip *, int, - irq_handler_t handler, void *); -extern int pm860x_free_irq(struct pm860x_chip *, int); - extern int pm860x_device_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata); extern void pm860x_device_exit(struct pm860x_chip *chip); -- cgit v0.10.2 From 6985403138b74ad28c8ddac8baf88869556bec9a Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 3 Feb 2010 15:40:59 -0500 Subject: input: Support onkey in 88pm860x Signed-off-by: Haojian Zhuang Acked-by: Dmitry Torokhov Signed-off-by: Samuel Ortiz diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c new file mode 100644 index 0000000..69a48e8 --- /dev/null +++ b/drivers/input/misc/88pm860x_onkey.c @@ -0,0 +1,155 @@ +/* + * 88pm860x_onkey.c - Marvell 88PM860x ONKEY driver + * + * Copyright (C) 2009-2010 Marvell International Ltd. + * Haojian Zhuang + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#define PM8607_WAKEUP 0x0b + +#define LONG_ONKEY_EN (1 << 1) +#define ONKEY_STATUS (1 << 0) + +struct pm860x_onkey_info { + struct input_dev *idev; + struct pm860x_chip *chip; + struct i2c_client *i2c; + struct device *dev; + int irq; +}; + +/* 88PM860x gives us an interrupt when ONKEY is held */ +static irqreturn_t pm860x_onkey_handler(int irq, void *data) +{ + struct pm860x_onkey_info *info = data; + int ret; + + ret = pm860x_reg_read(info->i2c, PM8607_STATUS_2); + ret &= ONKEY_STATUS; + input_report_key(info->idev, KEY_POWER, ret); + input_sync(info->idev); + + /* Enable 8-second long onkey detection */ + pm860x_set_bits(info->i2c, PM8607_WAKEUP, 3, LONG_ONKEY_EN); + return IRQ_HANDLED; +} + +static int __devinit pm860x_onkey_probe(struct platform_device *pdev) +{ + struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct pm860x_onkey_info *info; + int irq, ret; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "No IRQ resource!\n"); + return -EINVAL; + } + + info = kzalloc(sizeof(struct pm860x_onkey_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + info->chip = chip; + info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; + info->dev = &pdev->dev; + info->irq = irq + chip->irq_base; + + info->idev = input_allocate_device(); + if (!info->idev) { + dev_err(chip->dev, "Failed to allocate input dev\n"); + ret = -ENOMEM; + goto out; + } + + info->idev->name = "88pm860x_on"; + info->idev->phys = "88pm860x_on/input0"; + info->idev->id.bustype = BUS_I2C; + info->idev->dev.parent = &pdev->dev; + info->irq = irq; + info->idev->evbit[0] = BIT_MASK(EV_KEY); + info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); + + ret = input_register_device(info->idev); + if (ret) { + dev_err(chip->dev, "Can't register input device: %d\n", ret); + goto out_reg; + } + + ret = request_threaded_irq(info->irq, NULL, pm860x_onkey_handler, + IRQF_ONESHOT, "onkey", info); + if (ret < 0) { + dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", + info->irq, ret); + goto out_irq; + } + + platform_set_drvdata(pdev, info); + return 0; + +out_irq: + input_unregister_device(info->idev); + kfree(info); + return ret; + +out_reg: + input_free_device(info->idev); +out: + kfree(info); + return ret; +} + +static int __devexit pm860x_onkey_remove(struct platform_device *pdev) +{ + struct pm860x_onkey_info *info = platform_get_drvdata(pdev); + + free_irq(info->irq, info); + input_unregister_device(info->idev); + kfree(info); + return 0; +} + +static struct platform_driver pm860x_onkey_driver = { + .driver = { + .name = "88pm860x-onkey", + .owner = THIS_MODULE, + }, + .probe = pm860x_onkey_probe, + .remove = __devexit_p(pm860x_onkey_remove), +}; + +static int __init pm860x_onkey_init(void) +{ + return platform_driver_register(&pm860x_onkey_driver); +} +module_init(pm860x_onkey_init); + +static void __exit pm860x_onkey_exit(void) +{ + platform_driver_unregister(&pm860x_onkey_driver); +} +module_exit(pm860x_onkey_exit); + +MODULE_DESCRIPTION("Marvell 88PM860x ONKEY driver"); +MODULE_AUTHOR("Haojian Zhuang "); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 16ec523..7097bfe 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -12,6 +12,16 @@ menuconfig INPUT_MISC if INPUT_MISC +config INPUT_88PM860X_ONKEY + tristate "88PM860x ONKEY support" + depends on MFD_88PM860X + help + Support the ONKEY of Marvell 88PM860x PMICs as an input device + reporting power button status. + + To compile this driver as a module, choose M here: the module + will be called 88pm860x_onkey. + config INPUT_PCSPKR tristate "PC Speaker support" depends on PCSPKR_PLATFORM diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index a8b8485..b611615 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -4,6 +4,7 @@ # Each configuration option enables a list of files. +obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o obj-$(CONFIG_INPUT_APANEL) += apanel.o obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o -- cgit v0.10.2 From 14e5c82ca32870698b7cbe54196e00682d929ca5 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 11 Feb 2010 13:47:09 +0100 Subject: mfd: Fix twl_has_pwrbutton typo Change the typo CONFIG_INPUT_TWL4030_PWBUTTON_MODULE in the twl_has_pwrbutton definition to CONFIG_INPUT_TWL4030_PWRBUTTON_MODULE. Signed-off-by: Eduardo Valentin Signed-off-by: Christoph Egger Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index d81003f..942a1e8 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -123,7 +123,7 @@ #define TWL_NUM_SLAVES 4 #if defined(CONFIG_INPUT_TWL4030_PWRBUTTON) \ - || defined(CONFIG_INPUT_TWL4030_PWBUTTON_MODULE) + || defined(CONFIG_INPUT_TWL4030_PWRBUTTON_MODULE) #define twl_has_pwrbutton() true #else #define twl_has_pwrbutton() false -- cgit v0.10.2 From 91fedede0338eb6203cdd618d8ece873fdb7c22c Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 19 Feb 2010 11:07:59 +0100 Subject: mfd: Check for ACPI conflicts For ACPI based systems, we should check for ACPI conflicts when adding the platform devices. The test will always succeed for non ACPI platforms. Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index ae15e49..aa17f4b 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -13,6 +13,7 @@ #include #include +#include #include static int mfd_add_device(struct device *parent, int id, @@ -62,6 +63,10 @@ static int mfd_add_device(struct device *parent, int id, res[r].start = cell->resources[r].start; res[r].end = cell->resources[r].end; } + + ret = acpi_check_resource_conflict(res); + if (ret) + goto fail_res; } platform_device_add_resources(pdev, res, cell->num_resources); -- cgit v0.10.2 From e82c60ae7d3a7f19c4b9b3e7bd6ea298fa5efe93 Mon Sep 17 00:00:00 2001 From: Denis Turischev Date: Fri, 19 Feb 2010 11:26:25 +0100 Subject: mfd: Introduce lpc_sch for Intel SCH LPC bridge Intel Poulsbo (SCH) chipset LPC bridge controller contains several functions. Creating and MFD driver for the LPC bridge controller allows simultaneous use of SMBus and GPIO interfaces on the SCH. Signed-off-by: Denis Turischev Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 84a68d2..9b25fe2 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -389,6 +389,15 @@ config MFD_TIMBERDALE The timberdale FPGA can be found on the Intel Atom development board for in-vehicle infontainment, called Russellville. + +config LPC_SCH + tristate "Intel SCH LPC" + depends on PCI + select MFD_CORE + help + LPC bridge function of the Intel SCH provides support for + System Management Bus and General Purpose I/O. + endmenu menu "Multimedia Capabilities Port drivers" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 878cac6..22715ad 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -62,3 +62,4 @@ obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o obj-$(CONFIG_AB4500_CORE) += ab4500-core.o obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o obj-$(CONFIG_PMIC_ADP5520) += adp5520.o +obj-$(CONFIG_LPC_SCH) += lpc_sch.o \ No newline at end of file diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c new file mode 100644 index 0000000..51b2f60 --- /dev/null +++ b/drivers/mfd/lpc_sch.c @@ -0,0 +1,133 @@ +/* + * lpc_sch.c - LPC interface for Intel Poulsbo SCH + * + * LPC bridge function of the Intel SCH contains many other + * functional units, such as Interrupt controllers, Timers, + * Power Management, System Management, GPIO, RTC, and LPC + * Configuration Registers. + * + * Copyright (c) 2010 CompuLab Ltd + * Author: Denis Turischev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define SMBASE 0x40 +#define SMBUS_IO_SIZE 64 + +#define GPIOBASE 0x44 +#define GPIO_IO_SIZE 64 + +static struct resource smbus_sch_resource = { + .flags = IORESOURCE_IO, +}; + + +static struct resource gpio_sch_resource = { + .flags = IORESOURCE_IO, +}; + +static struct mfd_cell lpc_sch_cells[] = { + { + .name = "isch_smbus", + .num_resources = 1, + .resources = &smbus_sch_resource, + }, + { + .name = "sch_gpio", + .num_resources = 1, + .resources = &gpio_sch_resource, + }, +}; + +static struct pci_device_id lpc_sch_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, lpc_sch_ids); + +static int __devinit lpc_sch_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + unsigned int base_addr_cfg; + unsigned short base_addr; + + pci_read_config_dword(dev, SMBASE, &base_addr_cfg); + if (!(base_addr_cfg & (1 << 31))) { + dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n"); + return -ENODEV; + } + base_addr = (unsigned short)base_addr_cfg; + if (base_addr == 0) { + dev_err(&dev->dev, "I/O space for SMBus uninitialized\n"); + return -ENODEV; + } + + smbus_sch_resource.start = base_addr; + smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1; + + pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg); + if (!(base_addr_cfg & (1 << 31))) { + dev_err(&dev->dev, "Decode of the GPIO I/O range disabled\n"); + return -ENODEV; + } + base_addr = (unsigned short)base_addr_cfg; + if (base_addr == 0) { + dev_err(&dev->dev, "I/O space for GPIO uninitialized\n"); + return -ENODEV; + } + + gpio_sch_resource.start = base_addr; + gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1; + + return mfd_add_devices(&dev->dev, -1, + lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 0); +} + +static void __devexit lpc_sch_remove(struct pci_dev *dev) +{ + mfd_remove_devices(&dev->dev); +} + +static struct pci_driver lpc_sch_driver = { + .name = "lpc_sch", + .id_table = lpc_sch_ids, + .probe = lpc_sch_probe, + .remove = __devexit_p(lpc_sch_remove), +}; + +static int __init lpc_sch_init(void) +{ + return pci_register_driver(&lpc_sch_driver); +} + +static void __exit lpc_sch_exit(void) +{ + pci_unregister_driver(&lpc_sch_driver); +} + +module_init(lpc_sch_init); +module_exit(lpc_sch_exit); + +MODULE_AUTHOR("Denis Turischev "); +MODULE_DESCRIPTION("LPC interface for Intel Poulsbo SCH"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From a29aaf55cd6faa75e35abfe00bd3ffc537490485 Mon Sep 17 00:00:00 2001 From: Moiz Sonasath Date: Tue, 16 Feb 2010 18:57:21 -0600 Subject: mfd: Disable TWL4030/5030 I2C1/I2C4 internal pull-ups This patch disables TWL4030/5030 I2C1 adn I2C4(SR) internal pull-up, to use only the external HW resistor >=470 Ohm for the assured functionality in HS mode. While testing the I2C in High Speed mode, it was discovered that without a proper pull-up resistor, there is data corruption during multi-byte transfer. RTC(time_set) test case was used for testing. From the analysis done, it was concluded that ideally we need a pull-up of 1.6k Ohm(recomended) or atleast 470 Ohm or greater for assured performance in HS mode. Signed-off-by: Moiz Sonasath Signed-off-by: Allen Pais Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 942a1e8..7ccc39f 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -958,6 +958,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) int status; unsigned i; struct twl4030_platform_data *pdata = client->dev.platform_data; + u8 temp; if (!pdata) { dev_dbg(&client->dev, "no platform data?\n"); @@ -1025,6 +1026,18 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) goto fail; } + /* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface. + * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0, + * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0. + */ + + if (twl_class_is_4030()) { + twl_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1); + temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \ + I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU); + twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1); + } + status = add_children(pdata, id->driver_data); fail: if (status < 0) diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index 9733e9e..e28d4c0 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -239,6 +239,21 @@ int twl6030_interrupt_mask(u8 bit_mask, u8 offset); /*----------------------------------------------------------------------*/ +/*Interface Bit Register (INTBR) offsets + *(Use TWL_4030_MODULE_INTBR) + */ + +#define REG_GPPUPDCTR1 0x0F + +/*I2C1 and I2C4(SR) SDA/SCL pull-up control bits */ + +#define I2C_SCL_CTRL_PU BIT(0) +#define I2C_SDA_CTRL_PU BIT(2) +#define SR_I2C_SCL_CTRL_PU BIT(4) +#define SR_I2C_SDA_CTRL_PU BIT(6) + +/*----------------------------------------------------------------------*/ + /* * Keypad register offsets (use TWL4030_MODULE_KEYPAD) * ... SIH/interrupt only -- cgit v0.10.2 From fa0d976298b25d090fafc3460c63fee1c8eea854 Mon Sep 17 00:00:00 2001 From: Balaji T K Date: Fri, 19 Feb 2010 12:39:38 +0100 Subject: mfd: Add twl6030 base addr for ID0, ID1, ID2 Add base address for generic slave ID0, ID1, ID2 and introduced one more entry to align RTC module number between twl4030 and twl6030 Signed-off-by: Balaji T K Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 7ccc39f..562cd49 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -198,6 +198,7 @@ /* subchip/slave 3 0x4B - AUDIO */ #define TWL6030_BASEADD_AUDIO 0x0000 #define TWL6030_BASEADD_RSV 0x0000 +#define TWL6030_BASEADD_ZERO 0x0000 /* Few power values */ #define R_CFG_BOOT 0x05 @@ -313,9 +314,11 @@ static struct twl_mapping twl6030_map[] = { { SUB_CHIP_ID1, TWL6030_BASEADD_CHARGER }, { SUB_CHIP_ID1, TWL6030_BASEADD_GASGAUGE }, { SUB_CHIP_ID1, TWL6030_BASEADD_PWM }, - { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, - { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, + { SUB_CHIP_ID0, TWL6030_BASEADD_ZERO }, + { SUB_CHIP_ID1, TWL6030_BASEADD_ZERO }, + { SUB_CHIP_ID2, TWL6030_BASEADD_ZERO }, + { SUB_CHIP_ID2, TWL6030_BASEADD_ZERO }, { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, { SUB_CHIP_ID2, TWL6030_BASEADD_RSV }, diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index e28d4c0..70d4caf 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -80,6 +80,11 @@ #define TWL_MODULE_PM_MASTER TWL4030_MODULE_PM_MASTER #define TWL_MODULE_PM_RECEIVER TWL4030_MODULE_PM_RECEIVER #define TWL_MODULE_RTC TWL4030_MODULE_RTC +#define TWL_MODULE_PWM TWL4030_MODULE_PWM0 + +#define TWL6030_MODULE_ID0 0x0D +#define TWL6030_MODULE_ID1 0x0E +#define TWL6030_MODULE_ID2 0x0F #define GPIO_INTR_OFFSET 0 #define KEYPAD_INTR_OFFSET 1 -- cgit v0.10.2 From a8c39d8deb8341d15fc0eabaa9750f7a1db9d0df Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 17 Feb 2010 16:37:45 +0900 Subject: tmio_mmc: Keep card-detect interrupts enabled On SuperH platforms the SDHI controller does not produce any command IRQs after a completed IO. This leads to card-detect interrupts staying disabled. Do not disable card-detect interrupts on DATA IRQs. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Magnus Damm Signed-off-by: Samuel Ortiz diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 692dc23..dafecfb 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -55,10 +55,8 @@ /* Define some IRQ masks */ /* This is the mask used at reset by the chip */ #define TMIO_MASK_ALL 0x837f031d -#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND | \ - TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) -#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND | \ - TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) +#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND) +#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND) #define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \ TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) #define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) -- cgit v0.10.2 From b741d440a97c376af309e902eeb2f3c5673d2c92 Mon Sep 17 00:00:00 2001 From: Yusuke Goda Date: Wed, 17 Feb 2010 16:37:55 +0900 Subject: tmio_mmc: Add MMC_CAP_MMC_HIGHSPEED support V2 Enable MMC_CAP_XX support in the tmio_mmc driver if pdata->capabilities is set. Signed-off-by: Yusuke Goda Signed-off-by: Magnus Damm Signed-off-by: Samuel Ortiz diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index e22c3fa..e2c0cc9 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -550,6 +550,7 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev) mmc->ops = &tmio_mmc_ops; mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->caps |= pdata->capabilities; mmc->f_max = pdata->hclk; mmc->f_min = mmc->f_max / 512; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index 9cb1834..37d9414 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h @@ -60,6 +60,7 @@ void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state); */ struct tmio_mmc_data { const unsigned int hclk; + unsigned long capabilities; void (*set_pwr)(struct platform_device *host, int state); void (*set_clk_div)(struct platform_device *host, int state); }; -- cgit v0.10.2 From 6d9af5af61a6c30676ef6f56a791d4036c92d249 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 17 Feb 2010 16:38:04 +0900 Subject: tmio_mmc: Use 100ms mmc_detect_change() delay This patch changes the tmio_mmc driver to wait 100ms before checking the card detect status. This type of delay is quite common among mmc drivers, it seems that most hardware platforms need to give the hardware some time to settle before checking card availabilty. Hotplug is half-broken without this patch on the sh7724 Ecovec board. Hot insertion seems ok but eject is never detected without this patch. Signed-off-by: Magnus Damm Signed-off-by: Samuel Ortiz diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index e2c0cc9..7b2376d 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -323,7 +323,7 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid) if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) { ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE); - mmc_detect_change(host->mmc, 0); + mmc_detect_change(host->mmc, msecs_to_jiffies(100)); } /* CRC and other errors */ -- cgit v0.10.2 From 707f0b2fbc65876e8abd94d26d8d0620600c05d4 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 17 Feb 2010 16:38:14 +0900 Subject: tmio_mmc: Remove const from platform data V3 Remove const from the tmio-mmc platform data hclk V3. This change makes it possible to remove the type cast from the sh_mobile_sdhi driver which is using the clock framework to get the clock rate. Signed-off-by: Magnus Damm Signed-off-by: Samuel Ortiz diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index 37d9414..c3f7dff 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h @@ -59,7 +59,7 @@ void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state); * data for the MMC controller */ struct tmio_mmc_data { - const unsigned int hclk; + unsigned int hclk; unsigned long capabilities; void (*set_pwr)(struct platform_device *host, int state); void (*set_clk_div)(struct platform_device *host, int state); -- cgit v0.10.2 From 7ee422dc6e947fcdc153246d47f26ae0b7cf083d Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 17 Feb 2010 16:38:23 +0900 Subject: tmio_mmc: Balance cell enable()/disable() calls This patch adds cell->disable() calls to the tmio-mmc probe() error handling and the remove() function. Signed-off-by: Magnus Damm Signed-off-by: Samuel Ortiz diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 7b2376d..b2b577f 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -569,14 +569,14 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev) if (ret >= 0) host->irq = ret; else - goto unmap_ctl; + goto cell_disable; disable_mmc_irqs(host, TMIO_MASK_ALL); ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED | IRQF_TRIGGER_FALLING, dev_name(&dev->dev), host); if (ret) - goto unmap_ctl; + goto cell_disable; mmc_add_host(mmc); @@ -588,6 +588,9 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev) return 0; +cell_disable: + if (cell->disable) + cell->disable(dev); unmap_ctl: iounmap(host->ctl); host_free: @@ -598,6 +601,7 @@ out: static int __devexit tmio_mmc_remove(struct platform_device *dev) { + struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; struct mmc_host *mmc = platform_get_drvdata(dev); platform_set_drvdata(dev, NULL); @@ -606,6 +610,8 @@ static int __devexit tmio_mmc_remove(struct platform_device *dev) struct tmio_mmc_host *host = mmc_priv(mmc); mmc_remove_host(mmc); free_irq(host->irq, host); + if (cell->disable) + cell->disable(dev); iounmap(host->ctl); mmc_free_host(mmc); } -- cgit v0.10.2 From 3383d23d86791503559cb87837491af37469d9e5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 17 Feb 2010 18:04:35 +0000 Subject: gpiolib: Actually set output state in wm831x_gpio_direction_output() wm831x_gpio_direction_output() ignored the state passed into it. Signed-off-by: Mark Brown Cc: stable@kernel.org Signed-off-by: Samuel Ortiz diff --git a/drivers/gpio/wm831x-gpio.c b/drivers/gpio/wm831x-gpio.c index b4468b6..c5a00f7 100644 --- a/drivers/gpio/wm831x-gpio.c +++ b/drivers/gpio/wm831x-gpio.c @@ -60,23 +60,31 @@ static int wm831x_gpio_get(struct gpio_chip *chip, unsigned offset) return 0; } -static int wm831x_gpio_direction_out(struct gpio_chip *chip, - unsigned offset, int value) +static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip); struct wm831x *wm831x = wm831x_gpio->wm831x; - return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset, - WM831X_GPN_DIR | WM831X_GPN_TRI, 0); + wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, 1 << offset, + value << offset); } -static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +static int wm831x_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value) { struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip); struct wm831x *wm831x = wm831x_gpio->wm831x; + int ret; - wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, 1 << offset, - value << offset); + ret = wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset, + WM831X_GPN_DIR | WM831X_GPN_TRI, 0); + if (ret < 0) + return ret; + + /* Can only set GPIO state once it's in output mode */ + wm831x_gpio_set(chip, offset, value); + + return 0; } static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -- cgit v0.10.2 From 6b8274fafeec9b112cee5b6ced5f9189957c889f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 17 Feb 2010 18:45:24 +0000 Subject: gpiolib: Correct debugfs display of WM831x GPIO inversion Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz diff --git a/drivers/gpio/wm831x-gpio.c b/drivers/gpio/wm831x-gpio.c index c5a00f7..2554180 100644 --- a/drivers/gpio/wm831x-gpio.c +++ b/drivers/gpio/wm831x-gpio.c @@ -176,7 +176,7 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) wm831x_gpio_get(chip, i) ? "high" : "low", pull, powerdomain, - reg & WM831X_GPN_POL ? " inverted" : "", + reg & WM831X_GPN_POL ? "" : " inverted", reg & WM831X_GPN_OD ? "open-drain" : "CMOS", reg & WM831X_GPN_TRI ? " tristated" : "", reg); -- cgit v0.10.2 From f92e8f8144243a3651b2e350b706ea2d04931f8c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 17 Feb 2010 18:45:25 +0000 Subject: mfd: Add WM831x revision B support Revision B of the WM831x devices changes the sense of the tristate bit for GPIO configuration, inverting it to become an enable instead. Take account of this in the gpiolib driver. A current sink regulation status bit has also been added in revision B, add a flag indicating if it's present but don't use it yet. This revision also adds an interrupt on key up for the ON pin event which the existing code is able to take advantage of. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz diff --git a/drivers/gpio/wm831x-gpio.c b/drivers/gpio/wm831x-gpio.c index 2554180..5b8dc09 100644 --- a/drivers/gpio/wm831x-gpio.c +++ b/drivers/gpio/wm831x-gpio.c @@ -38,10 +38,13 @@ static int wm831x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip); struct wm831x *wm831x = wm831x_gpio->wm831x; + int val = WM831X_GPN_DIR; + + if (wm831x->has_gpio_ena) + val |= WM831X_GPN_TRI; return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset, - WM831X_GPN_DIR | WM831X_GPN_TRI, - WM831X_GPN_DIR); + WM831X_GPN_DIR | WM831X_GPN_TRI, val); } static int wm831x_gpio_get(struct gpio_chip *chip, unsigned offset) @@ -74,10 +77,14 @@ static int wm831x_gpio_direction_out(struct gpio_chip *chip, { struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip); struct wm831x *wm831x = wm831x_gpio->wm831x; + int val = 0; int ret; + if (wm831x->has_gpio_ena) + val |= WM831X_GPN_TRI; + ret = wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset, - WM831X_GPN_DIR | WM831X_GPN_TRI, 0); + WM831X_GPN_DIR | WM831X_GPN_TRI, val); if (ret < 0) return ret; @@ -103,7 +110,7 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) { struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip); struct wm831x *wm831x = wm831x_gpio->wm831x; - int i; + int i, tristated; for (i = 0; i < chip->ngpio; i++) { int gpio = i + chip->base; @@ -170,6 +177,10 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) break; } + tristated = reg & WM831X_GPN_TRI; + if (wm831x->has_gpio_ena) + tristated = !tristated; + seq_printf(s, " %s %s %s %s%s\n" " %s%s (0x%4x)\n", reg & WM831X_GPN_DIR ? "in" : "out", @@ -178,7 +189,7 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) powerdomain, reg & WM831X_GPN_POL ? "" : " inverted", reg & WM831X_GPN_OD ? "open-drain" : "CMOS", - reg & WM831X_GPN_TRI ? " tristated" : "", + tristated ? " tristated" : "", reg); } } diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 4b2021a..c428d9f 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -1449,18 +1449,33 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) case WM8310: parent = WM8310; wm831x->num_gpio = 16; + if (rev > 0) { + wm831x->has_gpio_ena = 1; + wm831x->has_cs_sts = 1; + } + dev_info(wm831x->dev, "WM8310 revision %c\n", 'A' + rev); break; case WM8311: parent = WM8311; wm831x->num_gpio = 16; + if (rev > 0) { + wm831x->has_gpio_ena = 1; + wm831x->has_cs_sts = 1; + } + dev_info(wm831x->dev, "WM8311 revision %c\n", 'A' + rev); break; case WM8312: parent = WM8312; wm831x->num_gpio = 16; + if (rev > 0) { + wm831x->has_gpio_ena = 1; + wm831x->has_cs_sts = 1; + } + dev_info(wm831x->dev, "WM8312 revision %c\n", 'A' + rev); break; diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h index 5184b79..53580b5 100644 --- a/include/linux/mfd/wm831x/core.h +++ b/include/linux/mfd/wm831x/core.h @@ -254,6 +254,10 @@ struct wm831x { int irq_masks_cur[WM831X_NUM_IRQ_REGS]; /* Currently active value */ int irq_masks_cache[WM831X_NUM_IRQ_REGS]; /* Cached hardware value */ + /* Chip revision based flags */ + unsigned has_gpio_ena:1; /* Has GPIO enable bit */ + unsigned has_cs_sts:1; /* Has current sink status bit */ + int num_gpio; struct mutex auxadc_lock; diff --git a/include/linux/mfd/wm831x/gpio.h b/include/linux/mfd/wm831x/gpio.h index 2835614..9b163c5 100644 --- a/include/linux/mfd/wm831x/gpio.h +++ b/include/linux/mfd/wm831x/gpio.h @@ -41,6 +41,10 @@ #define WM831X_GPN_OD_MASK 0x0200 /* GPN_OD */ #define WM831X_GPN_OD_SHIFT 9 /* GPN_OD */ #define WM831X_GPN_OD_WIDTH 1 /* GPN_OD */ +#define WM831X_GPN_ENA 0x0080 /* GPN_ENA */ +#define WM831X_GPN_ENA_MASK 0x0080 /* GPN_ENA */ +#define WM831X_GPN_ENA_SHIFT 7 /* GPN_ENA */ +#define WM831X_GPN_ENA_WIDTH 1 /* GPN_ENA */ #define WM831X_GPN_TRI 0x0080 /* GPN_TRI */ #define WM831X_GPN_TRI_MASK 0x0080 /* GPN_TRI */ #define WM831X_GPN_TRI_SHIFT 7 /* GPN_TRI */ -- cgit v0.10.2 From 1bca748cccec1c7f30b4424882de965100744432 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 17 Feb 2010 18:45:26 +0000 Subject: gpiolib: Force wm831x GPIOs into GPIO mode when requested This is the chip default but it's possible the bootloader or OTP will have been configured to a different mode (eg, to provide feedback during startup). Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz diff --git a/drivers/gpio/wm831x-gpio.c b/drivers/gpio/wm831x-gpio.c index 5b8dc09..d09021f 100644 --- a/drivers/gpio/wm831x-gpio.c +++ b/drivers/gpio/wm831x-gpio.c @@ -44,7 +44,8 @@ static int wm831x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) val |= WM831X_GPN_TRI; return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset, - WM831X_GPN_DIR | WM831X_GPN_TRI, val); + WM831X_GPN_DIR | WM831X_GPN_TRI | + WM831X_GPN_FN_MASK, val); } static int wm831x_gpio_get(struct gpio_chip *chip, unsigned offset) @@ -84,7 +85,8 @@ static int wm831x_gpio_direction_out(struct gpio_chip *chip, val |= WM831X_GPN_TRI; ret = wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset, - WM831X_GPN_DIR | WM831X_GPN_TRI, val); + WM831X_GPN_DIR | WM831X_GPN_TRI | + WM831X_GPN_FN_MASK, val); if (ret < 0) return ret; -- cgit v0.10.2 From 3c49e810507c9d0659b8aa61f7f91aecda428ee3 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 22 Feb 2010 13:37:09 +0900 Subject: mfd: sh_mobile_sdhi MMC_CAP_MMC_HIGHSPEED support Add MMC_CAP_MMC_HIGHSPEED support to the sh_mobile_sdhi driver. Also, remove type cast and FIXME comment. Signed-off-by: Magnus Damm Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c index 03efae8..468fd36 100644 --- a/drivers/mfd/sh_mobile_sdhi.c +++ b/drivers/mfd/sh_mobile_sdhi.c @@ -21,7 +21,7 @@ #include #include #include - +#include #include #include #include @@ -95,9 +95,9 @@ static int __init sh_mobile_sdhi_probe(struct platform_device *pdev) clk_enable(priv->clk); - /* FIXME: silly const unsigned int hclk */ - *(unsigned int *)&priv->mmc_data.hclk = clk_get_rate(priv->clk); + priv->mmc_data.hclk = clk_get_rate(priv->clk); priv->mmc_data.set_pwr = sh_mobile_sdhi_set_pwr; + priv->mmc_data.capabilities = MMC_CAP_MMC_HIGHSPEED; memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc)); priv->cell_mmc.driver_data = &priv->mmc_data; -- cgit v0.10.2 From 3d8ca8c0b9fe42d005360e255fbf7a6f8580ef87 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 22 Feb 2010 13:40:59 +0900 Subject: mfd/mmc: SDHI Kconfig update Enable the sh_mobile_sdhi mfd driver on SH-Mobile ARM processors. While at it, make CONFIG_TMIO_MMC depend on CONFIG_MFD_SH_MOBILE_SDHI. Signed-off-by: Magnus Damm Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 9b25fe2..951fa9b 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -47,7 +47,7 @@ config MFD_ASIC3 config MFD_SH_MOBILE_SDHI bool "Support for SuperH Mobile SDHI" - depends on SUPERH + depends on SUPERH || ARCH_SHMOBILE select MFD_CORE ---help--- This driver supports the SDHI hardware block found in many diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 7b431bb..2e13b94 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -365,7 +365,7 @@ config MMC_SDRICOH_CS config MMC_TMIO tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support" - depends on MFD_TMIO || MFD_ASIC3 || SUPERH + depends on MFD_TMIO || MFD_ASIC3 || MFD_SH_MOBILE_SDHI help This provides support for the SD/MMC cell found in TC6393XB, T7L66XB and also HTC ASIC3 -- cgit v0.10.2 From 11a441ce82d6ffecfd39b324024de0cd630b36c1 Mon Sep 17 00:00:00 2001 From: Mike Turquette Date: Mon, 22 Feb 2010 11:16:30 -0600 Subject: mfd: Introduce remove_script function for twl4030 New function twl4030_remove_script(u8 flags) takes a script type as defined in twl.h and prevents any script already loaded in that position from running. This is accomplished by programming SEQ_ADD_* to 0x3f, the END_OF_SCRIPT value, where SEQ_ADD_* is determined by flags. (Future) users of this function include OMAP board files for machines facing a race condition between sleep and warm reset. Signed-off-by: Mike Turquette Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 5b045ff..7efa878 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -461,6 +461,56 @@ out: return err; } +int twl4030_remove_script(u8 flags) +{ + int err = 0; + + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_1, + R_PROTECT_KEY); + if (err) { + pr_err("twl4030: unable to unlock PROTECT_KEY\n"); + return err; + } + + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, R_KEY_2, + R_PROTECT_KEY); + if (err) { + pr_err("twl4030: unable to unlock PROTECT_KEY\n"); + return err; + } + + if (flags & TWL4030_WRST_SCRIPT) { + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT, + R_SEQ_ADD_WARM); + if (err) + return err; + } + if (flags & TWL4030_WAKEUP12_SCRIPT) { + if (err) + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT, + R_SEQ_ADD_S2A12); + return err; + } + if (flags & TWL4030_WAKEUP3_SCRIPT) { + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT, + R_SEQ_ADD_S2A3); + if (err) + return err; + } + if (flags & TWL4030_SLEEP_SCRIPT) { + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT, + R_SEQ_ADD_A2S); + if (err) + return err; + } + + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY); + if (err) + pr_err("TWL4030 Unable to relock registers\n"); + + return err; +} + void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) { int err = 0; diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index 70d4caf..fb6784e 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -550,6 +550,7 @@ struct twl4030_power_data { }; extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts); +extern int twl4030_remove_script(u8 flags); struct twl4030_codec_audio_data { unsigned int audio_mclk; -- cgit v0.10.2 From d19663ac61a6e36eec655d3c84a106686ebddd2c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 23 Feb 2010 11:08:05 +0000 Subject: mfd: Use completion interrupt for WM835x AUXADC Use the completion interrupt generated by the device rather than polling for conversions to complete. As a backup we still check the state of the AUXADC if we don't get a completion, mostly for systems that don't have the WM8350 interrupt infrastructure hooked up. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c index 9a970bd..bd75807 100644 --- a/drivers/mfd/wm8350-core.c +++ b/drivers/mfd/wm8350-core.c @@ -339,7 +339,6 @@ EXPORT_SYMBOL_GPL(wm8350_reg_unlock); int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref) { u16 reg, result = 0; - int tries = 5; if (channel < WM8350_AUXADC_AUX1 || channel > WM8350_AUXADC_TEMP) return -EINVAL; @@ -363,12 +362,13 @@ int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref) reg |= 1 << channel | WM8350_AUXADC_POLL; wm8350_reg_write(wm8350, WM8350_DIGITISER_CONTROL_1, reg); - do { - schedule_timeout_interruptible(1); - reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1); - } while ((reg & WM8350_AUXADC_POLL) && --tries); + /* We ignore the result of the completion and just check for a + * conversion result, allowing us to soldier on if the IRQ + * infrastructure is not set up for the chip. */ + wait_for_completion_timeout(&wm8350->auxadc_done, msecs_to_jiffies(5)); - if (!tries) + reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1); + if (reg & WM8350_AUXADC_POLL) dev_err(wm8350->dev, "adc chn %d read timeout\n", channel); else result = wm8350_reg_read(wm8350, @@ -385,6 +385,15 @@ int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref) } EXPORT_SYMBOL_GPL(wm8350_read_auxadc); +static irqreturn_t wm8350_auxadc_irq(int irq, void *irq_data) +{ + struct wm8350 *wm8350 = irq_data; + + complete(&wm8350->auxadc_done); + + return IRQ_HANDLED; +} + /* * Cache is always host endian. */ @@ -682,11 +691,22 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq, } mutex_init(&wm8350->auxadc_mutex); + init_completion(&wm8350->auxadc_done); ret = wm8350_irq_init(wm8350, irq, pdata); if (ret < 0) goto err; + if (wm8350->irq_base) { + ret = request_threaded_irq(wm8350->irq_base + + WM8350_IRQ_AUXADC_DATARDY, + NULL, wm8350_auxadc_irq, 0, + "auxadc", wm8350); + if (ret < 0) + dev_warn(wm8350->dev, + "Failed to request AUXADC IRQ: %d\n", ret); + } + if (pdata && pdata->init) { ret = pdata->init(wm8350); if (ret != 0) { @@ -736,6 +756,9 @@ void wm8350_device_exit(struct wm8350 *wm8350) platform_device_unregister(wm8350->gpio.pdev); platform_device_unregister(wm8350->codec.pdev); + if (wm8350->irq_base) + free_irq(wm8350->irq_base + WM8350_IRQ_AUXADC_DATARDY, wm8350); + wm8350_irq_exit(wm8350); kfree(wm8350->reg_cache); diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h index fae08aa..98fcc97 100644 --- a/include/linux/mfd/wm8350/core.h +++ b/include/linux/mfd/wm8350/core.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -621,6 +622,7 @@ struct wm8350 { u16 *reg_cache; struct mutex auxadc_mutex; + struct completion auxadc_done; /* Interrupt handling */ struct mutex irq_lock; -- cgit v0.10.2 From 473fe73650b9f92114edbedfbb616561c1a0026c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 23 Feb 2010 11:08:06 +0000 Subject: mfd: Use completion interrupt for WM831x AUXADC Use the completion interrupt generated by the device rather than polling for conversions to complete. As a backup we still check the status of the AUXADC if we don't get a completion, mostly for systems that don't have the WM831x interrupt infrastructure hooked up. Also reduce the timeout for completion of conversions to 5ms from the previous 10ms, the lower timeout should be sufficient. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index c428d9f..07101e9 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -321,7 +321,6 @@ EXPORT_SYMBOL_GPL(wm831x_set_bits); */ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) { - int tries = 10; int ret, src; mutex_lock(&wm831x->auxadc_lock); @@ -349,13 +348,14 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input) goto disable; } - do { - msleep(1); + /* Ignore the result to allow us to soldier on without IRQ hookup */ + wait_for_completion_timeout(&wm831x->auxadc_done, msecs_to_jiffies(5)); - ret = wm831x_reg_read(wm831x, WM831X_AUXADC_CONTROL); - if (ret < 0) - ret = WM831X_AUX_CVT_ENA; - } while ((ret & WM831X_AUX_CVT_ENA) && --tries); + ret = wm831x_reg_read(wm831x, WM831X_AUXADC_CONTROL); + if (ret < 0) { + dev_err(wm831x->dev, "AUXADC status read failed: %d\n", ret); + goto disable; + } if (ret & WM831X_AUX_CVT_ENA) { dev_err(wm831x->dev, "Timed out reading AUXADC\n"); @@ -390,6 +390,15 @@ out: } EXPORT_SYMBOL_GPL(wm831x_auxadc_read); +static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data) +{ + struct wm831x *wm831x = irq_data; + + complete(&wm831x->auxadc_done); + + return IRQ_HANDLED; +} + /** * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC * @@ -1411,6 +1420,7 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) mutex_init(&wm831x->io_lock); mutex_init(&wm831x->key_lock); mutex_init(&wm831x->auxadc_lock); + init_completion(&wm831x->auxadc_done); dev_set_drvdata(wm831x->dev, wm831x); ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID); @@ -1523,6 +1533,16 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) if (ret != 0) goto err; + if (wm831x->irq_base) { + ret = request_threaded_irq(wm831x->irq_base + + WM831X_IRQ_AUXADC_DATA, + NULL, wm831x_auxadc_irq, 0, + "auxadc", wm831x); + if (ret < 0) + dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n", + ret); + } + /* The core device is up, instantiate the subdevices. */ switch (parent) { case WM8310: @@ -1593,6 +1613,8 @@ static void wm831x_device_exit(struct wm831x *wm831x) { wm831x_otp_exit(wm831x); mfd_remove_devices(wm831x->dev); + if (wm831x->irq_base) + free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x); wm831x_irq_exit(wm831x); kfree(wm831x); } diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h index 53580b5..5915f6e 100644 --- a/include/linux/mfd/wm831x/core.h +++ b/include/linux/mfd/wm831x/core.h @@ -15,6 +15,7 @@ #ifndef __MFD_WM831X_CORE_H__ #define __MFD_WM831X_CORE_H__ +#include #include /* @@ -261,6 +262,7 @@ struct wm831x { int num_gpio; struct mutex auxadc_lock; + struct completion auxadc_done; /* The WM831x has a security key blocking access to certain * registers. The mutex is taken by the accessors for locking -- cgit v0.10.2 From fd46a0064af171c90664e5b7165c0c9f94478a87 Mon Sep 17 00:00:00 2001 From: Denis Turischev Date: Mon, 1 Mar 2010 18:59:55 +0200 Subject: i2c: convert i2c-isch to platform_device Convert i2c-isch to platform_device for the lpc mfd core to add it at probe time. Signed-off-by: Denis Turischev Signed-off-by: Samuel Ortiz diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 4cc3807..f22eff1 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -105,7 +105,7 @@ config I2C_I801 config I2C_ISCH tristate "Intel SCH SMBus 1.0" - depends on PCI + select LPC_SCH help Say Y here if you want to use SMBus controller on the Intel SCH based systems. diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c index 69c22f7..ddc258e 100644 --- a/drivers/i2c/busses/i2c-isch.c +++ b/drivers/i2c/busses/i2c-isch.c @@ -27,7 +27,7 @@ */ #include -#include +#include #include #include #include @@ -46,12 +46,6 @@ #define SMBHSTDAT1 (7 + sch_smba) #define SMBBLKDAT (0x20 + sch_smba) -/* count for request_region */ -#define SMBIOSIZE 64 - -/* PCI Address Constants */ -#define SMBBA_SCH 0x40 - /* Other settings */ #define MAX_TIMEOUT 500 @@ -63,7 +57,6 @@ #define SCH_BLOCK_DATA 0x05 static unsigned short sch_smba; -static struct pci_driver sch_driver; static struct i2c_adapter sch_adapter; /* @@ -256,37 +249,23 @@ static struct i2c_adapter sch_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id sch_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, sch_ids); - -static int __devinit sch_probe(struct pci_dev *dev, - const struct pci_device_id *id) +static int __devinit smbus_sch_probe(struct platform_device *dev) { + struct resource *res; int retval; - unsigned int smba; - pci_read_config_dword(dev, SMBBA_SCH, &smba); - if (!(smba & (1 << 31))) { - dev_err(&dev->dev, "SMBus I/O space disabled!\n"); - return -ENODEV; - } + res = platform_get_resource(dev, IORESOURCE_IO, 0); + if (!res) + return -EBUSY; - sch_smba = (unsigned short)smba; - if (sch_smba == 0) { - dev_err(&dev->dev, "SMBus base address uninitialized!\n"); - return -ENODEV; - } - if (acpi_check_region(sch_smba, SMBIOSIZE, sch_driver.name)) - return -ENODEV; - if (!request_region(sch_smba, SMBIOSIZE, sch_driver.name)) { + if (!request_region(res->start, resource_size(res), dev->name)) { dev_err(&dev->dev, "SMBus region 0x%x already in use!\n", sch_smba); return -EBUSY; } + + sch_smba = res->start; + dev_dbg(&dev->dev, "SMBA = 0x%X\n", sch_smba); /* set up the sysfs linkage to our parent device */ @@ -298,37 +277,43 @@ static int __devinit sch_probe(struct pci_dev *dev, retval = i2c_add_adapter(&sch_adapter); if (retval) { dev_err(&dev->dev, "Couldn't register adapter!\n"); - release_region(sch_smba, SMBIOSIZE); + release_region(res->start, resource_size(res)); sch_smba = 0; } return retval; } -static void __devexit sch_remove(struct pci_dev *dev) +static int __devexit smbus_sch_remove(struct platform_device *pdev) { + struct resource *res; if (sch_smba) { i2c_del_adapter(&sch_adapter); - release_region(sch_smba, SMBIOSIZE); + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + release_region(res->start, resource_size(res)); sch_smba = 0; } + + return 0; } -static struct pci_driver sch_driver = { - .name = "isch_smbus", - .id_table = sch_ids, - .probe = sch_probe, - .remove = __devexit_p(sch_remove), +static struct platform_driver smbus_sch_driver = { + .driver = { + .name = "isch_smbus", + .owner = THIS_MODULE, + }, + .probe = smbus_sch_probe, + .remove = __devexit_p(smbus_sch_remove), }; static int __init i2c_sch_init(void) { - return pci_register_driver(&sch_driver); + return platform_driver_register(&smbus_sch_driver); } static void __exit i2c_sch_exit(void) { - pci_unregister_driver(&sch_driver); + platform_driver_unregister(&smbus_sch_driver); } MODULE_AUTHOR("Jacob Pan "); @@ -337,3 +322,4 @@ MODULE_LICENSE("GPL"); module_init(i2c_sch_init); module_exit(i2c_sch_exit); +MODULE_ALIAS("platform:isch_smbus"); -- cgit v0.10.2 From be9b06b2d80fe661491138c6993f944babb26260 Mon Sep 17 00:00:00 2001 From: Denis Turischev Date: Tue, 2 Mar 2010 10:48:55 +0100 Subject: gpio: add Intel SCH GPIO controller driver Signed-off-by: Denis Turischev Signed-off-by: Samuel Ortiz diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index f42cb31..60cb363 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -94,6 +94,22 @@ config GPIO_VR41XX help Say yes here to support the NEC VR4100 series General-purpose I/O Uint +config GPIO_SCH + tristate "Intel SCH GPIO" + depends on GPIOLIB + select LPC_SCH + help + Say yes here to support GPIO interface on Intel Poulsbo SCH. + The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are + powered by the core power rail and are turned off during sleep + modes (S3 and higher). The remaining four GPIOs are powered by + the Intel SCH suspend power supply. These GPIOs remain + active during S3. The suspend powered GPIOs can be used to wake the + system from the Suspend-to-RAM state. + + This driver can also be built as a module. If so, the module + will be called sch-gpio. + comment "I2C GPIO expanders:" config GPIO_MAX7300 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 594bb70..10f3f8d 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -27,3 +27,4 @@ obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o obj-$(CONFIG_GPIO_WM8350) += wm8350-gpiolib.o obj-$(CONFIG_GPIO_WM8994) += wm8994-gpio.o +obj-$(CONFIG_GPIO_SCH) += sch_gpio.o \ No newline at end of file diff --git a/drivers/gpio/sch_gpio.c b/drivers/gpio/sch_gpio.c new file mode 100644 index 0000000..761071a --- /dev/null +++ b/drivers/gpio/sch_gpio.c @@ -0,0 +1,282 @@ +/* + * sch_gpio.c - GPIO interface for Intel Poulsbo SCH + * + * Copyright (c) 2010 CompuLab Ltd + * Author: Denis Turischev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +static DEFINE_SPINLOCK(gpio_lock); + +#define CGEN (0x00) +#define CGIO (0x04) +#define CGLV (0x08) + +#define RGEN (0x20) +#define RGIO (0x24) +#define RGLV (0x28) + +static unsigned short gpio_ba; + +static int sch_gpio_core_direction_in(struct gpio_chip *gc, unsigned gpio_num) +{ + u8 curr_dirs; + unsigned short offset, bit; + + spin_lock(&gpio_lock); + + offset = CGIO + gpio_num / 8; + bit = gpio_num % 8; + + curr_dirs = inb(gpio_ba + offset); + + if (!(curr_dirs & (1 << bit))) + outb(curr_dirs | (1 << bit), gpio_ba + offset); + + spin_unlock(&gpio_lock); + return 0; +} + +static int sch_gpio_core_get(struct gpio_chip *gc, unsigned gpio_num) +{ + int res; + unsigned short offset, bit; + + offset = CGLV + gpio_num / 8; + bit = gpio_num % 8; + + res = !!(inb(gpio_ba + offset) & (1 << bit)); + return res; +} + +static void sch_gpio_core_set(struct gpio_chip *gc, unsigned gpio_num, int val) +{ + u8 curr_vals; + unsigned short offset, bit; + + spin_lock(&gpio_lock); + + offset = CGLV + gpio_num / 8; + bit = gpio_num % 8; + + curr_vals = inb(gpio_ba + offset); + + if (val) + outb(curr_vals | (1 << bit), gpio_ba + offset); + else + outb((curr_vals & ~(1 << bit)), gpio_ba + offset); + spin_unlock(&gpio_lock); +} + +static int sch_gpio_core_direction_out(struct gpio_chip *gc, + unsigned gpio_num, int val) +{ + u8 curr_dirs; + unsigned short offset, bit; + + sch_gpio_core_set(gc, gpio_num, val); + + spin_lock(&gpio_lock); + + offset = CGIO + gpio_num / 8; + bit = gpio_num % 8; + + curr_dirs = inb(gpio_ba + offset); + if (curr_dirs & (1 << bit)) + outb(curr_dirs & ~(1 << bit), gpio_ba + offset); + + spin_unlock(&gpio_lock); + return 0; +} + +static struct gpio_chip sch_gpio_core = { + .label = "sch_gpio_core", + .owner = THIS_MODULE, + .direction_input = sch_gpio_core_direction_in, + .get = sch_gpio_core_get, + .direction_output = sch_gpio_core_direction_out, + .set = sch_gpio_core_set, +}; + +static int sch_gpio_resume_direction_in(struct gpio_chip *gc, + unsigned gpio_num) +{ + u8 curr_dirs; + + spin_lock(&gpio_lock); + + curr_dirs = inb(gpio_ba + RGIO); + + if (!(curr_dirs & (1 << gpio_num))) + outb(curr_dirs | (1 << gpio_num) , gpio_ba + RGIO); + + spin_unlock(&gpio_lock); + return 0; +} + +static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num) +{ + return !!(inb(gpio_ba + RGLV) & (1 << gpio_num)); +} + +static void sch_gpio_resume_set(struct gpio_chip *gc, + unsigned gpio_num, int val) +{ + u8 curr_vals; + + spin_lock(&gpio_lock); + + curr_vals = inb(gpio_ba + RGLV); + + if (val) + outb(curr_vals | (1 << gpio_num), gpio_ba + RGLV); + else + outb((curr_vals & ~(1 << gpio_num)), gpio_ba + RGLV); + + spin_unlock(&gpio_lock); +} + +static int sch_gpio_resume_direction_out(struct gpio_chip *gc, + unsigned gpio_num, int val) +{ + u8 curr_dirs; + + sch_gpio_resume_set(gc, gpio_num, val); + + spin_lock(&gpio_lock); + + curr_dirs = inb(gpio_ba + RGIO); + if (curr_dirs & (1 << gpio_num)) + outb(curr_dirs & ~(1 << gpio_num), gpio_ba + RGIO); + + spin_unlock(&gpio_lock); + return 0; +} + +static struct gpio_chip sch_gpio_resume = { + .label = "sch_gpio_resume", + .owner = THIS_MODULE, + .direction_input = sch_gpio_resume_direction_in, + .get = sch_gpio_resume_get, + .direction_output = sch_gpio_resume_direction_out, + .set = sch_gpio_resume_set, +}; + +static int __devinit sch_gpio_probe(struct platform_device *pdev) +{ + struct resource *res; + int err; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) + return -EBUSY; + + if (!request_region(res->start, resource_size(res), pdev->name)) + return -EBUSY; + + gpio_ba = res->start; + + sch_gpio_core.base = 0; + sch_gpio_core.ngpio = 10; + sch_gpio_core.dev = &pdev->dev; + + sch_gpio_resume.base = 10; + sch_gpio_resume.ngpio = 4; + sch_gpio_resume.dev = &pdev->dev; + + err = gpiochip_add(&sch_gpio_core); + if (err < 0) + goto err_sch_gpio_core; + + err = gpiochip_add(&sch_gpio_resume); + if (err < 0) + goto err_sch_gpio_resume; + + /* + * GPIO[6:0] enabled by default + * GPIO7 is configured by the CMC as SLPIOVR + * Enable GPIO[9:8] core powered gpios explicitly + */ + outb(0x3, gpio_ba + CGEN + 1); + /* + * SUS_GPIO[2:0] enabled by default + * Enable SUS_GPIO3 resume powered gpio explicitly + */ + outb(0x8, gpio_ba + RGEN); + + return 0; + +err_sch_gpio_resume: + gpiochip_remove(&sch_gpio_core); + +err_sch_gpio_core: + release_region(res->start, resource_size(res)); + gpio_ba = 0; + + return err; +} + +static int __devexit sch_gpio_remove(struct platform_device *pdev) +{ + struct resource *res; + if (gpio_ba) { + gpiochip_remove(&sch_gpio_core); + gpiochip_remove(&sch_gpio_resume); + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + + release_region(res->start, resource_size(res)); + gpio_ba = 0; + } + + return 0; +} + +static struct platform_driver sch_gpio_driver = { + .driver = { + .name = "sch_gpio", + .owner = THIS_MODULE, + }, + .probe = sch_gpio_probe, + .remove = __devexit_p(sch_gpio_remove), +}; + +static int __init sch_gpio_init(void) +{ + return platform_driver_register(&sch_gpio_driver); +} + +static void __exit sch_gpio_exit(void) +{ + platform_driver_unregister(&sch_gpio_driver); +} + +module_init(sch_gpio_init); +module_exit(sch_gpio_exit); + +MODULE_AUTHOR("Denis Turischev "); +MODULE_DESCRIPTION("GPIO interface for Intel Poulsbo SCH"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sch_gpio"); -- cgit v0.10.2 From 8e7aafe41be2a7cd5c181ed68876e9ec55ccdba7 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 5 Mar 2010 17:14:01 +0100 Subject: gpio: Fix sch_gpio warning We need to check for gpiochip_remove() errors. Signed-off-by: Samuel Ortiz diff --git a/drivers/gpio/sch_gpio.c b/drivers/gpio/sch_gpio.c index 761071a..5835213 100644 --- a/drivers/gpio/sch_gpio.c +++ b/drivers/gpio/sch_gpio.c @@ -229,7 +229,10 @@ static int __devinit sch_gpio_probe(struct platform_device *pdev) return 0; err_sch_gpio_resume: - gpiochip_remove(&sch_gpio_core); + err = gpiochip_remove(&sch_gpio_core); + if (err) + dev_err(&pdev->dev, "%s failed, %d\n", + "gpiochip_remove()", err); err_sch_gpio_core: release_region(res->start, resource_size(res)); @@ -242,13 +245,23 @@ static int __devexit sch_gpio_remove(struct platform_device *pdev) { struct resource *res; if (gpio_ba) { - gpiochip_remove(&sch_gpio_core); - gpiochip_remove(&sch_gpio_resume); + int err; + + err = gpiochip_remove(&sch_gpio_core); + if (err) + dev_err(&pdev->dev, "%s failed, %d\n", + "gpiochip_remove()", err); + err = gpiochip_remove(&sch_gpio_resume); + if (err) + dev_err(&pdev->dev, "%s failed, %d\n", + "gpiochip_remove()", err); res = platform_get_resource(pdev, IORESOURCE_IO, 0); release_region(res->start, resource_size(res)); gpio_ba = 0; + + return err; } return 0; -- cgit v0.10.2 From 860fb8c134ebca9be8bc2ddd2b13e19ac10c192e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 5 Mar 2010 09:43:06 -0800 Subject: mfd: Fix lpc_sch related depends/selects, fix build error LPC_SCH is selected by GPI_SCH and I2C_ISCH, even when PCI is not enabled, but LPC_SCH depends on PCI, so make GPI_SCH and I2C_ISCH also depend on PCI. Those 2 selects also need to select what LPC_SCH selects, since kconfig does not follow selects. Signed-off-by: Randy Dunlap Cc: Denis Turischev Signed-off-by: Samuel Ortiz diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 60cb363..fee678f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -96,7 +96,8 @@ config GPIO_VR41XX config GPIO_SCH tristate "Intel SCH GPIO" - depends on GPIOLIB + depends on GPIOLIB && PCI + select MFD_CORE select LPC_SCH help Say yes here to support GPIO interface on Intel Poulsbo SCH. diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index f22eff1..4cd1ff7 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -105,6 +105,8 @@ config I2C_I801 config I2C_ISCH tristate "Intel SCH SMBus 1.0" + depends on PCI + select MFD_CORE select LPC_SCH help Say Y here if you want to use SMBus controller on the Intel SCH -- cgit v0.10.2 From 2c08583c6a6b4c5f5dea4cb0931eca82af7db6fe Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Sat, 6 Mar 2010 14:36:38 +0100 Subject: mfd: Fix ucb1x00 build failure for collie_defconfig This patch fixes a build failure[1], by adding the missing semaphore.h include References: [1] http://kisskb.ellerman.id.au/kisskb/buildresult/2234322/ Signed-off-by: Peter Huewe Signed-off-by: Samuel Ortiz diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index 252b741..b281217 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include diff --git a/include/linux/mfd/ucb1x00.h b/include/linux/mfd/ucb1x00.h index aa9c378..4321f04 100644 --- a/include/linux/mfd/ucb1x00.h +++ b/include/linux/mfd/ucb1x00.h @@ -12,6 +12,7 @@ #include #include +#include #define UCB_IO_DATA 0x00 #define UCB_IO_DIR 0x01 -- cgit v0.10.2