예제 #1
0
파일: wm8350_wdt.c 프로젝트: 19Dan01/linux
static int wm8350_wdt_set_timeout(struct watchdog_device *wdt_dev,
				  unsigned int timeout)
{
	struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
	int ret, i;
	u16 reg;

	for (i = 0; i < ARRAY_SIZE(wm8350_wdt_cfgs); i++)
		if (wm8350_wdt_cfgs[i].time == timeout)
			break;
	if (i == ARRAY_SIZE(wm8350_wdt_cfgs))
		return -EINVAL;

	mutex_lock(&wdt_mutex);
	wm8350_reg_unlock(wm8350);

	reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
	reg &= ~WM8350_WDOG_TO_MASK;
	reg |= wm8350_wdt_cfgs[i].val;
	ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);

	wm8350_reg_lock(wm8350);
	mutex_unlock(&wdt_mutex);

	wdt_dev->timeout = timeout;
	return ret;
}
static __devinit int wm8350_power_probe(struct platform_device *pdev)
{
	struct wm8350 *wm8350 = platform_get_drvdata(pdev);
	struct wm8350_power *power = &wm8350->power;
	struct wm8350_charger_policy *policy = power->policy;
	struct power_supply *usb = &power->usb;
	struct power_supply *battery = &power->battery;
	struct power_supply *ac = &power->ac;
	int ret;

	ac->name = "wm8350-ac";
	ac->type = POWER_SUPPLY_TYPE_MAINS;
	ac->properties = wm8350_ac_props;
	ac->num_properties = ARRAY_SIZE(wm8350_ac_props);
	ac->get_property = wm8350_ac_get_prop;
	ret = power_supply_register(&pdev->dev, ac);
	if (ret)
		return ret;

	battery->name = "wm8350-battery";
	battery->properties = wm8350_bat_props;
	battery->num_properties = ARRAY_SIZE(wm8350_bat_props);
	battery->get_property = wm8350_bat_get_property;
	battery->use_for_apm = 1;
	ret = power_supply_register(&pdev->dev, battery);
	if (ret)
		goto battery_failed;

	usb->name = "wm8350-usb",
	usb->type = POWER_SUPPLY_TYPE_USB;
	usb->properties = wm8350_usb_props;
	usb->num_properties = ARRAY_SIZE(wm8350_usb_props);
	usb->get_property = wm8350_usb_get_prop;
	ret = power_supply_register(&pdev->dev, usb);
	if (ret)
		goto usb_failed;

	ret = device_create_file(&pdev->dev, &dev_attr_charger_state);
	if (ret < 0)
		dev_warn(wm8350->dev, "failed to add charge sysfs: %d\n", ret);
	ret = 0;

	wm8350_init_charger(wm8350);
	if (wm8350_charger_config(wm8350, policy) == 0) {
		wm8350_reg_unlock(wm8350);
		wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CHG_ENA);
		wm8350_reg_lock(wm8350);
	}

	return ret;

usb_failed:
	power_supply_unregister(battery);
battery_failed:
	power_supply_unregister(ac);

	return ret;
}
static irqreturn_t wm8350_charger_handler(int irq, void *data)
{
	struct wm8350 *wm8350 = data;
	struct wm8350_power *power = &wm8350->power;
	struct wm8350_charger_policy *policy = power->policy;

	switch (irq - wm8350->irq_base) {
	case WM8350_IRQ_CHG_BAT_FAIL:
		dev_err(wm8350->dev, "battery failed\n");
		break;
	case WM8350_IRQ_CHG_TO:
		dev_err(wm8350->dev, "charger timeout\n");
		power_supply_changed(&power->battery);
		break;

	case WM8350_IRQ_CHG_BAT_HOT:
	case WM8350_IRQ_CHG_BAT_COLD:
	case WM8350_IRQ_CHG_START:
	case WM8350_IRQ_CHG_END:
		power_supply_changed(&power->battery);
		break;

	case WM8350_IRQ_CHG_FAST_RDY:
		dev_dbg(wm8350->dev, "fast charger ready\n");
		wm8350_charger_config(wm8350, policy);
		wm8350_reg_unlock(wm8350);
		wm8350_set_bits(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1,
				WM8350_CHG_FAST);
		wm8350_reg_lock(wm8350);
		break;

	case WM8350_IRQ_CHG_VBATT_LT_3P9:
		dev_warn(wm8350->dev, "battery < 3.9V\n");
		break;
	case WM8350_IRQ_CHG_VBATT_LT_3P1:
		dev_warn(wm8350->dev, "battery < 3.1V\n");
		break;
	case WM8350_IRQ_CHG_VBATT_LT_2P85:
		dev_warn(wm8350->dev, "battery < 2.85V\n");
		break;

		/* Supply change.  We will overnotify but it should do
		 * no harm. */
	case WM8350_IRQ_EXT_USB_FB:
	case WM8350_IRQ_EXT_WALL_FB:
		wm8350_charger_config(wm8350, policy);
	case WM8350_IRQ_EXT_BAT_FB:   /* Fall through */
		power_supply_changed(&power->battery);
		power_supply_changed(&power->usb);
		power_supply_changed(&power->ac);
		break;

	default:
		dev_err(wm8350->dev, "Unknown interrupt %d\n", irq);
	}

	return IRQ_HANDLED;
}
예제 #4
0
static void wm8350_charger_handler(struct wm8350 *wm8350, int irq, void *data)
{
	struct wm8350_power *power = &wm8350->power;
	struct wm8350_charger_policy *policy = power->policy;

	switch (irq) {
	case WM8350_IRQ_CHG_BAT_FAIL:
		dev_err(wm8350->dev, "battery failed\n");
		break;
	case WM8350_IRQ_CHG_TO:
		dev_err(wm8350->dev, "charger timeout\n");
		power_supply_changed(&power->battery);
		break;

	case WM8350_IRQ_CHG_BAT_HOT:
	case WM8350_IRQ_CHG_BAT_COLD:
	case WM8350_IRQ_CHG_START:
	case WM8350_IRQ_CHG_END:
		power_supply_changed(&power->battery);
		break;

	case WM8350_IRQ_CHG_FAST_RDY:
		dev_dbg(wm8350->dev, "fast charger ready\n");
		wm8350_charger_config(wm8350, policy);
		wm8350_reg_unlock(wm8350);
		wm8350_set_bits(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1,
				WM8350_CHG_FAST);
		wm8350_reg_lock(wm8350);
		break;

	case WM8350_IRQ_CHG_VBATT_LT_3P9:
		dev_warn(wm8350->dev, "battery < 3.9V\n");
		break;
	case WM8350_IRQ_CHG_VBATT_LT_3P1:
		dev_warn(wm8350->dev, "battery < 3.1V\n");
		break;
	case WM8350_IRQ_CHG_VBATT_LT_2P85:
		dev_warn(wm8350->dev, "battery < 2.85V\n");
		break;

		
	case WM8350_IRQ_EXT_USB_FB:
	case WM8350_IRQ_EXT_WALL_FB:
		wm8350_charger_config(wm8350, policy);
	case WM8350_IRQ_EXT_BAT_FB:   
		power_supply_changed(&power->battery);
		power_supply_changed(&power->usb);
		power_supply_changed(&power->ac);
		break;

	default:
		dev_err(wm8350->dev, "Unknown interrupt %d\n", irq);
	}
}
static int wm8350_charger_config(struct wm8350 *wm8350,
				 struct wm8350_charger_policy *policy)
{
	u16 reg, eoc_mA, fast_limit_mA;

	if (!policy) {
		dev_warn(wm8350->dev,
			 "No charger policy, charger not configured.\n");
		return -EINVAL;
	}

	/* make sure USB fast charge current is not > 500mA */
	if (policy->fast_limit_USB_mA > 500) {
		dev_err(wm8350->dev, "USB fast charge > 500mA\n");
		return -EINVAL;
	}

	eoc_mA = WM8350_CHG_EOC_mA(policy->eoc_mA);

	wm8350_reg_unlock(wm8350);

	reg = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1)
		& WM8350_CHG_ENA_R168;
	wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1,
			 reg | eoc_mA | policy->trickle_start_mV |
			 WM8350_CHG_TRICKLE_TEMP_CHOKE |
			 WM8350_CHG_TRICKLE_USB_CHOKE |
			 WM8350_CHG_FAST_USB_THROTTLE);

	if (wm8350_get_supplies(wm8350) & WM8350_USB_SUPPLY) {
		fast_limit_mA =
			WM8350_CHG_FAST_LIMIT_mA(policy->fast_limit_USB_mA);
		wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2,
			    policy->charge_mV | policy->trickle_charge_USB_mA |
			    fast_limit_mA | wm8350_charge_time_min(wm8350,
						policy->charge_timeout));

	} else {
		fast_limit_mA =
			WM8350_CHG_FAST_LIMIT_mA(policy->fast_limit_mA);
		wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2,
			    policy->charge_mV | policy->trickle_charge_mA |
			    fast_limit_mA | wm8350_charge_time_min(wm8350,
						policy->charge_timeout));
	}

	wm8350_reg_lock(wm8350);
	return 0;
}
예제 #6
0
static int gpio_set_dir(struct wm8350 *wm8350, int gpio, int dir)
{
	int ret;

	wm8350_reg_unlock(wm8350);
	if (dir == WM8350_GPIO_DIR_OUT)
		ret = wm8350_clear_bits(wm8350,
					WM8350_GPIO_CONFIGURATION_I_O,
					1 << gpio);
	else
		ret = wm8350_set_bits(wm8350,
				      WM8350_GPIO_CONFIGURATION_I_O,
				      1 << gpio);
	wm8350_reg_lock(wm8350);
	return ret;
}
예제 #7
0
static int wm8350_wdt_stop(struct wm8350 *wm8350)
{
	int ret;
	u16 reg;

	mutex_lock(&wdt_mutex);
	wm8350_reg_unlock(wm8350);

	reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
	reg &= ~WM8350_WDOG_MODE_MASK;
	ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);

	wm8350_reg_lock(wm8350);
	mutex_unlock(&wdt_mutex);

	return ret;
}
예제 #8
0
static int wm8350_wdt_set_timeout(struct wm8350 *wm8350, u16 value)
{
	int ret;
	u16 reg;

	mutex_lock(&wdt_mutex);
	wm8350_reg_unlock(wm8350);

	reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
	reg &= ~WM8350_WDOG_TO_MASK;
	reg |= value;
	ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);

	wm8350_reg_lock(wm8350);
	mutex_unlock(&wdt_mutex);

	return ret;
}
예제 #9
0
파일: wm8350_wdt.c 프로젝트: 19Dan01/linux
static int wm8350_wdt_stop(struct watchdog_device *wdt_dev)
{
	struct wm8350 *wm8350 = watchdog_get_drvdata(wdt_dev);
	int ret;
	u16 reg;

	mutex_lock(&wdt_mutex);
	wm8350_reg_unlock(wm8350);

	reg = wm8350_reg_read(wm8350, WM8350_SYSTEM_CONTROL_2);
	reg &= ~WM8350_WDOG_MODE_MASK;
	ret = wm8350_reg_write(wm8350, WM8350_SYSTEM_CONTROL_2, reg);

	wm8350_reg_lock(wm8350);
	mutex_unlock(&wdt_mutex);

	return ret;
}
예제 #10
0
//static int wm8350_init(struct wm8350 *wm8350)
int wm8350_dev_init(struct wm8350 *wm8350)
{
	int i, ret;
	u16 data;

#if 0
	/* dont assert RTS when hibernating */
	wm8350_set_bits(wm8350, WM8350_SYSTEM_HIBERNATE, WM8350_RST_HIB_MODE);
#endif

	wm8350_reg_unlock(wm8350);
	wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1, WM8350_IRQ_POL);
	wm8350_reg_lock(wm8350);

	s3c2410_gpio_pullup(S3C2410_GPF1, 0);
	s3c2410_gpio_cfgpin(S3C2410_GPF1, S3C2410_GPF1_EINT1);
//	set_irq_type(IRQ_EINT1, IRQT_BOTHEDGE);
	s3c2410_gpio_pullup(S3C2410_GPF2, 0);
	s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2);

	/* Shutdown threshold value 3.1v off , 3.2v on */
	wm8350_reg_unlock(wm8350);
	data = wm8350_reg_read(wm8350, WM8350_POWER_CHECK_COMPARATOR)
		& ~(WM8350_PCCMP_OFF_THR_MASK | WM8350_PCCMP_ON_THR_MASK);
	wm8350_reg_write(wm8350, WM8350_POWER_CHECK_COMPARATOR, data | 0x23);
	wm8350_reg_lock(wm8350);

	data = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_2);
	wm8350_reg_write(wm8350, WM8350_DIGITISER_CONTROL_2, data | WM8350_AUXADC_CAL);

	config_s3c_wm8350_gpio(wm8350);

#if 0
	/* Sw1 --> PWR_ON */
	wm8350_register_irq(wm8350, WM8350_IRQ_WKUP_ONKEY,
			    imx32ads_switch_handler, NULL);
	wm8350_unmask_irq(wm8350, WM8350_IRQ_WKUP_ONKEY);
#endif

#ifndef CONFIG_MACH_CANOPUS
	for (i = 0; i < ARRAY_SIZE(wm8350_regulator_devices); i++) {
		platform_set_drvdata(&wm8350_regulator_devices[i], wm8350);
		ret = platform_device_register(&wm8350_regulator_devices[i]);
		if (ret < 0)
			goto unwind;
	}
#else	// CONFIG_MACH_CANOPUS
	struct regulator_init_data *reg_data = NULL;

	for (i = 0; i < ARRAY_SIZE(wm8350_regulator_devices); i++) {
		if (wm8350_regulator_devices[i].id == WM8350_DCDC_4) {
			// for LCD
			if (q_hw_ver(7800_ES2)
					|| q_hw_ver(7800_TP)
					|| q_hw_ver(7800_MP)) {
				reg_data = (struct regulator_init_data *)wm8350_regulator_devices[i].dev.platform_data;
				reg_data->constraints.min_uV = 3400000;
				reg_data->constraints.max_uV = 3400000;
				reg_data->constraints.state_mem.uV = 3400000;
			}
		} else if (wm8350_regulator_devices[i].id == WM8350_LDO_3) {
			// for PMIC LDO
			if (q_hw_ver(SWP2000)
					|| q_hw_ver(7800_MP2)
					|| q_hw_ver(KTQOOK_TP2)
					|| q_hw_ver(KTQOOK_MP)
					|| q_hw_ver(SKATM)) {
				reg_data = (struct regulator_init_data *)wm8350_regulator_devices[i].dev.platform_data;

				reg_data->constraints.min_uV = 1200000;
				reg_data->constraints.max_uV = 1200000;
				reg_data->num_consumer_supplies = ARRAY_SIZE(ldo4_consumers);
				reg_data->consumer_supplies = ldo4_consumers;
			}
		} else if (wm8350_regulator_devices[i].id == WM8350_LDO_4) {
			// for PMIC LDO
			if (q_hw_ver(SWP2000)
					|| q_hw_ver(7800_MP2)
					|| q_hw_ver(KTQOOK_TP2)
					|| q_hw_ver(KTQOOK_MP)
					|| q_hw_ver(SKATM)) {
				reg_data = (struct regulator_init_data *)wm8350_regulator_devices[i].dev.platform_data;
				reg_data->constraints.min_uV = 3300000;
				reg_data->constraints.max_uV = 3300000;
				reg_data->num_consumer_supplies = ARRAY_SIZE(ldo3_consumers);
				reg_data->consumer_supplies = ldo3_consumers;
			}
		}

		platform_set_drvdata(&wm8350_regulator_devices[i], wm8350);
		ret = platform_device_register(&wm8350_regulator_devices[i]);
		if (ret < 0)
			goto unwind;
	}
#endif	// CONFIG_MACH_CANOPUS

	/* now register other clients */
	return s3c_wm8350_device_register(wm8350);
unwind:
	for (i--; i >= 0; i--)
		platform_device_unregister(&wm8350_regulator_devices[i]);

	return ret;
}
예제 #11
0
파일: rtc-wm8350.c 프로젝트: 020gzh/linux
static int wm8350_rtc_probe(struct platform_device *pdev)
{
	struct wm8350 *wm8350 = platform_get_drvdata(pdev);
	struct wm8350_rtc *wm_rtc = &wm8350->rtc;
	int ret = 0;
	u16 timectl, power5;

	timectl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL);
	if (timectl & WM8350_RTC_BCD) {
		dev_err(&pdev->dev, "RTC BCD mode not supported\n");
		return -EINVAL;
	}
	if (timectl & WM8350_RTC_12HR) {
		dev_err(&pdev->dev, "RTC 12 hour mode not supported\n");
		return -EINVAL;
	}

	/* enable the RTC if it's not already enabled */
	power5 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
	if (!(power5 &  WM8350_RTC_TICK_ENA)) {
		dev_info(wm8350->dev, "Starting RTC\n");

		wm8350_reg_unlock(wm8350);

		ret = wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5,
				      WM8350_RTC_TICK_ENA);
		if (ret < 0) {
			dev_err(&pdev->dev, "failed to enable RTC: %d\n", ret);
			return ret;
		}

		wm8350_reg_lock(wm8350);
	}

	if (timectl & WM8350_RTC_STS) {
		int retries;

		ret = wm8350_clear_bits(wm8350, WM8350_RTC_TIME_CONTROL,
					WM8350_RTC_SET);
		if (ret < 0) {
			dev_err(&pdev->dev, "failed to start: %d\n", ret);
			return ret;
		}

		retries = WM8350_SET_TIME_RETRIES;
		do {
			timectl = wm8350_reg_read(wm8350,
						  WM8350_RTC_TIME_CONTROL);
		} while (timectl & WM8350_RTC_STS && --retries);

		if (retries == 0) {
			dev_err(&pdev->dev, "failed to start: timeout\n");
			return -ENODEV;
		}
	}

	device_init_wakeup(&pdev->dev, 1);

	wm_rtc->rtc = devm_rtc_device_register(&pdev->dev, "wm8350",
					&wm8350_rtc_ops, THIS_MODULE);
	if (IS_ERR(wm_rtc->rtc)) {
		ret = PTR_ERR(wm_rtc->rtc);
		dev_err(&pdev->dev, "failed to register RTC: %d\n", ret);
		return ret;
	}

	wm8350_register_irq(wm8350, WM8350_IRQ_RTC_SEC,
			    wm8350_rtc_update_handler, 0,
			    "RTC Seconds", wm8350);
	wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);

	wm8350_register_irq(wm8350, WM8350_IRQ_RTC_ALM,
			    wm8350_rtc_alarm_handler, 0,
			    "RTC Alarm", wm8350);

	return 0;
}
예제 #12
0
static int gpio_set_func(struct wm8350 *wm8350, int gpio, int func)
{
	u16 reg;

	wm8350_reg_unlock(wm8350);
	switch (gpio) {
	case 0:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
		    & ~WM8350_GP0_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
				 reg | ((func & 0xf) << 0));
		break;
	case 1:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
		    & ~WM8350_GP1_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
				 reg | ((func & 0xf) << 4));
		break;
	case 2:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
		    & ~WM8350_GP2_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
				 reg | ((func & 0xf) << 8));
		break;
	case 3:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
		    & ~WM8350_GP3_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
				 reg | ((func & 0xf) << 12));
		break;
	case 4:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
		    & ~WM8350_GP4_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
				 reg | ((func & 0xf) << 0));
		break;
	case 5:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
		    & ~WM8350_GP5_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
				 reg | ((func & 0xf) << 4));
		break;
	case 6:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
		    & ~WM8350_GP6_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
				 reg | ((func & 0xf) << 8));
		break;
	case 7:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
		    & ~WM8350_GP7_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
				 reg | ((func & 0xf) << 12));
		break;
	case 8:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
		    & ~WM8350_GP8_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
				 reg | ((func & 0xf) << 0));
		break;
	case 9:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
		    & ~WM8350_GP9_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
				 reg | ((func & 0xf) << 4));
		break;
	case 10:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
		    & ~WM8350_GP10_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
				 reg | ((func & 0xf) << 8));
		break;
	case 11:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
		    & ~WM8350_GP11_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
				 reg | ((func & 0xf) << 12));
		break;
	case 12:
		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_4)
		    & ~WM8350_GP12_FN_MASK;
		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_4,
				 reg | ((func & 0xf) << 0));
		break;
	default:
		wm8350_reg_lock(wm8350);
		return -EINVAL;
	}

	wm8350_reg_lock(wm8350);
	return 0;
}
int wm8350_init(struct wm8350 *wm8350)
{
    int ret = 0;

    /* register regulator and set constraints */
    wm8350_device_register_pmic(wm8350);
    set_regulator_constraints(wm8350);
#ifdef NOT_PORTED_TO_IMX37
    wm8350_device_register_rtc(wm8350);
    wm8350_device_register_wdg(wm8350);
    wm8350_device_register_power(wm8350);
#endif
    mxc_init_wm8350();

    /*Note: Needs to be moved into a regulator function. */
    /* Configuring -- GPIO 7 pin */
    if (wm8350_gpio_config(wm8350, 7, WM8350_GPIO_DIR_OUT, 0,
                           WM8350_GPIO_ACTIVE_LOW, WM8350_GPIO_PULL_NONE,
                           WM8350_GPIO_INVERT_OFF,
                           WM8350_GPIO_DEBOUNCE_OFF) == 0)
        wm8350_gpio_set_status(wm8350, 7, 1);
    else
        printk(KERN_ERR "Error in setting Wolfson GPIO pin 7 \n");
    /* enable gpio4:USB_VBUS_EN */
    ret =
        wm8350_gpio_config(wm8350, 4, WM8350_GPIO_DIR_IN,
                           WM8350_GPIO4_MR_IN, WM8350_GPIO_ACTIVE_HIGH,
                           WM8350_GPIO_PULL_UP, WM8350_GPIO_INVERT_OFF,
                           WM8350_GPIO_DEBOUNCE_OFF);
    if (ret)
        printk(KERN_ERR "Error in setting USB VBUS enable pin\n");

    /*PMIC RDY*/
    if (wm8350_gpio_config(wm8350, 9, WM8350_GPIO_DIR_OUT, WM8350_GPIO9_GPIO_OUT,
                           WM8350_GPIO_ACTIVE_LOW, WM8350_GPIO_PULL_NONE,
                           WM8350_GPIO_INVERT_OFF, WM8350_GPIO_DEBOUNCE_OFF) == 0)
        wm8350_gpio_set_status(wm8350, 9, 1);
    else
        printk(KERN_ERR "Error in setting Wolfson GPIO pin 9 \n");

    /* register sound */
    printk("Registering imx37_snd_device");
    imx_snd_device = platform_device_alloc("wm8350-imx-3stack-audio", -1);
    if (!imx_snd_device) {
        ret = -ENOMEM;
        goto err;
    }
    imx_snd_device->dev.platform_data = &imx_3stack_audio_platform_data;
    platform_set_drvdata(imx_snd_device, &wm8350->audio);
    ret = platform_device_add(imx_snd_device);
    if (ret)
        goto snd_err;

    /* set up PMIC IRQ (active high) to i.MX32ADS */
    printk("Registering PMIC INT");
    INIT_WORK(&wm8350->work, wm8350_irq_work);
    wm8350_reg_unlock(wm8350);
    wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1, WM8350_IRQ_POL);
    wm8350_reg_lock(wm8350);
    set_irq_type(MXC_PMIC_INT_LINE, IRQT_RISING);
    ret = request_irq(MXC_PMIC_INT_LINE, wm8350_irq_handler,
                      IRQF_DISABLED, "wm8350-pmic", wm8350);
    if (ret != 0) {
        printk(KERN_ERR "wm8350: cant request irq %d\n",
               MXC_PMIC_INT_LINE);
        goto err;
    }
    wm8350->nirq = MXC_PMIC_INT_LINE;

    set_irq_wake(MXC_PMIC_INT_LINE, 1);

#ifdef NOT_PORTED_TO_IMX37
    printk("Configuring WM8350 GPIOS");
    config_gpios(wm8350);
    config_hibernate(wm8350);
#endif

    /* Sw1 --> PWR_ON */
    printk("Registering and unmasking the WM8350 wakeup key\n");
    wm8350_register_irq(wm8350, WM8350_IRQ_WKUP_ONKEY,
                        imx37_3stack_switch_handler, NULL);
    wm8350_unmask_irq(wm8350, WM8350_IRQ_WKUP_ONKEY);

    /* unmask all & clear sticky */
    printk("Unmasking WM8350 local interrupts\n");
    wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0x3ffe);
    schedule_work(&wm8350->work);

#if BATTERY
    /* not much use without a battery atm */
    wm8350_init_battery(wm8350);
#endif

    printk("Exiting normally from wm8350_init()");
    return ret;
snd_err:
    platform_device_put(imx_snd_device);

err:
    printk("wm8350_init() FAILED");
    kfree(wm8350->reg_cache);
    return ret;
}