123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- /* Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <linux/device.h>
- #include <linux/regulator/consumer.h>
- #include <linux/gpio.h>
- #include <mach/rpc_pmapp.h>
- #include <linux/err.h>
- #include <linux/qcomwlan7x27a_pwrif.h>
- #include <linux/module.h>
- #define WLAN_GPIO_EXT_POR_N 134
- static const char *id = "WLAN";
- enum {
- WLAN_VREG_L17 = 0,
- WLAN_VREG_S3,
- WLAN_VREG_TCXO_L11,
- WLAN_VREG_L19,
- WLAN_VREG_L5,
- WLAN_VREG_L6
- };
- struct wlan_vreg_info {
- const char *vreg_id;
- unsigned int level_min;
- unsigned int level_max;
- unsigned int pmapp_id;
- unsigned int is_vreg_pin_controlled;
- struct regulator *reg;
- };
- static struct wlan_vreg_info vreg_info[] = {
- {"bt", 3050000, 3050000, 21, 1, NULL},
- {"msme1", 1800000, 1800000, 2, 0, NULL},
- {"wlan_tcx0", 1800000, 1800000, 53, 0, NULL},
- {"wlan4", 1200000, 1200000, 23, 0, NULL},
- {"wlan2", 1350000, 1350000, 9, 1, NULL},
- {"wlan3", 1200000, 1200000, 10, 1, NULL},
- };
- static int qrf6285_init_regs(void)
- {
- struct regulator_bulk_data regs[ARRAY_SIZE(vreg_info)];
- int i, rc;
- for (i = 0; i < ARRAY_SIZE(regs); i++) {
- regs[i].supply = vreg_info[i].vreg_id;
- regs[i].min_uV = vreg_info[i].level_min;
- regs[i].max_uV = vreg_info[i].level_max;
- }
- rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs), regs);
- if (rc) {
- pr_err("%s: could not get regulators: %d\n", __func__, rc);
- goto out;
- }
- for (i = 0; i < ARRAY_SIZE(regs); i++)
- vreg_info[i].reg = regs[i].consumer;
- return 0;
- out:
- return rc;
- }
- int chip_power_qrf6285(bool on)
- {
- static bool init_done;
- int rc = 0, index = 0;
- if (unlikely(!init_done)) {
- rc = qrf6285_init_regs();
- if (rc)
- return rc;
- else
- init_done = true;
- }
- if (on) {
- rc = gpio_request(WLAN_GPIO_EXT_POR_N, "WLAN_DEEP_SLEEP_N");
- if (rc) {
- pr_err("WLAN reset GPIO %d request failed %d\n",
- WLAN_GPIO_EXT_POR_N, rc);
- goto fail;
- }
- rc = gpio_direction_output(WLAN_GPIO_EXT_POR_N, 1);
- if (rc < 0) {
- pr_err("WLAN reset GPIO %d set direction failed %d\n",
- WLAN_GPIO_EXT_POR_N, rc);
- goto fail_gpio_dir_out;
- }
- rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
- PMAPP_CLOCK_VOTE_ON);
- if (rc) {
- pr_err("%s: Configuring A0 to always"
- " on failed %d\n", __func__, rc);
- goto clock_vote_fail;
- }
- } else {
- gpio_set_value_cansleep(WLAN_GPIO_EXT_POR_N, 0);
- rc = gpio_direction_input(WLAN_GPIO_EXT_POR_N);
- if (rc) {
- pr_err("WLAN reset GPIO %d set direction failed %d\n",
- WLAN_GPIO_EXT_POR_N, rc);
- }
- gpio_free(WLAN_GPIO_EXT_POR_N);
- rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
- PMAPP_CLOCK_VOTE_OFF);
- if (rc) {
- pr_err("%s: Configuring A0 to turn OFF"
- " failed %d\n", __func__, rc);
- }
- }
- for (index = 0; index < ARRAY_SIZE(vreg_info); index++) {
- if (on) {
- rc = regulator_set_voltage(vreg_info[index].reg,
- vreg_info[index].level_min,
- vreg_info[index].level_max);
- if (rc) {
- pr_err("%s:%s set voltage failed %d\n",
- __func__, vreg_info[index].vreg_id, rc);
- goto vreg_fail;
- }
- rc = regulator_enable(vreg_info[index].reg);
- if (rc) {
- pr_err("%s:%s vreg enable failed %d\n",
- __func__, vreg_info[index].vreg_id, rc);
- goto vreg_fail;
- }
- if (vreg_info[index].is_vreg_pin_controlled) {
- rc = pmapp_vreg_lpm_pincntrl_vote(id,
- vreg_info[index].pmapp_id,
- PMAPP_CLOCK_ID_A0, 1);
- if (rc) {
- pr_err("%s:%s pmapp_vreg_lpm_pincntrl"
- " for enable failed %d\n",
- __func__,
- vreg_info[index].vreg_id, rc);
- goto vreg_clock_vote_fail;
- }
- }
- /*At this point CLK_PWR_REQ is high*/
- if (WLAN_VREG_L6 == index) {
- /*
- * Configure A0 clock to be slave to
- * WLAN_CLK_PWR_REQ
- ` */
- rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_A0,
- PMAPP_CLOCK_VOTE_PIN_CTRL);
- if (rc) {
- pr_err("%s: Configuring A0 to Pin"
- " controllable failed %d\n",
- __func__, rc);
- goto vreg_clock_vote_fail;
- }
- }
- } else {
- if (vreg_info[index].is_vreg_pin_controlled) {
- rc = pmapp_vreg_lpm_pincntrl_vote(id,
- vreg_info[index].pmapp_id,
- PMAPP_CLOCK_ID_A0, 0);
- if (rc) {
- pr_err("%s:%s pmapp_vreg_lpm_pincntrl"
- " for disable failed %d\n",
- __func__,
- vreg_info[index].vreg_id, rc);
- }
- }
- rc = regulator_disable(vreg_info[index].reg);
- if (rc) {
- pr_err("%s:%s vreg disable failed %d\n",
- __func__, vreg_info[index].vreg_id, rc);
- }
- }
- }
- return 0;
- vreg_fail:
- index--;
- vreg_clock_vote_fail:
- while (index >= 0) {
- rc = regulator_disable(vreg_info[index].reg);
- if (rc) {
- pr_err("%s:%s vreg disable failed %d\n",
- __func__, vreg_info[index].vreg_id, rc);
- }
- index--;
- }
- if (!on)
- goto fail;
- clock_vote_fail:
- gpio_set_value_cansleep(WLAN_GPIO_EXT_POR_N, 0);
- rc = gpio_direction_input(WLAN_GPIO_EXT_POR_N);
- if (rc) {
- pr_err("WLAN reset GPIO %d set direction failed %d\n",
- WLAN_GPIO_EXT_POR_N, rc);
- }
- fail_gpio_dir_out:
- gpio_free(WLAN_GPIO_EXT_POR_N);
- fail:
- return rc;
- }
- EXPORT_SYMBOL(chip_power_qrf6285);
|