blob: 1b6c8b0d2e5bc9642ea20c6e7e4d14c5d094a340 [file] [log] [blame]
Channagoud Kadabiafb8e172013-05-23 13:55:47 -07001/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <platform/iomap.h>
30#include <platform/irqs.h>
31#include <platform/interrupts.h>
32#include <platform/timer.h>
33#include <target.h>
34#include <string.h>
35#include <stdlib.h>
36#include <bits.h>
37#include <debug.h>
38#include <sdhci.h>
39#include <sdhci_msm.h>
40
41
42/*
43 * Function: sdhci int handler
44 * Arg : MSM specific data for sdhci
45 * Return : 0
46 * Flow: : 1. Read the power control mask register
47 * 2. Check if bus is ON
48 * 3. Write success to ack regiser
49 * Details : This is power control interrupt handler.
50 * Once we receive the interrupt, we will ack the power control
51 * register that we have successfully completed pmic transactions
52 */
53static enum handler_return sdhci_int_handler(struct sdhci_msm_data *data)
54{
55 uint32_t ack;
56 uint32_t status;
57
58 /*
59 * Read the mask register to check if BUS & IO level
60 * interrupts are enabled
61 */
62 status = readl(data->pwrctl_base + SDCC_HC_PWRCTL_MASK_REG);
63
64 if (status & (SDCC_HC_BUS_ON | SDCC_HC_BUS_OFF))
65 ack = SDCC_HC_BUS_ON_OFF_SUCC;
66 if (status & (SDCC_HC_IO_SIG_LOW | SDCC_HC_IO_SIG_HIGH))
67 ack |= SDCC_HC_IO_SIG_SUCC;
68
69 /* Write success to power control register */
70 writel(ack, (data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG));
71
72 event_signal(data->sdhc_event, false);
73
74 return 0;
75}
76
77/*
78 * Function: sdhci clear pending interrupts
79 * Arg : MSM specific data for sdhci
80 * Return : None
81 * Flow: : Clear pending interrupts
82 */
83static void sdhci_clear_power_ctrl_irq(struct sdhci_msm_data *data)
84{
85 uint32_t irq_ctl;
86 uint32_t irq_stat;
87
88 /*
89 * Read the power control status register to know
90 * the status of BUS & IO_HIGH_V
91 */
92 irq_stat = readl(data->pwrctl_base + SDCC_HC_PWRCTL_STATUS_REG);
93
94 /* Clear the power control status */
95 writel(irq_stat, (data->pwrctl_base + SDCC_HC_PWRCTL_CLEAR_REG));
96
97 /*
98 * Handle the pending irq by ack'ing the bus & IO switch
99 */
100 irq_ctl = readl(data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG);
101
102 if (irq_stat & (SDCC_HC_BUS_ON | SDCC_HC_BUS_OFF))
103 irq_ctl |= SDCC_HC_BUS_ON_OFF_SUCC;
104 if (irq_stat & (SDCC_HC_IO_SIG_LOW | SDCC_HC_IO_SIG_HIGH))
105 irq_ctl |= SDCC_HC_IO_SIG_SUCC;
106
107 writel(irq_ctl, (data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG));
108}
109
110/*
111 * Function: sdhci msm init
112 * Arg : MSM specific config data for sdhci
113 * Return : None
114 * Flow: : Enable sdhci mode & do msm specific init
115 */
116void sdhci_msm_init(struct sdhci_msm_data *config)
117{
118 /* Enable sdhc mode */
119 writel(SDHCI_HC_MODE_EN, (config->pwrctl_base + SDCC_MCI_HC_MODE));
120
121 /*
122 * CORE_SW_RST may trigger power irq if previous status of PWRCTL
123 * was either BUS_ON or IO_HIGH. So before we enable the power irq
124 * interrupt in GIC (by registering the interrupt handler), we need to
125 * ensure that any pending power irq interrupt status is acknowledged
126 * otherwise power irq interrupt handler would be fired prematurely.
127 */
128 sdhci_clear_power_ctrl_irq(config);
129
130 /*
131 * Register the interrupt handler for pwr irq
132 */
133 register_int_handler(config->pwr_irq, sdhci_int_handler, (void *)config);
134
135 unmask_interrupt(config->pwr_irq);
136
137 /* Enable pwr control interrupt */
138 writel(SDCC_HC_PWR_CTRL_INT, (config->pwrctl_base + SDCC_HC_PWRCTL_MASK_REG));
139}