| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Arizona core driver | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright 2012 Wolfson Microelectronics plc | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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 <linux/delay.h>
 | 
					
						
							| 
									
										
										
										
											2012-07-09 00:31:36 +02:00
										 |  |  | #include <linux/err.h>
 | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | #include <linux/gpio.h>
 | 
					
						
							|  |  |  | #include <linux/interrupt.h>
 | 
					
						
							|  |  |  | #include <linux/mfd/core.h>
 | 
					
						
							|  |  |  | #include <linux/module.h>
 | 
					
						
							| 
									
										
										
										
											2013-03-25 00:11:27 +00:00
										 |  |  | #include <linux/of.h>
 | 
					
						
							|  |  |  | #include <linux/of_device.h>
 | 
					
						
							|  |  |  | #include <linux/of_gpio.h>
 | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | #include <linux/pm_runtime.h>
 | 
					
						
							|  |  |  | #include <linux/regmap.h>
 | 
					
						
							|  |  |  | #include <linux/regulator/consumer.h>
 | 
					
						
							| 
									
										
										
										
											2013-04-23 19:44:16 +01:00
										 |  |  | #include <linux/regulator/machine.h>
 | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | #include <linux/slab.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/mfd/arizona/core.h>
 | 
					
						
							|  |  |  | #include <linux/mfd/arizona/registers.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "arizona.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char *wm5102_core_supplies[] = { | 
					
						
							|  |  |  | 	"AVDD", | 
					
						
							|  |  |  | 	"DBVDD1", | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int arizona_clk32k_enable(struct arizona *arizona) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mutex_lock(&arizona->clk_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	arizona->clk32k_ref++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-19 14:47:47 +01:00
										 |  |  | 	if (arizona->clk32k_ref == 1) { | 
					
						
							|  |  |  | 		switch (arizona->pdata.clk32k_src) { | 
					
						
							|  |  |  | 		case ARIZONA_32KZ_MCLK1: | 
					
						
							|  |  |  | 			ret = pm_runtime_get_sync(arizona->dev); | 
					
						
							|  |  |  | 			if (ret != 0) | 
					
						
							|  |  |  | 				goto out; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 		ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, | 
					
						
							|  |  |  | 					 ARIZONA_CLK_32K_ENA, | 
					
						
							|  |  |  | 					 ARIZONA_CLK_32K_ENA); | 
					
						
							| 
									
										
										
										
											2013-03-19 14:47:47 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-19 14:47:47 +01:00
										 |  |  | out: | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	if (ret != 0) | 
					
						
							|  |  |  | 		arizona->clk32k_ref--; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mutex_unlock(&arizona->clk_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(arizona_clk32k_enable); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int arizona_clk32k_disable(struct arizona *arizona) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mutex_lock(&arizona->clk_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BUG_ON(arizona->clk32k_ref <= 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	arizona->clk32k_ref--; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-19 14:47:47 +01:00
										 |  |  | 	if (arizona->clk32k_ref == 0) { | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 		regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, | 
					
						
							|  |  |  | 				   ARIZONA_CLK_32K_ENA, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-19 14:47:47 +01:00
										 |  |  | 		switch (arizona->pdata.clk32k_src) { | 
					
						
							|  |  |  | 		case ARIZONA_32KZ_MCLK1: | 
					
						
							|  |  |  | 			pm_runtime_put_sync(arizona->dev); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	mutex_unlock(&arizona->clk_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(arizona_clk32k_disable); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static irqreturn_t arizona_clkgen_err(int irq, void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct arizona *arizona = data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_err(arizona->dev, "CLKGEN error\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return IRQ_HANDLED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static irqreturn_t arizona_underclocked(int irq, void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct arizona *arizona = data; | 
					
						
							|  |  |  | 	unsigned int val; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_8, | 
					
						
							|  |  |  | 			  &val); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Failed to read underclock status: %d\n", | 
					
						
							|  |  |  | 			ret); | 
					
						
							|  |  |  | 		return IRQ_NONE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (val & ARIZONA_AIF3_UNDERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "AIF3 underclocked\n"); | 
					
						
							|  |  |  | 	if (val & ARIZONA_AIF2_UNDERCLOCKED_STS) | 
					
						
							| 
									
										
										
										
											2012-11-20 13:46:20 +09:00
										 |  |  | 		dev_err(arizona->dev, "AIF2 underclocked\n"); | 
					
						
							|  |  |  | 	if (val & ARIZONA_AIF1_UNDERCLOCKED_STS) | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 		dev_err(arizona->dev, "AIF1 underclocked\n"); | 
					
						
							|  |  |  | 	if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "ISRC2 underclocked\n"); | 
					
						
							|  |  |  | 	if (val & ARIZONA_ISRC1_UNDERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "ISRC1 underclocked\n"); | 
					
						
							|  |  |  | 	if (val & ARIZONA_FX_UNDERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "FX underclocked\n"); | 
					
						
							|  |  |  | 	if (val & ARIZONA_ASRC_UNDERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "ASRC underclocked\n"); | 
					
						
							|  |  |  | 	if (val & ARIZONA_DAC_UNDERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "DAC underclocked\n"); | 
					
						
							|  |  |  | 	if (val & ARIZONA_ADC_UNDERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "ADC underclocked\n"); | 
					
						
							|  |  |  | 	if (val & ARIZONA_MIXER_UNDERCLOCKED_STS) | 
					
						
							| 
									
										
										
										
											2013-01-28 00:32:53 +08:00
										 |  |  | 		dev_err(arizona->dev, "Mixer dropped sample\n"); | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return IRQ_HANDLED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static irqreturn_t arizona_overclocked(int irq, void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct arizona *arizona = data; | 
					
						
							|  |  |  | 	unsigned int val[2]; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	ret = regmap_bulk_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_6, | 
					
						
							|  |  |  | 			       &val[0], 2); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Failed to read overclock status: %d\n", | 
					
						
							|  |  |  | 			ret); | 
					
						
							|  |  |  | 		return IRQ_NONE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (val[0] & ARIZONA_PWM_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "PWM overclocked\n"); | 
					
						
							|  |  |  | 	if (val[0] & ARIZONA_FX_CORE_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "FX core overclocked\n"); | 
					
						
							|  |  |  | 	if (val[0] & ARIZONA_DAC_SYS_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "DAC SYS overclocked\n"); | 
					
						
							|  |  |  | 	if (val[0] & ARIZONA_DAC_WARP_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "DAC WARP overclocked\n"); | 
					
						
							|  |  |  | 	if (val[0] & ARIZONA_ADC_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "ADC overclocked\n"); | 
					
						
							|  |  |  | 	if (val[0] & ARIZONA_MIXER_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Mixer overclocked\n"); | 
					
						
							|  |  |  | 	if (val[0] & ARIZONA_AIF3_SYNC_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "AIF3 overclocked\n"); | 
					
						
							|  |  |  | 	if (val[0] & ARIZONA_AIF2_SYNC_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "AIF2 overclocked\n"); | 
					
						
							|  |  |  | 	if (val[0] & ARIZONA_AIF1_SYNC_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "AIF1 overclocked\n"); | 
					
						
							|  |  |  | 	if (val[0] & ARIZONA_PAD_CTRL_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Pad control overclocked\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (val[1] & ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Slimbus subsystem overclocked\n"); | 
					
						
							|  |  |  | 	if (val[1] & ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Slimbus async overclocked\n"); | 
					
						
							|  |  |  | 	if (val[1] & ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Slimbus sync overclocked\n"); | 
					
						
							|  |  |  | 	if (val[1] & ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "ASRC async system overclocked\n"); | 
					
						
							|  |  |  | 	if (val[1] & ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "ASRC async WARP overclocked\n"); | 
					
						
							|  |  |  | 	if (val[1] & ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "ASRC sync system overclocked\n"); | 
					
						
							|  |  |  | 	if (val[1] & ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "ASRC sync WARP overclocked\n"); | 
					
						
							|  |  |  | 	if (val[1] & ARIZONA_ADSP2_1_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "DSP1 overclocked\n"); | 
					
						
							|  |  |  | 	if (val[1] & ARIZONA_ISRC2_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "ISRC2 overclocked\n"); | 
					
						
							|  |  |  | 	if (val[1] & ARIZONA_ISRC1_OVERCLOCKED_STS) | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "ISRC1 overclocked\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return IRQ_HANDLED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-26 17:38:45 +00:00
										 |  |  | static int arizona_poll_reg(struct arizona *arizona, | 
					
						
							|  |  |  | 			    int timeout, unsigned int reg, | 
					
						
							|  |  |  | 			    unsigned int mask, unsigned int target) | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-03-26 17:38:45 +00:00
										 |  |  | 	unsigned int val = 0; | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	int ret, i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-26 17:38:45 +00:00
										 |  |  | 	for (i = 0; i < timeout; i++) { | 
					
						
							|  |  |  | 		ret = regmap_read(arizona->regmap, reg, &val); | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 		if (ret != 0) { | 
					
						
							| 
									
										
										
										
											2013-03-26 17:38:45 +00:00
										 |  |  | 			dev_err(arizona->dev, "Failed to read reg %u: %d\n", | 
					
						
							|  |  |  | 				reg, ret); | 
					
						
							| 
									
										
										
										
											2012-07-05 20:35:30 +01:00
										 |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-26 17:38:45 +00:00
										 |  |  | 		if ((val & mask) == target) | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		msleep(1); | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-26 17:38:45 +00:00
										 |  |  | 	dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val); | 
					
						
							|  |  |  | 	return -ETIMEDOUT; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int arizona_wait_for_boot(struct arizona *arizona) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * We can't use an interrupt as we need to runtime resume to do so, | 
					
						
							|  |  |  | 	 * we won't race with the interrupt handler as it'll be blocked on | 
					
						
							|  |  |  | 	 * runtime resume. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5, | 
					
						
							|  |  |  | 			       ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!ret) | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 		regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, | 
					
						
							|  |  |  | 			     ARIZONA_BOOT_DONE_STS); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pm_runtime_mark_last_busy(arizona->dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-26 17:38:45 +00:00
										 |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-26 18:46:15 +00:00
										 |  |  | static int arizona_apply_hardware_patch(struct arizona* arizona) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int fll, sysclk; | 
					
						
							|  |  |  | 	int ret, err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Cache existing FLL and SYSCLK settings */ | 
					
						
							|  |  |  | 	ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &fll); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Failed to cache FLL settings: %d\n", | 
					
						
							|  |  |  | 			ret); | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &sysclk); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n", | 
					
						
							|  |  |  | 			ret); | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Start up SYSCLK using the FLL in free running mode */ | 
					
						
							|  |  |  | 	ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, | 
					
						
							|  |  |  | 			ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(arizona->dev, | 
					
						
							|  |  |  | 			"Failed to start FLL in freerunning mode: %d\n", | 
					
						
							|  |  |  | 			ret); | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5, | 
					
						
							|  |  |  | 			       ARIZONA_FLL1_CLOCK_OK_STS, | 
					
						
							|  |  |  | 			       ARIZONA_FLL1_CLOCK_OK_STS); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		ret = -ETIMEDOUT; | 
					
						
							|  |  |  | 		goto err_fll; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret); | 
					
						
							|  |  |  | 		goto err_fll; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Start the write sequencer and wait for it to finish */ | 
					
						
							|  |  |  | 	ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, | 
					
						
							|  |  |  | 			ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Failed to start write sequencer: %d\n", | 
					
						
							|  |  |  | 			ret); | 
					
						
							|  |  |  | 		goto err_sysclk; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1, | 
					
						
							|  |  |  | 			       ARIZONA_WSEQ_BUSY, 0); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, | 
					
						
							|  |  |  | 				ARIZONA_WSEQ_ABORT); | 
					
						
							|  |  |  | 		ret = -ETIMEDOUT; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | err_sysclk: | 
					
						
							|  |  |  | 	err = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, sysclk); | 
					
						
							|  |  |  | 	if (err != 0) { | 
					
						
							|  |  |  | 		dev_err(arizona->dev, | 
					
						
							|  |  |  | 			"Failed to re-apply old SYSCLK settings: %d\n", | 
					
						
							|  |  |  | 			err); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | err_fll: | 
					
						
							|  |  |  | 	err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, fll); | 
					
						
							|  |  |  | 	if (err != 0) { | 
					
						
							|  |  |  | 		dev_err(arizona->dev, | 
					
						
							|  |  |  | 			"Failed to re-apply old FLL settings: %d\n", | 
					
						
							|  |  |  | 			err); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ret != 0) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | #ifdef CONFIG_PM_RUNTIME
 | 
					
						
							|  |  |  | static int arizona_runtime_resume(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct arizona *arizona = dev_get_drvdata(dev); | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 17:09:12 +01:00
										 |  |  | 	dev_dbg(arizona->dev, "Leaving AoD mode\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-09 00:31:36 +02:00
										 |  |  | 	ret = regulator_enable(arizona->dcvdd); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Failed to enable DCVDD: %d\n", ret); | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	regcache_cache_only(arizona->regmap, false); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-26 18:01:49 +00:00
										 |  |  | 	switch (arizona->type) { | 
					
						
							|  |  |  | 	case WM5102: | 
					
						
							| 
									
										
										
										
											2013-04-23 19:44:16 +01:00
										 |  |  | 		if (arizona->external_dcvdd) { | 
					
						
							|  |  |  | 			ret = regmap_update_bits(arizona->regmap, | 
					
						
							|  |  |  | 						 ARIZONA_ISOLATION_CONTROL, | 
					
						
							|  |  |  | 						 ARIZONA_ISOLATE_DCVDD1, 0); | 
					
						
							|  |  |  | 			if (ret != 0) { | 
					
						
							|  |  |  | 				dev_err(arizona->dev, | 
					
						
							|  |  |  | 					"Failed to connect DCVDD: %d\n", ret); | 
					
						
							|  |  |  | 				goto err; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-26 18:01:49 +00:00
										 |  |  | 		ret = wm5102_patch(arizona); | 
					
						
							|  |  |  | 		if (ret != 0) { | 
					
						
							|  |  |  | 			dev_err(arizona->dev, "Failed to apply patch: %d\n", | 
					
						
							|  |  |  | 				ret); | 
					
						
							|  |  |  | 			goto err; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-03-26 18:46:15 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		ret = arizona_apply_hardware_patch(arizona); | 
					
						
							|  |  |  | 		if (ret != 0) { | 
					
						
							|  |  |  | 			dev_err(arizona->dev, | 
					
						
							|  |  |  | 				"Failed to apply hardware patch: %d\n", | 
					
						
							|  |  |  | 				ret); | 
					
						
							|  |  |  | 			goto err; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2013-03-27 09:49:40 +00:00
										 |  |  | 		ret = arizona_wait_for_boot(arizona); | 
					
						
							|  |  |  | 		if (ret != 0) { | 
					
						
							|  |  |  | 			goto err; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-23 19:44:16 +01:00
										 |  |  | 		if (arizona->external_dcvdd) { | 
					
						
							|  |  |  | 			ret = regmap_update_bits(arizona->regmap, | 
					
						
							|  |  |  | 						 ARIZONA_ISOLATION_CONTROL, | 
					
						
							|  |  |  | 						 ARIZONA_ISOLATE_DCVDD1, 0); | 
					
						
							|  |  |  | 			if (ret != 0) { | 
					
						
							|  |  |  | 				dev_err(arizona->dev, | 
					
						
							|  |  |  | 					"Failed to connect DCVDD: %d\n", ret); | 
					
						
							|  |  |  | 				goto err; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-03-26 18:46:15 +00:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2013-03-26 18:01:49 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-26 18:01:49 +00:00
										 |  |  | 	switch (arizona->type) { | 
					
						
							|  |  |  | 	case WM5102: | 
					
						
							|  |  |  | 		ret = wm5102_patch(arizona); | 
					
						
							|  |  |  | 		if (ret != 0) { | 
					
						
							|  |  |  | 			dev_err(arizona->dev, "Failed to apply patch: %d\n", | 
					
						
							|  |  |  | 				ret); | 
					
						
							|  |  |  | 			goto err; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-04 17:16:12 +00:00
										 |  |  | 	ret = regcache_sync(arizona->regmap); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Failed to restore register cache\n"); | 
					
						
							| 
									
										
										
										
											2013-01-14 15:50:38 +09:00
										 |  |  | 		goto err; | 
					
						
							| 
									
										
										
										
											2013-01-04 17:16:12 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2013-01-14 15:50:38 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | err: | 
					
						
							|  |  |  | 	regcache_cache_only(arizona->regmap, true); | 
					
						
							|  |  |  | 	regulator_disable(arizona->dcvdd); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int arizona_runtime_suspend(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct arizona *arizona = dev_get_drvdata(dev); | 
					
						
							| 
									
										
										
										
											2013-04-23 19:44:16 +01:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-20 17:09:12 +01:00
										 |  |  | 	dev_dbg(arizona->dev, "Entering AoD mode\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-23 19:44:16 +01:00
										 |  |  | 	if (arizona->external_dcvdd) { | 
					
						
							|  |  |  | 		ret = regmap_update_bits(arizona->regmap, | 
					
						
							|  |  |  | 					 ARIZONA_ISOLATION_CONTROL, | 
					
						
							|  |  |  | 					 ARIZONA_ISOLATE_DCVDD1, | 
					
						
							|  |  |  | 					 ARIZONA_ISOLATE_DCVDD1); | 
					
						
							|  |  |  | 		if (ret != 0) { | 
					
						
							|  |  |  | 			dev_err(arizona->dev, "Failed to isolate DCVDD: %d\n", | 
					
						
							|  |  |  | 				ret); | 
					
						
							|  |  |  | 			return ret; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-09 00:31:36 +02:00
										 |  |  | 	regcache_cache_only(arizona->regmap, true); | 
					
						
							|  |  |  | 	regcache_mark_dirty(arizona->regmap); | 
					
						
							| 
									
										
										
										
											2013-08-06 17:18:35 +01:00
										 |  |  | 	regulator_disable(arizona->dcvdd); | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-27 12:07:32 +08:00
										 |  |  | #ifdef CONFIG_PM_SLEEP
 | 
					
						
							| 
									
										
										
										
											2013-04-10 12:40:26 +01:00
										 |  |  | static int arizona_suspend(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct arizona *arizona = dev_get_drvdata(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(arizona->dev, "Suspend, disabling IRQ\n"); | 
					
						
							|  |  |  | 	disable_irq(arizona->irq); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int arizona_suspend_late(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct arizona *arizona = dev_get_drvdata(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(arizona->dev, "Late suspend, reenabling IRQ\n"); | 
					
						
							|  |  |  | 	enable_irq(arizona->irq); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-27 12:07:32 +08:00
										 |  |  | static int arizona_resume_noirq(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct arizona *arizona = dev_get_drvdata(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(arizona->dev, "Early resume, disabling IRQ\n"); | 
					
						
							|  |  |  | 	disable_irq(arizona->irq); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int arizona_resume(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct arizona *arizona = dev_get_drvdata(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n"); | 
					
						
							|  |  |  | 	enable_irq(arizona->irq); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | const struct dev_pm_ops arizona_pm_ops = { | 
					
						
							|  |  |  | 	SET_RUNTIME_PM_OPS(arizona_runtime_suspend, | 
					
						
							|  |  |  | 			   arizona_runtime_resume, | 
					
						
							|  |  |  | 			   NULL) | 
					
						
							| 
									
										
										
										
											2013-04-10 12:40:26 +01:00
										 |  |  | 	SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume) | 
					
						
							| 
									
										
										
										
											2013-01-27 12:07:32 +08:00
										 |  |  | #ifdef CONFIG_PM_SLEEP
 | 
					
						
							| 
									
										
										
										
											2013-04-10 12:40:26 +01:00
										 |  |  | 	.suspend_late = arizona_suspend_late, | 
					
						
							| 
									
										
										
										
											2013-01-27 12:07:32 +08:00
										 |  |  | 	.resume_noirq = arizona_resume_noirq, | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(arizona_pm_ops); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-25 00:11:27 +00:00
										 |  |  | #ifdef CONFIG_OF
 | 
					
						
							|  |  |  | int arizona_of_get_type(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const struct of_device_id *id = of_match_device(arizona_of_match, dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (id) | 
					
						
							|  |  |  | 		return (int)id->data; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(arizona_of_get_type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int arizona_of_get_core_pdata(struct arizona *arizona) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret, i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	arizona->pdata.reset = of_get_named_gpio(arizona->dev->of_node, | 
					
						
							|  |  |  | 						 "wlf,reset", 0); | 
					
						
							|  |  |  | 	if (arizona->pdata.reset < 0) | 
					
						
							|  |  |  | 		arizona->pdata.reset = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	arizona->pdata.ldoena = of_get_named_gpio(arizona->dev->of_node, | 
					
						
							|  |  |  | 						  "wlf,ldoena", 0); | 
					
						
							|  |  |  | 	if (arizona->pdata.ldoena < 0) | 
					
						
							|  |  |  | 		arizona->pdata.ldoena = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = of_property_read_u32_array(arizona->dev->of_node, | 
					
						
							|  |  |  | 					 "wlf,gpio-defaults", | 
					
						
							|  |  |  | 					 arizona->pdata.gpio_defaults, | 
					
						
							|  |  |  | 					 ARRAY_SIZE(arizona->pdata.gpio_defaults)); | 
					
						
							|  |  |  | 	if (ret >= 0) { | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * All values are literal except out of range values | 
					
						
							|  |  |  | 		 * which are chip default, translate into platform | 
					
						
							|  |  |  | 		 * data which uses 0 as chip default and out of range | 
					
						
							|  |  |  | 		 * as zero. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { | 
					
						
							|  |  |  | 			if (arizona->pdata.gpio_defaults[i] > 0xffff) | 
					
						
							|  |  |  | 				arizona->pdata.gpio_defaults[i] = 0; | 
					
						
							| 
									
										
										
										
											2013-10-03 16:16:01 +01:00
										 |  |  | 			else if (arizona->pdata.gpio_defaults[i] == 0) | 
					
						
							| 
									
										
										
										
											2013-03-25 00:11:27 +00:00
										 |  |  | 				arizona->pdata.gpio_defaults[i] = 0x10000; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n", | 
					
						
							|  |  |  | 			ret); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const struct of_device_id arizona_of_match[] = { | 
					
						
							|  |  |  | 	{ .compatible = "wlf,wm5102", .data = (void *)WM5102 }, | 
					
						
							|  |  |  | 	{ .compatible = "wlf,wm5110", .data = (void *)WM5110 }, | 
					
						
							| 
									
										
										
										
											2013-06-13 09:43:29 +01:00
										 |  |  | 	{ .compatible = "wlf,wm8997", .data = (void *)WM8997 }, | 
					
						
							| 
									
										
										
										
											2013-03-25 00:11:27 +00:00
										 |  |  | 	{}, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(arizona_of_match); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | static inline int arizona_of_get_core_pdata(struct arizona *arizona) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-18 14:33:06 +01:00
										 |  |  | static const struct mfd_cell early_devs[] = { | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	{ .name = "arizona-ldo1" }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-15 20:14:22 +01:00
										 |  |  | static const char *wm5102_supplies[] = { | 
					
						
							|  |  |  | 	"DBVDD2", | 
					
						
							|  |  |  | 	"DBVDD3", | 
					
						
							|  |  |  | 	"CPVDD", | 
					
						
							|  |  |  | 	"SPKVDDL", | 
					
						
							|  |  |  | 	"SPKVDDR", | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-18 14:33:06 +01:00
										 |  |  | static const struct mfd_cell wm5102_devs[] = { | 
					
						
							| 
									
										
										
										
											2012-12-20 15:38:03 +00:00
										 |  |  | 	{ .name = "arizona-micsupp" }, | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	{ .name = "arizona-extcon" }, | 
					
						
							|  |  |  | 	{ .name = "arizona-gpio" }, | 
					
						
							| 
									
										
										
										
											2012-11-27 17:36:38 +00:00
										 |  |  | 	{ .name = "arizona-haptics" }, | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	{ .name = "arizona-pwm" }, | 
					
						
							| 
									
										
										
										
											2013-10-15 20:14:22 +01:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		.name = "wm5102-codec", | 
					
						
							|  |  |  | 		.parent_supplies = wm5102_supplies, | 
					
						
							|  |  |  | 		.num_parent_supplies = ARRAY_SIZE(wm5102_supplies), | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-18 14:33:06 +01:00
										 |  |  | static const struct mfd_cell wm5110_devs[] = { | 
					
						
							| 
									
										
										
										
											2012-12-20 15:38:03 +00:00
										 |  |  | 	{ .name = "arizona-micsupp" }, | 
					
						
							| 
									
										
										
										
											2012-07-10 12:37:58 +01:00
										 |  |  | 	{ .name = "arizona-extcon" }, | 
					
						
							|  |  |  | 	{ .name = "arizona-gpio" }, | 
					
						
							| 
									
										
										
										
											2012-11-27 17:36:38 +00:00
										 |  |  | 	{ .name = "arizona-haptics" }, | 
					
						
							| 
									
										
										
										
											2012-07-10 12:37:58 +01:00
										 |  |  | 	{ .name = "arizona-pwm" }, | 
					
						
							| 
									
										
										
										
											2013-10-15 20:14:22 +01:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		.name = "wm5110-codec", | 
					
						
							|  |  |  | 		.parent_supplies = wm5102_supplies, | 
					
						
							|  |  |  | 		.num_parent_supplies = ARRAY_SIZE(wm5102_supplies), | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char *wm8997_supplies[] = { | 
					
						
							|  |  |  | 	"DBVDD2", | 
					
						
							|  |  |  | 	"CPVDD", | 
					
						
							|  |  |  | 	"SPKVDD", | 
					
						
							| 
									
										
										
										
											2012-07-10 12:37:58 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-18 14:33:06 +01:00
										 |  |  | static const struct mfd_cell wm8997_devs[] = { | 
					
						
							| 
									
										
										
										
											2013-06-13 09:43:29 +01:00
										 |  |  | 	{ .name = "arizona-micsupp" }, | 
					
						
							|  |  |  | 	{ .name = "arizona-extcon" }, | 
					
						
							|  |  |  | 	{ .name = "arizona-gpio" }, | 
					
						
							|  |  |  | 	{ .name = "arizona-haptics" }, | 
					
						
							|  |  |  | 	{ .name = "arizona-pwm" }, | 
					
						
							| 
									
										
										
										
											2013-10-15 20:14:22 +01:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		.name = "wm8997-codec", | 
					
						
							|  |  |  | 		.parent_supplies = wm8997_supplies, | 
					
						
							|  |  |  | 		.num_parent_supplies = ARRAY_SIZE(wm8997_supplies), | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2013-06-13 09:43:29 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-19 13:23:04 -05:00
										 |  |  | int arizona_dev_init(struct arizona *arizona) | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = arizona->dev; | 
					
						
							|  |  |  | 	const char *type_name; | 
					
						
							|  |  |  | 	unsigned int reg, val; | 
					
						
							| 
									
										
										
										
											2012-12-02 11:41:46 +09:00
										 |  |  | 	int (*apply_patch)(struct arizona *) = NULL; | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	int ret, i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_set_drvdata(arizona->dev, arizona); | 
					
						
							|  |  |  | 	mutex_init(&arizona->clk_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (dev_get_platdata(arizona->dev)) | 
					
						
							|  |  |  | 		memcpy(&arizona->pdata, dev_get_platdata(arizona->dev), | 
					
						
							|  |  |  | 		       sizeof(arizona->pdata)); | 
					
						
							| 
									
										
										
										
											2013-09-27 14:25:55 +01:00
										 |  |  | 	else | 
					
						
							|  |  |  | 		arizona_of_get_core_pdata(arizona); | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	regcache_cache_only(arizona->regmap, true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (arizona->type) { | 
					
						
							|  |  |  | 	case WM5102: | 
					
						
							| 
									
										
										
										
											2012-07-10 12:37:58 +01:00
										 |  |  | 	case WM5110: | 
					
						
							| 
									
										
										
										
											2013-06-13 09:43:29 +01:00
										 |  |  | 	case WM8997: | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 		for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++) | 
					
						
							|  |  |  | 			arizona->core_supplies[i].supply | 
					
						
							|  |  |  | 				= wm5102_core_supplies[i]; | 
					
						
							|  |  |  | 		arizona->num_core_supplies = ARRAY_SIZE(wm5102_core_supplies); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Unknown device type %d\n", | 
					
						
							|  |  |  | 			arizona->type); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = mfd_add_devices(arizona->dev, -1, early_devs, | 
					
						
							| 
									
										
										
										
											2012-09-11 15:16:36 +08:00
										 |  |  | 			      ARRAY_SIZE(early_devs), NULL, 0, NULL); | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(dev, "Failed to add early children: %d\n", ret); | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = devm_regulator_bulk_get(dev, arizona->num_core_supplies, | 
					
						
							|  |  |  | 				      arizona->core_supplies); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(dev, "Failed to request core supplies: %d\n", | 
					
						
							|  |  |  | 			ret); | 
					
						
							|  |  |  | 		goto err_early; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-09 00:31:36 +02:00
										 |  |  | 	arizona->dcvdd = devm_regulator_get(arizona->dev, "DCVDD"); | 
					
						
							|  |  |  | 	if (IS_ERR(arizona->dcvdd)) { | 
					
						
							|  |  |  | 		ret = PTR_ERR(arizona->dcvdd); | 
					
						
							|  |  |  | 		dev_err(dev, "Failed to request DCVDD: %d\n", ret); | 
					
						
							|  |  |  | 		goto err_early; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-26 12:15:26 +00:00
										 |  |  | 	if (arizona->pdata.reset) { | 
					
						
							|  |  |  | 		/* Start out with /RESET low to put the chip into reset */ | 
					
						
							|  |  |  | 		ret = gpio_request_one(arizona->pdata.reset, | 
					
						
							|  |  |  | 				       GPIOF_DIR_OUT | GPIOF_INIT_LOW, | 
					
						
							|  |  |  | 				       "arizona /RESET"); | 
					
						
							|  |  |  | 		if (ret != 0) { | 
					
						
							|  |  |  | 			dev_err(dev, "Failed to request /RESET: %d\n", ret); | 
					
						
							|  |  |  | 			goto err_early; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	ret = regulator_bulk_enable(arizona->num_core_supplies, | 
					
						
							|  |  |  | 				    arizona->core_supplies); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(dev, "Failed to enable core supplies: %d\n", | 
					
						
							|  |  |  | 			ret); | 
					
						
							|  |  |  | 		goto err_early; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-09 00:31:36 +02:00
										 |  |  | 	ret = regulator_enable(arizona->dcvdd); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(dev, "Failed to enable DCVDD: %d\n", ret); | 
					
						
							|  |  |  | 		goto err_enable; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-03 12:53:37 +01:00
										 |  |  | 	if (arizona->pdata.reset) { | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 		gpio_set_value_cansleep(arizona->pdata.reset, 1); | 
					
						
							| 
									
										
										
										
											2013-04-03 12:53:37 +01:00
										 |  |  | 		msleep(1); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	regcache_cache_only(arizona->regmap, false); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-09 16:04:35 +01:00
										 |  |  | 	/* Verify that this is a chip we know about */ | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(dev, "Failed to read ID register: %d\n", ret); | 
					
						
							| 
									
										
										
										
											2012-07-09 00:31:36 +02:00
										 |  |  | 		goto err_reset; | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (reg) { | 
					
						
							|  |  |  | 	case 0x5102: | 
					
						
							| 
									
										
										
										
											2012-07-10 12:37:58 +01:00
										 |  |  | 	case 0x5110: | 
					
						
							| 
									
										
										
										
											2013-06-13 09:43:29 +01:00
										 |  |  | 	case 0x8997: | 
					
						
							| 
									
										
										
										
											2012-07-10 12:37:58 +01:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2013-04-09 16:04:35 +01:00
										 |  |  | 		dev_err(arizona->dev, "Unknown device ID: %x\n", reg); | 
					
						
							| 
									
										
										
										
											2012-07-09 00:31:36 +02:00
										 |  |  | 		goto err_reset; | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* If we have a /RESET GPIO we'll already be reset */ | 
					
						
							|  |  |  | 	if (!arizona->pdata.reset) { | 
					
						
							| 
									
										
										
										
											2012-11-20 14:49:10 +09:00
										 |  |  | 		regcache_mark_dirty(arizona->regmap); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 		ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0); | 
					
						
							|  |  |  | 		if (ret != 0) { | 
					
						
							|  |  |  | 			dev_err(dev, "Failed to reset device: %d\n", ret); | 
					
						
							| 
									
										
										
										
											2012-07-09 00:31:36 +02:00
										 |  |  | 			goto err_reset; | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-11-20 14:49:10 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-03 12:53:37 +01:00
										 |  |  | 		msleep(1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-20 14:49:10 +09:00
										 |  |  | 		ret = regcache_sync(arizona->regmap); | 
					
						
							|  |  |  | 		if (ret != 0) { | 
					
						
							|  |  |  | 			dev_err(dev, "Failed to sync device: %d\n", ret); | 
					
						
							|  |  |  | 			goto err_reset; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-09 16:04:35 +01:00
										 |  |  | 	/* Ensure device startup is complete */ | 
					
						
							| 
									
										
										
										
											2013-04-03 09:45:29 +01:00
										 |  |  | 	switch (arizona->type) { | 
					
						
							|  |  |  | 	case WM5102: | 
					
						
							|  |  |  | 		ret = regmap_read(arizona->regmap, 0x19, &val); | 
					
						
							|  |  |  | 		if (ret != 0) | 
					
						
							|  |  |  | 			dev_err(dev, | 
					
						
							|  |  |  | 				"Failed to check write sequencer state: %d\n", | 
					
						
							|  |  |  | 				ret); | 
					
						
							|  |  |  | 		else if (val & 0x01) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		/* Fall through */ | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		ret = arizona_wait_for_boot(arizona); | 
					
						
							|  |  |  | 		if (ret != 0) { | 
					
						
							|  |  |  | 			dev_err(arizona->dev, | 
					
						
							|  |  |  | 				"Device failed initial boot: %d\n", ret); | 
					
						
							|  |  |  | 			goto err_reset; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2012-07-09 11:56:43 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-09 16:04:35 +01:00
										 |  |  | 	/* Read the device ID information & do device specific stuff */ | 
					
						
							|  |  |  | 	ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(dev, "Failed to read ID register: %d\n", ret); | 
					
						
							|  |  |  | 		goto err_reset; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION, | 
					
						
							|  |  |  | 			  &arizona->rev); | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(dev, "Failed to read revision register: %d\n", ret); | 
					
						
							|  |  |  | 		goto err_reset; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	arizona->rev &= ARIZONA_DEVICE_REVISION_MASK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (reg) { | 
					
						
							|  |  |  | #ifdef CONFIG_MFD_WM5102
 | 
					
						
							|  |  |  | 	case 0x5102: | 
					
						
							|  |  |  | 		type_name = "WM5102"; | 
					
						
							|  |  |  | 		if (arizona->type != WM5102) { | 
					
						
							|  |  |  | 			dev_err(arizona->dev, "WM5102 registered as %d\n", | 
					
						
							|  |  |  | 				arizona->type); | 
					
						
							|  |  |  | 			arizona->type = WM5102; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		apply_patch = wm5102_patch; | 
					
						
							|  |  |  | 		arizona->rev &= 0x7; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #ifdef CONFIG_MFD_WM5110
 | 
					
						
							|  |  |  | 	case 0x5110: | 
					
						
							|  |  |  | 		type_name = "WM5110"; | 
					
						
							|  |  |  | 		if (arizona->type != WM5110) { | 
					
						
							|  |  |  | 			dev_err(arizona->dev, "WM5110 registered as %d\n", | 
					
						
							|  |  |  | 				arizona->type); | 
					
						
							|  |  |  | 			arizona->type = WM5110; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		apply_patch = wm5110_patch; | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2013-06-13 09:43:29 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | #ifdef CONFIG_MFD_WM8997
 | 
					
						
							|  |  |  | 	case 0x8997: | 
					
						
							|  |  |  | 		type_name = "WM8997"; | 
					
						
							|  |  |  | 		if (arizona->type != WM8997) { | 
					
						
							|  |  |  | 			dev_err(arizona->dev, "WM8997 registered as %d\n", | 
					
						
							|  |  |  | 				arizona->type); | 
					
						
							|  |  |  | 			arizona->type = WM8997; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		apply_patch = wm8997_patch; | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2013-04-09 16:04:35 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Unknown device ID %x\n", reg); | 
					
						
							|  |  |  | 		goto err_reset; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-02 11:41:46 +09:00
										 |  |  | 	if (apply_patch) { | 
					
						
							|  |  |  | 		ret = apply_patch(arizona); | 
					
						
							|  |  |  | 		if (ret != 0) { | 
					
						
							|  |  |  | 			dev_err(arizona->dev, "Failed to apply patch: %d\n", | 
					
						
							|  |  |  | 				ret); | 
					
						
							|  |  |  | 			goto err_reset; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-03-26 18:46:15 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		switch (arizona->type) { | 
					
						
							|  |  |  | 		case WM5102: | 
					
						
							|  |  |  | 			ret = arizona_apply_hardware_patch(arizona); | 
					
						
							|  |  |  | 			if (ret != 0) { | 
					
						
							|  |  |  | 				dev_err(arizona->dev, | 
					
						
							|  |  |  | 					"Failed to apply hardware patch: %d\n", | 
					
						
							|  |  |  | 					ret); | 
					
						
							|  |  |  | 				goto err_reset; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-12-02 11:41:46 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { | 
					
						
							|  |  |  | 		if (!arizona->pdata.gpio_defaults[i]) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		regmap_write(arizona->regmap, ARIZONA_GPIO1_CTRL + i, | 
					
						
							|  |  |  | 			     arizona->pdata.gpio_defaults[i]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-23 19:44:16 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * LDO1 can only be used to supply DCVDD so if it has no | 
					
						
							|  |  |  | 	 * consumers then DCVDD is supplied externally. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (arizona->pdata.ldo1 && | 
					
						
							|  |  |  | 	    arizona->pdata.ldo1->num_consumer_supplies == 0) | 
					
						
							|  |  |  | 		arizona->external_dcvdd = true; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	pm_runtime_set_autosuspend_delay(arizona->dev, 100); | 
					
						
							|  |  |  | 	pm_runtime_use_autosuspend(arizona->dev); | 
					
						
							|  |  |  | 	pm_runtime_enable(arizona->dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Chip default */ | 
					
						
							|  |  |  | 	if (!arizona->pdata.clk32k_src) | 
					
						
							|  |  |  | 		arizona->pdata.clk32k_src = ARIZONA_32KZ_MCLK2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (arizona->pdata.clk32k_src) { | 
					
						
							|  |  |  | 	case ARIZONA_32KZ_MCLK1: | 
					
						
							|  |  |  | 	case ARIZONA_32KZ_MCLK2: | 
					
						
							|  |  |  | 		regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, | 
					
						
							|  |  |  | 				   ARIZONA_CLK_32K_SRC_MASK, | 
					
						
							|  |  |  | 				   arizona->pdata.clk32k_src - 1); | 
					
						
							| 
									
										
										
										
											2013-03-19 19:04:46 +01:00
										 |  |  | 		arizona_clk32k_enable(arizona); | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case ARIZONA_32KZ_NONE: | 
					
						
							|  |  |  | 		regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, | 
					
						
							|  |  |  | 				   ARIZONA_CLK_32K_SRC_MASK, 2); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Invalid 32kHz clock source: %d\n", | 
					
						
							|  |  |  | 			arizona->pdata.clk32k_src); | 
					
						
							|  |  |  | 		ret = -EINVAL; | 
					
						
							| 
									
										
										
										
											2012-07-09 00:31:36 +02:00
										 |  |  | 		goto err_reset; | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-29 00:47:37 +08:00
										 |  |  | 	for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { | 
					
						
							| 
									
										
										
										
											2013-01-29 18:44:41 +08:00
										 |  |  | 		if (!arizona->pdata.micbias[i].mV && | 
					
						
							|  |  |  | 		    !arizona->pdata.micbias[i].bypass) | 
					
						
							| 
									
										
										
										
											2013-01-29 00:47:37 +08:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-29 18:44:41 +08:00
										 |  |  | 		/* Apply default for bypass mode */ | 
					
						
							|  |  |  | 		if (!arizona->pdata.micbias[i].mV) | 
					
						
							|  |  |  | 			arizona->pdata.micbias[i].mV = 2800; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-29 00:47:37 +08:00
										 |  |  | 		val = (arizona->pdata.micbias[i].mV - 1500) / 100; | 
					
						
							| 
									
										
										
										
											2013-01-29 18:44:41 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-29 00:47:37 +08:00
										 |  |  | 		val <<= ARIZONA_MICB1_LVL_SHIFT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (arizona->pdata.micbias[i].ext_cap) | 
					
						
							|  |  |  | 			val |= ARIZONA_MICB1_EXT_CAP; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (arizona->pdata.micbias[i].discharge) | 
					
						
							|  |  |  | 			val |= ARIZONA_MICB1_DISCH; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-21 14:56:58 +01:00
										 |  |  | 		if (arizona->pdata.micbias[i].soft_start) | 
					
						
							| 
									
										
										
										
											2013-01-29 00:47:37 +08:00
										 |  |  | 			val |= ARIZONA_MICB1_RATE; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-29 18:44:41 +08:00
										 |  |  | 		if (arizona->pdata.micbias[i].bypass) | 
					
						
							|  |  |  | 			val |= ARIZONA_MICB1_BYPASS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-29 00:47:37 +08:00
										 |  |  | 		regmap_update_bits(arizona->regmap, | 
					
						
							|  |  |  | 				   ARIZONA_MIC_BIAS_CTRL_1 + i, | 
					
						
							|  |  |  | 				   ARIZONA_MICB1_LVL_MASK | | 
					
						
							|  |  |  | 				   ARIZONA_MICB1_DISCH | | 
					
						
							| 
									
										
										
										
											2013-01-29 18:44:41 +08:00
										 |  |  | 				   ARIZONA_MICB1_BYPASS | | 
					
						
							| 
									
										
										
										
											2013-01-29 00:47:37 +08:00
										 |  |  | 				   ARIZONA_MICB1_RATE, val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	for (i = 0; i < ARIZONA_MAX_INPUT; i++) { | 
					
						
							|  |  |  | 		/* Default for both is 0 so noop with defaults */ | 
					
						
							|  |  |  | 		val = arizona->pdata.dmic_ref[i] | 
					
						
							|  |  |  | 			<< ARIZONA_IN1_DMIC_SUP_SHIFT; | 
					
						
							|  |  |  | 		val |= arizona->pdata.inmode[i] << ARIZONA_IN1_MODE_SHIFT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		regmap_update_bits(arizona->regmap, | 
					
						
							|  |  |  | 				   ARIZONA_IN1L_CONTROL + (i * 8), | 
					
						
							|  |  |  | 				   ARIZONA_IN1_DMIC_SUP_MASK | | 
					
						
							|  |  |  | 				   ARIZONA_IN1_MODE_MASK, val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) { | 
					
						
							|  |  |  | 		/* Default is 0 so noop with defaults */ | 
					
						
							|  |  |  | 		if (arizona->pdata.out_mono[i]) | 
					
						
							|  |  |  | 			val = ARIZONA_OUT1_MONO; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			val = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		regmap_update_bits(arizona->regmap, | 
					
						
							|  |  |  | 				   ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8), | 
					
						
							|  |  |  | 				   ARIZONA_OUT1_MONO, val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) { | 
					
						
							|  |  |  | 		if (arizona->pdata.spk_mute[i]) | 
					
						
							|  |  |  | 			regmap_update_bits(arizona->regmap, | 
					
						
							| 
									
										
										
										
											2012-07-09 19:33:14 +01:00
										 |  |  | 					   ARIZONA_PDM_SPK1_CTRL_1 + (i * 2), | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 					   ARIZONA_SPK1_MUTE_ENDIAN_MASK | | 
					
						
							|  |  |  | 					   ARIZONA_SPK1_MUTE_SEQ1_MASK, | 
					
						
							|  |  |  | 					   arizona->pdata.spk_mute[i]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (arizona->pdata.spk_fmt[i]) | 
					
						
							|  |  |  | 			regmap_update_bits(arizona->regmap, | 
					
						
							| 
									
										
										
										
											2012-07-09 19:33:14 +01:00
										 |  |  | 					   ARIZONA_PDM_SPK1_CTRL_2 + (i * 2), | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 					   ARIZONA_SPK1_FMT_MASK, | 
					
						
							|  |  |  | 					   arizona->pdata.spk_fmt[i]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Set up for interrupts */ | 
					
						
							|  |  |  | 	ret = arizona_irq_init(arizona); | 
					
						
							|  |  |  | 	if (ret != 0) | 
					
						
							| 
									
										
										
										
											2012-07-09 00:31:36 +02:00
										 |  |  | 		goto err_reset; | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	arizona_request_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, "CLKGEN error", | 
					
						
							|  |  |  | 			    arizona_clkgen_err, arizona); | 
					
						
							|  |  |  | 	arizona_request_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, "Overclocked", | 
					
						
							|  |  |  | 			    arizona_overclocked, arizona); | 
					
						
							|  |  |  | 	arizona_request_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, "Underclocked", | 
					
						
							|  |  |  | 			    arizona_underclocked, arizona); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (arizona->type) { | 
					
						
							|  |  |  | 	case WM5102: | 
					
						
							|  |  |  | 		ret = mfd_add_devices(arizona->dev, -1, wm5102_devs, | 
					
						
							| 
									
										
										
										
											2012-09-11 15:16:36 +08:00
										 |  |  | 				      ARRAY_SIZE(wm5102_devs), NULL, 0, NULL); | 
					
						
							| 
									
										
										
										
											2012-07-10 12:37:58 +01:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case WM5110: | 
					
						
							|  |  |  | 		ret = mfd_add_devices(arizona->dev, -1, wm5110_devs, | 
					
						
							| 
									
										
										
										
											2012-11-20 13:46:19 +09:00
										 |  |  | 				      ARRAY_SIZE(wm5110_devs), NULL, 0, NULL); | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2013-06-13 09:43:29 +01:00
										 |  |  | 	case WM8997: | 
					
						
							|  |  |  | 		ret = mfd_add_devices(arizona->dev, -1, wm8997_devs, | 
					
						
							|  |  |  | 				      ARRAY_SIZE(wm8997_devs), NULL, 0, NULL); | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ret != 0) { | 
					
						
							|  |  |  | 		dev_err(arizona->dev, "Failed to add subdevices: %d\n", ret); | 
					
						
							|  |  |  | 		goto err_irq; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-09 00:31:36 +02:00
										 |  |  | #ifdef CONFIG_PM_RUNTIME
 | 
					
						
							|  |  |  | 	regulator_disable(arizona->dcvdd); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | err_irq: | 
					
						
							|  |  |  | 	arizona_irq_exit(arizona); | 
					
						
							|  |  |  | err_reset: | 
					
						
							|  |  |  | 	if (arizona->pdata.reset) { | 
					
						
							| 
									
										
										
										
											2013-03-26 12:15:26 +00:00
										 |  |  | 		gpio_set_value_cansleep(arizona->pdata.reset, 0); | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 		gpio_free(arizona->pdata.reset); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-07-09 00:31:36 +02:00
										 |  |  | 	regulator_disable(arizona->dcvdd); | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | err_enable: | 
					
						
							| 
									
										
										
										
											2012-07-09 00:45:53 +02:00
										 |  |  | 	regulator_bulk_disable(arizona->num_core_supplies, | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 			       arizona->core_supplies); | 
					
						
							|  |  |  | err_early: | 
					
						
							|  |  |  | 	mfd_remove_devices(dev); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(arizona_dev_init); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-19 13:26:01 -05:00
										 |  |  | int arizona_dev_exit(struct arizona *arizona) | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	mfd_remove_devices(arizona->dev); | 
					
						
							|  |  |  | 	arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona); | 
					
						
							|  |  |  | 	arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona); | 
					
						
							|  |  |  | 	arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona); | 
					
						
							|  |  |  | 	pm_runtime_disable(arizona->dev); | 
					
						
							|  |  |  | 	arizona_irq_exit(arizona); | 
					
						
							| 
									
										
										
										
											2013-03-26 12:16:26 +00:00
										 |  |  | 	if (arizona->pdata.reset) | 
					
						
							|  |  |  | 		gpio_set_value_cansleep(arizona->pdata.reset, 0); | 
					
						
							|  |  |  | 	regulator_disable(arizona->dcvdd); | 
					
						
							|  |  |  | 	regulator_bulk_disable(ARRAY_SIZE(arizona->core_supplies), | 
					
						
							|  |  |  | 			       arizona->core_supplies); | 
					
						
							| 
									
										
										
										
											2012-06-19 16:31:53 +01:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(arizona_dev_exit); |