123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768 |
- /* Copyright (c) 2011-2018, 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/module.h>
- #include <linux/kernel.h>
- #include <linux/delay.h>
- #include <linux/init.h>
- #include <linux/io.h>
- #include <linux/slab.h>
- #include "spm_driver.h"
- #define MSM_SPM_PMIC_STATE_IDLE 0
- enum {
- MSM_SPM_DEBUG_SHADOW = 1U << 0,
- MSM_SPM_DEBUG_VCTL = 1U << 1,
- };
- static int msm_spm_debug_mask;
- module_param_named(
- debug_mask, msm_spm_debug_mask, int, 0664
- );
- struct saw2_data {
- const char *ver_name;
- uint32_t major;
- uint32_t minor;
- uint32_t *spm_reg_offset_ptr;
- };
- static uint32_t msm_spm_reg_offsets_saw2_v2_1[MSM_SPM_REG_NR] = {
- [MSM_SPM_REG_SAW_SECURE] = 0x00,
- [MSM_SPM_REG_SAW_ID] = 0x04,
- [MSM_SPM_REG_SAW_CFG] = 0x08,
- [MSM_SPM_REG_SAW_SPM_STS] = 0x0C,
- [MSM_SPM_REG_SAW_AVS_STS] = 0x10,
- [MSM_SPM_REG_SAW_PMIC_STS] = 0x14,
- [MSM_SPM_REG_SAW_RST] = 0x18,
- [MSM_SPM_REG_SAW_VCTL] = 0x1C,
- [MSM_SPM_REG_SAW_AVS_CTL] = 0x20,
- [MSM_SPM_REG_SAW_AVS_LIMIT] = 0x24,
- [MSM_SPM_REG_SAW_AVS_DLY] = 0x28,
- [MSM_SPM_REG_SAW_AVS_HYSTERESIS] = 0x2C,
- [MSM_SPM_REG_SAW_SPM_CTL] = 0x30,
- [MSM_SPM_REG_SAW_SPM_DLY] = 0x34,
- [MSM_SPM_REG_SAW_PMIC_DATA_0] = 0x40,
- [MSM_SPM_REG_SAW_PMIC_DATA_1] = 0x44,
- [MSM_SPM_REG_SAW_PMIC_DATA_2] = 0x48,
- [MSM_SPM_REG_SAW_PMIC_DATA_3] = 0x4C,
- [MSM_SPM_REG_SAW_PMIC_DATA_4] = 0x50,
- [MSM_SPM_REG_SAW_PMIC_DATA_5] = 0x54,
- [MSM_SPM_REG_SAW_PMIC_DATA_6] = 0x58,
- [MSM_SPM_REG_SAW_PMIC_DATA_7] = 0x5C,
- [MSM_SPM_REG_SAW_SEQ_ENTRY] = 0x80,
- [MSM_SPM_REG_SAW_VERSION] = 0xFD0,
- };
- static uint32_t msm_spm_reg_offsets_saw2_v3_0[MSM_SPM_REG_NR] = {
- [MSM_SPM_REG_SAW_SECURE] = 0x00,
- [MSM_SPM_REG_SAW_ID] = 0x04,
- [MSM_SPM_REG_SAW_CFG] = 0x08,
- [MSM_SPM_REG_SAW_SPM_STS] = 0x0C,
- [MSM_SPM_REG_SAW_AVS_STS] = 0x10,
- [MSM_SPM_REG_SAW_PMIC_STS] = 0x14,
- [MSM_SPM_REG_SAW_RST] = 0x18,
- [MSM_SPM_REG_SAW_VCTL] = 0x1C,
- [MSM_SPM_REG_SAW_AVS_CTL] = 0x20,
- [MSM_SPM_REG_SAW_AVS_LIMIT] = 0x24,
- [MSM_SPM_REG_SAW_AVS_DLY] = 0x28,
- [MSM_SPM_REG_SAW_AVS_HYSTERESIS] = 0x2C,
- [MSM_SPM_REG_SAW_SPM_CTL] = 0x30,
- [MSM_SPM_REG_SAW_SPM_DLY] = 0x34,
- [MSM_SPM_REG_SAW_STS2] = 0x38,
- [MSM_SPM_REG_SAW_PMIC_DATA_0] = 0x40,
- [MSM_SPM_REG_SAW_PMIC_DATA_1] = 0x44,
- [MSM_SPM_REG_SAW_PMIC_DATA_2] = 0x48,
- [MSM_SPM_REG_SAW_PMIC_DATA_3] = 0x4C,
- [MSM_SPM_REG_SAW_PMIC_DATA_4] = 0x50,
- [MSM_SPM_REG_SAW_PMIC_DATA_5] = 0x54,
- [MSM_SPM_REG_SAW_PMIC_DATA_6] = 0x58,
- [MSM_SPM_REG_SAW_PMIC_DATA_7] = 0x5C,
- [MSM_SPM_REG_SAW_SEQ_ENTRY] = 0x400,
- [MSM_SPM_REG_SAW_VERSION] = 0xFD0,
- };
- static uint32_t msm_spm_reg_offsets_saw2_v4_1[MSM_SPM_REG_NR] = {
- [MSM_SPM_REG_SAW_SECURE] = 0xC00,
- [MSM_SPM_REG_SAW_ID] = 0xC04,
- [MSM_SPM_REG_SAW_STS2] = 0xC10,
- [MSM_SPM_REG_SAW_SPM_STS] = 0xC0C,
- [MSM_SPM_REG_SAW_AVS_STS] = 0xC14,
- [MSM_SPM_REG_SAW_PMIC_STS] = 0xC18,
- [MSM_SPM_REG_SAW_RST] = 0xC1C,
- [MSM_SPM_REG_SAW_VCTL] = 0x900,
- [MSM_SPM_REG_SAW_AVS_CTL] = 0x904,
- [MSM_SPM_REG_SAW_AVS_LIMIT] = 0x908,
- [MSM_SPM_REG_SAW_AVS_DLY] = 0x90C,
- [MSM_SPM_REG_SAW_SPM_CTL] = 0x0,
- [MSM_SPM_REG_SAW_SPM_DLY] = 0x4,
- [MSM_SPM_REG_SAW_CFG] = 0x0C,
- [MSM_SPM_REG_SAW_PMIC_DATA_0] = 0x40,
- [MSM_SPM_REG_SAW_PMIC_DATA_1] = 0x44,
- [MSM_SPM_REG_SAW_PMIC_DATA_2] = 0x48,
- [MSM_SPM_REG_SAW_PMIC_DATA_3] = 0x4C,
- [MSM_SPM_REG_SAW_PMIC_DATA_4] = 0x50,
- [MSM_SPM_REG_SAW_PMIC_DATA_5] = 0x54,
- [MSM_SPM_REG_SAW_SEQ_ENTRY] = 0x400,
- [MSM_SPM_REG_SAW_VERSION] = 0xFD0,
- };
- static struct saw2_data saw2_info[] = {
- [0] = {
- "SAW_v2.1",
- 0x2,
- 0x1,
- msm_spm_reg_offsets_saw2_v2_1,
- },
- [1] = {
- "SAW_v2.3",
- 0x3,
- 0x0,
- msm_spm_reg_offsets_saw2_v3_0,
- },
- [2] = {
- "SAW_v3.0",
- 0x1,
- 0x0,
- msm_spm_reg_offsets_saw2_v3_0,
- },
- [3] = {
- "SAW_v4.0",
- 0x4,
- 0x1,
- msm_spm_reg_offsets_saw2_v4_1,
- },
- };
- static uint32_t num_pmic_data;
- static void msm_spm_drv_flush_shadow(struct msm_spm_driver_data *dev,
- unsigned int reg_index)
- {
- if (!dev || !dev->reg_shadow)
- return;
- __raw_writel(dev->reg_shadow[reg_index],
- dev->reg_base_addr + dev->reg_offsets[reg_index]);
- }
- static void msm_spm_drv_load_shadow(struct msm_spm_driver_data *dev,
- unsigned int reg_index)
- {
- dev->reg_shadow[reg_index] =
- __raw_readl(dev->reg_base_addr +
- dev->reg_offsets[reg_index]);
- }
- static inline uint32_t msm_spm_drv_get_num_spm_entry(
- struct msm_spm_driver_data *dev)
- {
- if (!dev)
- return -ENODEV;
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_ID);
- return (dev->reg_shadow[MSM_SPM_REG_SAW_ID] >> 24) & 0xFF;
- }
- static inline void msm_spm_drv_set_start_addr(
- struct msm_spm_driver_data *dev, uint32_t ctl)
- {
- dev->reg_shadow[MSM_SPM_REG_SAW_SPM_CTL] = ctl;
- }
- static inline bool msm_spm_pmic_arb_present(struct msm_spm_driver_data *dev)
- {
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_ID);
- return (dev->reg_shadow[MSM_SPM_REG_SAW_ID] >> 2) & 0x1;
- }
- static inline void msm_spm_drv_set_vctl2(struct msm_spm_driver_data *dev,
- uint32_t vlevel, uint32_t vctl_port)
- {
- unsigned int pmic_data = 0;
- pmic_data |= vlevel;
- pmic_data |= (vctl_port & 0x7) << 16;
- dev->reg_shadow[MSM_SPM_REG_SAW_VCTL] &= ~0x700FF;
- dev->reg_shadow[MSM_SPM_REG_SAW_VCTL] |= pmic_data;
- dev->reg_shadow[MSM_SPM_REG_SAW_PMIC_DATA_3] &= ~0x700FF;
- dev->reg_shadow[MSM_SPM_REG_SAW_PMIC_DATA_3] |= pmic_data;
- msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_VCTL);
- msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_PMIC_DATA_3);
- }
- static inline uint32_t msm_spm_drv_get_num_pmic_data(
- struct msm_spm_driver_data *dev)
- {
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_ID);
- mb(); /* Ensure we flush */
- return (dev->reg_shadow[MSM_SPM_REG_SAW_ID] >> 4) & 0x7;
- }
- static inline uint32_t msm_spm_drv_get_sts_pmic_state(
- struct msm_spm_driver_data *dev)
- {
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_PMIC_STS);
- return (dev->reg_shadow[MSM_SPM_REG_SAW_PMIC_STS] >> 16) &
- 0x03;
- }
- uint32_t msm_spm_drv_get_sts_curr_pmic_data(
- struct msm_spm_driver_data *dev)
- {
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_PMIC_STS);
- return dev->reg_shadow[MSM_SPM_REG_SAW_PMIC_STS] & 0x300FF;
- }
- static inline void msm_spm_drv_get_saw2_ver(struct msm_spm_driver_data *dev,
- uint32_t *major, uint32_t *minor)
- {
- uint32_t val = 0;
- dev->reg_shadow[MSM_SPM_REG_SAW_VERSION] =
- __raw_readl(dev->reg_base_addr + dev->ver_reg);
- val = dev->reg_shadow[MSM_SPM_REG_SAW_VERSION];
- *major = (val >> 28) & 0xF;
- *minor = (val >> 16) & 0xFFF;
- }
- inline int msm_spm_drv_set_spm_enable(
- struct msm_spm_driver_data *dev, bool enable)
- {
- uint32_t value = enable ? 0x01 : 0x00;
- if (!dev)
- return -EINVAL;
- if ((dev->reg_shadow[MSM_SPM_REG_SAW_SPM_CTL] & 0x01) ^ value) {
- dev->reg_shadow[MSM_SPM_REG_SAW_SPM_CTL] &= ~0x1;
- dev->reg_shadow[MSM_SPM_REG_SAW_SPM_CTL] |= value;
- msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_SPM_CTL);
- wmb(); /* Ensure we flush */
- }
- return 0;
- }
- int msm_spm_drv_get_avs_enable(struct msm_spm_driver_data *dev)
- {
- if (!dev)
- return -EINVAL;
- return dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] & 0x01;
- }
- int msm_spm_drv_set_avs_enable(struct msm_spm_driver_data *dev,
- bool enable)
- {
- uint32_t value = enable ? 0x1 : 0x0;
- if (!dev)
- return -EINVAL;
- if ((dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] & 0x1) ^ value) {
- dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] &= ~0x1;
- dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] |= value;
- msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
- }
- return 0;
- }
- int msm_spm_drv_set_avs_limit(struct msm_spm_driver_data *dev,
- uint32_t min_lvl, uint32_t max_lvl)
- {
- uint32_t value = (max_lvl & 0xff) << 16 | (min_lvl & 0xff);
- if (!dev)
- return -EINVAL;
- dev->reg_shadow[MSM_SPM_REG_SAW_AVS_LIMIT] = value;
- msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_LIMIT);
- return 0;
- }
- static int msm_spm_drv_avs_irq_mask(enum msm_spm_avs_irq irq)
- {
- switch (irq) {
- case MSM_SPM_AVS_IRQ_MIN:
- return BIT(1);
- case MSM_SPM_AVS_IRQ_MAX:
- return BIT(2);
- default:
- return -EINVAL;
- }
- }
- int msm_spm_drv_set_avs_irq_enable(struct msm_spm_driver_data *dev,
- enum msm_spm_avs_irq irq, bool enable)
- {
- int mask = msm_spm_drv_avs_irq_mask(irq);
- uint32_t value;
- if (!dev)
- return -EINVAL;
- else if (mask < 0)
- return mask;
- value = enable ? mask : 0;
- if ((dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] & mask) ^ value) {
- dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] &= ~mask;
- dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] |= value;
- msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
- }
- return 0;
- }
- int msm_spm_drv_avs_clear_irq(struct msm_spm_driver_data *dev,
- enum msm_spm_avs_irq irq)
- {
- int mask = msm_spm_drv_avs_irq_mask(irq);
- if (!dev)
- return -EINVAL;
- else if (mask < 0)
- return mask;
- if (dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] & mask) {
- /*
- * The interrupt status is cleared by disabling and then
- * re-enabling the interrupt.
- */
- dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] &= ~mask;
- msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
- dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] |= mask;
- msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
- }
- return 0;
- }
- void msm_spm_drv_flush_seq_entry(struct msm_spm_driver_data *dev)
- {
- int i;
- int num_spm_entry = msm_spm_drv_get_num_spm_entry(dev);
- if (!dev) {
- __WARN();
- return;
- }
- for (i = 0; i < num_spm_entry; i++) {
- __raw_writel(dev->reg_seq_entry_shadow[i],
- dev->reg_base_addr
- + dev->reg_offsets[MSM_SPM_REG_SAW_SEQ_ENTRY]
- + 4 * i);
- }
- mb(); /* Ensure we flush */
- }
- void dump_regs(struct msm_spm_driver_data *dev, int cpu)
- {
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_SPM_STS);
- mb(); /* Ensure we flush */
- pr_err("CPU%d: spm register MSM_SPM_REG_SAW_SPM_STS: 0x%x\n", cpu,
- dev->reg_shadow[MSM_SPM_REG_SAW_SPM_STS]);
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_SPM_CTL);
- mb(); /* Ensure we flush */
- pr_err("CPU%d: spm register MSM_SPM_REG_SAW_SPM_CTL: 0x%x\n", cpu,
- dev->reg_shadow[MSM_SPM_REG_SAW_SPM_CTL]);
- }
- int msm_spm_drv_write_seq_data(struct msm_spm_driver_data *dev,
- uint8_t *cmd, uint32_t *offset)
- {
- uint32_t cmd_w;
- uint32_t offset_w = *offset / 4;
- uint8_t last_cmd;
- if (!cmd)
- return -EINVAL;
- while (1) {
- int i;
- cmd_w = 0;
- last_cmd = 0;
- cmd_w = dev->reg_seq_entry_shadow[offset_w];
- for (i = (*offset % 4); i < 4; i++) {
- last_cmd = *(cmd++);
- cmd_w |= last_cmd << (i * 8);
- (*offset)++;
- if (last_cmd == 0x0f)
- break;
- }
- dev->reg_seq_entry_shadow[offset_w++] = cmd_w;
- if (last_cmd == 0x0f)
- break;
- }
- return 0;
- }
- int msm_spm_drv_set_low_power_mode(struct msm_spm_driver_data *dev,
- uint32_t ctl)
- {
- /* SPM is configured to reset start address to zero after end of Program
- */
- if (!dev)
- return -EINVAL;
- msm_spm_drv_set_start_addr(dev, ctl);
- msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_SPM_CTL);
- wmb(); /* Ensure we flush */
- if (msm_spm_debug_mask & MSM_SPM_DEBUG_SHADOW) {
- int i;
- for (i = 0; i < MSM_SPM_REG_NR; i++)
- pr_info("%s: reg %02x = 0x%08x\n", __func__,
- dev->reg_offsets[i], dev->reg_shadow[i]);
- }
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_SPM_STS);
- return 0;
- }
- uint32_t msm_spm_drv_get_vdd(struct msm_spm_driver_data *dev)
- {
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_PMIC_STS);
- return dev->reg_shadow[MSM_SPM_REG_SAW_PMIC_STS] & 0xFF;
- }
- #ifdef CONFIG_MSM_AVS_HW
- static bool msm_spm_drv_is_avs_enabled(struct msm_spm_driver_data *dev)
- {
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
- return dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] & BIT(0);
- }
- static void msm_spm_drv_disable_avs(struct msm_spm_driver_data *dev)
- {
- msm_spm_drv_load_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
- dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] &= ~BIT(27);
- msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
- }
- static void msm_spm_drv_enable_avs(struct msm_spm_driver_data *dev)
- {
- dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] |= BIT(27);
- msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
- }
- static void msm_spm_drv_set_avs_vlevel(struct msm_spm_driver_data *dev,
- unsigned int vlevel)
- {
- vlevel &= 0x3f;
- dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] &= ~0x7efc00;
- dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] |= ((vlevel - 4) << 10);
- dev->reg_shadow[MSM_SPM_REG_SAW_AVS_CTL] |= (vlevel << 17);
- msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_AVS_CTL);
- }
- #else
- static bool msm_spm_drv_is_avs_enabled(struct msm_spm_driver_data *dev)
- {
- return false;
- }
- static void msm_spm_drv_disable_avs(struct msm_spm_driver_data *dev) { }
- static void msm_spm_drv_enable_avs(struct msm_spm_driver_data *dev) { }
- static void msm_spm_drv_set_avs_vlevel(struct msm_spm_driver_data *dev,
- unsigned int vlevel) { }
- #endif
- static inline int msm_spm_drv_validate_data(struct msm_spm_driver_data *dev,
- unsigned int vlevel, int vctl_port)
- {
- int timeout_us = dev->vctl_timeout_us;
- uint32_t new_level;
- /* Confirm the voltage we set was what hardware sent and
- * FSM is idle.
- */
- do {
- udelay(1);
- new_level = msm_spm_drv_get_sts_curr_pmic_data(dev);
- /**
- * VCTL_PORT has to be 0, for vlevel to be updated.
- * If port is not 0, check for PMIC_STATE only.
- */
- if (((new_level & 0x30000) == MSM_SPM_PMIC_STATE_IDLE) &&
- (vctl_port || ((new_level & 0xFF) == vlevel)))
- break;
- } while (--timeout_us);
- if (!timeout_us) {
- pr_err("Wrong level %#x\n", new_level);
- return -EIO;
- }
- if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
- pr_info("%s: done, remaining timeout %u us\n",
- __func__, timeout_us);
- return 0;
- }
- int msm_spm_drv_set_vdd(struct msm_spm_driver_data *dev, unsigned int vlevel)
- {
- uint32_t vlevel_set = vlevel;
- bool avs_enabled;
- int ret = 0;
- if (!dev)
- return -EINVAL;
- avs_enabled = msm_spm_drv_is_avs_enabled(dev);
- if (!msm_spm_pmic_arb_present(dev))
- return -ENODEV;
- if (msm_spm_debug_mask & MSM_SPM_DEBUG_VCTL)
- pr_info("%s: requesting vlevel %#x\n", __func__, vlevel);
- if (avs_enabled)
- msm_spm_drv_disable_avs(dev);
- if (dev->vctl_port_ub >= 0) {
- /**
- * VCTL can send 8bit voltage level at once.
- * Send lower 8bit first, vlevel change happens
- * when upper 8bit is sent.
- */
- vlevel = vlevel_set & 0xFF;
- }
- /* Kick the state machine back to idle */
- dev->reg_shadow[MSM_SPM_REG_SAW_RST] = 1;
- msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_RST);
- msm_spm_drv_set_vctl2(dev, vlevel, dev->vctl_port);
- ret = msm_spm_drv_validate_data(dev, vlevel, dev->vctl_port);
- if (ret)
- goto set_vdd_bail;
- if (dev->vctl_port_ub >= 0) {
- /* Send upper 8bit of voltage level */
- vlevel = (vlevel_set >> 8) & 0xFF;
- /* Kick the state machine back to idle */
- dev->reg_shadow[MSM_SPM_REG_SAW_RST] = 1;
- msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_RST);
- /*
- * Steps for sending for vctl port other than '0'
- * Write VCTL register with pmic data and address index
- * Perform system barrier
- * Wait for 1us
- * Read PMIC_STS register to make sure operation is complete
- */
- msm_spm_drv_set_vctl2(dev, vlevel, dev->vctl_port_ub);
- mb(); /* To make sure data is sent before checking status */
- ret = msm_spm_drv_validate_data(dev, vlevel, dev->vctl_port_ub);
- if (ret)
- goto set_vdd_bail;
- }
- /* Set AVS min/max */
- if (avs_enabled) {
- msm_spm_drv_set_avs_vlevel(dev, vlevel_set);
- msm_spm_drv_enable_avs(dev);
- }
- return ret;
- set_vdd_bail:
- if (avs_enabled)
- msm_spm_drv_enable_avs(dev);
- pr_err("%s: failed %#x vlevel setting in timeout %uus\n",
- __func__, vlevel_set, dev->vctl_timeout_us);
- return -EIO;
- }
- static int msm_spm_drv_get_pmic_port(struct msm_spm_driver_data *dev,
- enum msm_spm_pmic_port port)
- {
- int index = -1;
- switch (port) {
- case MSM_SPM_PMIC_VCTL_PORT:
- index = dev->vctl_port;
- break;
- case MSM_SPM_PMIC_PHASE_PORT:
- index = dev->phase_port;
- break;
- case MSM_SPM_PMIC_PFM_PORT:
- index = dev->pfm_port;
- break;
- default:
- break;
- }
- return index;
- }
- int msm_spm_drv_set_pmic_data(struct msm_spm_driver_data *dev,
- enum msm_spm_pmic_port port, unsigned int data)
- {
- unsigned int pmic_data = 0;
- unsigned int timeout_us = 0;
- int index = 0;
- if (!msm_spm_pmic_arb_present(dev))
- return -ENODEV;
- index = msm_spm_drv_get_pmic_port(dev, port);
- if (index < 0)
- return -ENODEV;
- pmic_data |= data & 0xFF;
- pmic_data |= (index & 0x7) << 16;
- dev->reg_shadow[MSM_SPM_REG_SAW_VCTL] &= ~0x700FF;
- dev->reg_shadow[MSM_SPM_REG_SAW_VCTL] |= pmic_data;
- msm_spm_drv_flush_shadow(dev, MSM_SPM_REG_SAW_VCTL);
- mb(); /* Ensure we flush */
- timeout_us = dev->vctl_timeout_us;
- /**
- * Confirm the pmic data set was what hardware sent by
- * checking the PMIC FSM state.
- * We cannot use the sts_pmic_data and check it against
- * the value like we do fot set_vdd, since the PMIC_STS
- * is only updated for SAW_VCTL sent with port index 0.
- */
- do {
- if (msm_spm_drv_get_sts_pmic_state(dev) ==
- MSM_SPM_PMIC_STATE_IDLE)
- break;
- udelay(1);
- } while (--timeout_us);
- if (!timeout_us) {
- pr_err("%s: failed, remaining timeout %u us, data %d\n",
- __func__, timeout_us, data);
- return -EIO;
- }
- return 0;
- }
- void msm_spm_drv_reinit(struct msm_spm_driver_data *dev, bool seq_write)
- {
- int i;
- if (seq_write)
- msm_spm_drv_flush_seq_entry(dev);
- for (i = 0; i < MSM_SPM_REG_SAW_PMIC_DATA_0 + num_pmic_data; i++)
- msm_spm_drv_load_shadow(dev, i);
- for (i = MSM_SPM_REG_NR_INITIALIZE + 1; i < MSM_SPM_REG_NR; i++)
- msm_spm_drv_load_shadow(dev, i);
- }
- int msm_spm_drv_reg_init(struct msm_spm_driver_data *dev,
- struct msm_spm_platform_data *data)
- {
- int i;
- bool found = false;
- dev->ver_reg = data->ver_reg;
- dev->reg_base_addr = data->reg_base_addr;
- msm_spm_drv_get_saw2_ver(dev, &dev->major, &dev->minor);
- for (i = 0; i < ARRAY_SIZE(saw2_info); i++)
- if (dev->major == saw2_info[i].major &&
- dev->minor == saw2_info[i].minor) {
- pr_debug("%s: Version found\n",
- saw2_info[i].ver_name);
- dev->reg_offsets = saw2_info[i].spm_reg_offset_ptr;
- found = true;
- break;
- }
- if (!found) {
- pr_err("%s: No SAW version found\n", __func__);
- WARN_ON(!found);
- }
- return 0;
- }
- void msm_spm_drv_upd_reg_shadow(struct msm_spm_driver_data *dev, int id,
- int val)
- {
- dev->reg_shadow[id] = val;
- msm_spm_drv_flush_shadow(dev, id);
- /* Complete the above writes before other accesses */
- mb();
- }
- int msm_spm_drv_init(struct msm_spm_driver_data *dev,
- struct msm_spm_platform_data *data)
- {
- int num_spm_entry;
- if (!dev || !data)
- return -ENODEV;
- dev->vctl_port = data->vctl_port;
- dev->vctl_port_ub = data->vctl_port_ub;
- dev->phase_port = data->phase_port;
- dev->pfm_port = data->pfm_port;
- dev->reg_base_addr = data->reg_base_addr;
- memcpy(dev->reg_shadow, data->reg_init_values,
- sizeof(data->reg_init_values));
- dev->vctl_timeout_us = data->vctl_timeout_us;
- if (!num_pmic_data)
- num_pmic_data = msm_spm_drv_get_num_pmic_data(dev);
- num_spm_entry = msm_spm_drv_get_num_spm_entry(dev);
- dev->reg_seq_entry_shadow =
- kzalloc(sizeof(*dev->reg_seq_entry_shadow) * num_spm_entry,
- GFP_KERNEL);
- if (!dev->reg_seq_entry_shadow)
- return -ENOMEM;
- return 0;
- }
|