Mike Rapoport | 5af244f | 2010-11-15 11:48:33 +0200 | [diff] [blame] | 1 | /* |
| 2 | * arch/arm/mach-dove/mpp.c |
| 3 | * |
| 4 | * MPP functions for Marvell Dove SoCs |
| 5 | * |
| 6 | * This file is licensed under the terms of the GNU General Public |
| 7 | * License version 2. This program is licensed "as is" without any |
| 8 | * warranty of any kind, whether express or implied. |
| 9 | */ |
| 10 | |
| 11 | #include <linux/kernel.h> |
| 12 | #include <linux/gpio.h> |
| 13 | #include <linux/io.h> |
| 14 | |
| 15 | #include <mach/dove.h> |
| 16 | |
| 17 | #include "mpp.h" |
| 18 | |
| 19 | #define MPP_NR_REGS 4 |
| 20 | #define MPP_CTRL(i) ((i) == 3 ? \ |
| 21 | DOVE_MPP_CTRL4_VIRT_BASE : \ |
| 22 | DOVE_MPP_VIRT_BASE + (i) * 4) |
| 23 | #define PMU_SIG_REGS 2 |
| 24 | #define PMU_SIG_CTRL(i) (DOVE_PMU_SIG_CTRL + (i) * 4) |
| 25 | |
| 26 | struct dove_mpp_grp { |
| 27 | int start; |
| 28 | int end; |
| 29 | }; |
| 30 | |
| 31 | static struct dove_mpp_grp dove_mpp_grp[] = { |
| 32 | [MPP_24_39] = { |
| 33 | .start = 24, |
| 34 | .end = 39, |
| 35 | }, |
| 36 | [MPP_40_45] = { |
| 37 | .start = 40, |
| 38 | .end = 45, |
| 39 | }, |
| 40 | [MPP_46_51] = { |
| 41 | .start = 40, |
| 42 | .end = 45, |
| 43 | }, |
| 44 | [MPP_58_61] = { |
| 45 | .start = 58, |
| 46 | .end = 61, |
| 47 | }, |
| 48 | [MPP_62_63] = { |
| 49 | .start = 62, |
| 50 | .end = 63, |
| 51 | }, |
| 52 | }; |
| 53 | |
| 54 | static void dove_mpp_gpio_mode(int start, int end, int gpio_mode) |
| 55 | { |
| 56 | int i; |
| 57 | |
| 58 | for (i = start; i <= end; i++) |
| 59 | orion_gpio_set_valid(i, gpio_mode); |
| 60 | } |
| 61 | |
| 62 | static void dove_mpp_dump_regs(void) |
| 63 | { |
| 64 | #ifdef DEBUG |
| 65 | int i; |
| 66 | |
| 67 | pr_debug("MPP_CTRL regs:"); |
| 68 | for (i = 0; i < MPP_NR_REGS; i++) |
| 69 | printk(" %08x", readl(MPP_CTRL(i))); |
| 70 | printk("\n"); |
| 71 | |
| 72 | pr_debug("PMU_SIG_CTRL regs:"); |
| 73 | for (i = 0; i < PMU_SIG_REGS; i++) |
| 74 | printk(" %08x", readl(PMU_SIG_CTRL(i))); |
| 75 | printk("\n"); |
| 76 | |
| 77 | pr_debug("PMU_MPP_GENERAL_CTRL: %08x\n", readl(DOVE_PMU_MPP_GENERAL_CTRL)); |
| 78 | pr_debug("MPP_GENERAL: %08x\n", readl(DOVE_MPP_GENERAL_VIRT_BASE)); |
| 79 | #endif |
| 80 | } |
| 81 | |
| 82 | static void dove_mpp_cfg_nfc(int sel) |
| 83 | { |
| 84 | u32 mpp_gen_cfg = readl(DOVE_MPP_GENERAL_VIRT_BASE); |
| 85 | |
| 86 | mpp_gen_cfg &= ~0x1; |
| 87 | mpp_gen_cfg |= sel; |
| 88 | writel(mpp_gen_cfg, DOVE_MPP_GENERAL_VIRT_BASE); |
| 89 | |
| 90 | dove_mpp_gpio_mode(64, 71, GPIO_OUTPUT_OK); |
| 91 | } |
| 92 | |
| 93 | static void dove_mpp_cfg_au1(int sel) |
| 94 | { |
| 95 | u32 mpp_ctrl4 = readl(DOVE_MPP_CTRL4_VIRT_BASE); |
| 96 | u32 ssp_ctrl1 = readl(DOVE_SSP_CTRL_STATUS_1); |
| 97 | u32 mpp_gen_ctrl = readl(DOVE_MPP_GENERAL_VIRT_BASE); |
| 98 | u32 global_cfg_2 = readl(DOVE_GLOBAL_CONFIG_2); |
| 99 | |
| 100 | mpp_ctrl4 &= ~(DOVE_AU1_GPIO_SEL); |
| 101 | ssp_ctrl1 &= ~(DOVE_SSP_ON_AU1); |
| 102 | mpp_gen_ctrl &= ~(DOVE_AU1_SPDIFO_GPIO_EN); |
| 103 | global_cfg_2 &= ~(DOVE_TWSI_OPTION3_GPIO); |
| 104 | |
| 105 | if (!sel || sel == 0x2) |
| 106 | dove_mpp_gpio_mode(52, 57, 0); |
| 107 | else |
| 108 | dove_mpp_gpio_mode(52, 57, GPIO_OUTPUT_OK | GPIO_INPUT_OK); |
| 109 | |
| 110 | if (sel & 0x1) { |
| 111 | global_cfg_2 |= DOVE_TWSI_OPTION3_GPIO; |
| 112 | dove_mpp_gpio_mode(56, 57, 0); |
| 113 | } |
| 114 | if (sel & 0x2) { |
| 115 | mpp_gen_ctrl |= DOVE_AU1_SPDIFO_GPIO_EN; |
| 116 | dove_mpp_gpio_mode(57, 57, GPIO_OUTPUT_OK | GPIO_INPUT_OK); |
| 117 | } |
| 118 | if (sel & 0x4) { |
| 119 | ssp_ctrl1 |= DOVE_SSP_ON_AU1; |
| 120 | dove_mpp_gpio_mode(52, 55, 0); |
| 121 | } |
| 122 | if (sel & 0x8) |
| 123 | mpp_ctrl4 |= DOVE_AU1_GPIO_SEL; |
| 124 | |
| 125 | writel(mpp_ctrl4, DOVE_MPP_CTRL4_VIRT_BASE); |
| 126 | writel(ssp_ctrl1, DOVE_SSP_CTRL_STATUS_1); |
| 127 | writel(mpp_gen_ctrl, DOVE_MPP_GENERAL_VIRT_BASE); |
| 128 | writel(global_cfg_2, DOVE_GLOBAL_CONFIG_2); |
| 129 | } |
| 130 | |
| 131 | static void dove_mpp_conf_grp(int num, int sel, u32 *mpp_ctrl) |
| 132 | { |
| 133 | int start = dove_mpp_grp[num].start; |
| 134 | int end = dove_mpp_grp[num].end; |
| 135 | int gpio_mode = sel ? GPIO_OUTPUT_OK | GPIO_INPUT_OK : 0; |
| 136 | |
| 137 | *mpp_ctrl &= ~(0x1 << num); |
| 138 | *mpp_ctrl |= sel << num; |
| 139 | |
| 140 | dove_mpp_gpio_mode(start, end, gpio_mode); |
| 141 | } |
| 142 | |
| 143 | void __init dove_mpp_conf(unsigned int *mpp_list) |
| 144 | { |
| 145 | u32 mpp_ctrl[MPP_NR_REGS]; |
| 146 | u32 pmu_mpp_ctrl = 0; |
| 147 | u32 pmu_sig_ctrl[PMU_SIG_REGS]; |
| 148 | int i; |
| 149 | |
Mike Rapoport | 5af244f | 2010-11-15 11:48:33 +0200 | [diff] [blame] | 150 | for (i = 0; i < MPP_NR_REGS; i++) |
| 151 | mpp_ctrl[i] = readl(MPP_CTRL(i)); |
| 152 | |
| 153 | for (i = 0; i < PMU_SIG_REGS; i++) |
| 154 | pmu_sig_ctrl[i] = readl(PMU_SIG_CTRL(i)); |
| 155 | |
| 156 | pmu_mpp_ctrl = readl(DOVE_PMU_MPP_GENERAL_CTRL); |
| 157 | |
| 158 | dove_mpp_dump_regs(); |
| 159 | |
| 160 | for ( ; *mpp_list != MPP_END; mpp_list++) { |
| 161 | unsigned int num = MPP_NUM(*mpp_list); |
| 162 | unsigned int sel = MPP_SEL(*mpp_list); |
| 163 | int shift, gpio_mode; |
| 164 | |
| 165 | if (num > MPP_MAX) { |
| 166 | pr_err("dove: invalid MPP number (%u)\n", num); |
| 167 | continue; |
| 168 | } |
| 169 | |
| 170 | if (*mpp_list & MPP_NFC_MASK) { |
| 171 | dove_mpp_cfg_nfc(sel); |
| 172 | continue; |
| 173 | } |
| 174 | |
| 175 | if (*mpp_list & MPP_AU1_MASK) { |
| 176 | dove_mpp_cfg_au1(sel); |
| 177 | continue; |
| 178 | } |
| 179 | |
| 180 | if (*mpp_list & MPP_GRP_MASK) { |
| 181 | dove_mpp_conf_grp(num, sel, &mpp_ctrl[3]); |
| 182 | continue; |
| 183 | } |
| 184 | |
| 185 | shift = (num & 7) << 2; |
| 186 | if (*mpp_list & MPP_PMU_MASK) { |
| 187 | pmu_mpp_ctrl |= (0x1 << num); |
| 188 | pmu_sig_ctrl[num / 8] &= ~(0xf << shift); |
| 189 | pmu_sig_ctrl[num / 8] |= 0xf << shift; |
| 190 | gpio_mode = 0; |
| 191 | } else { |
| 192 | mpp_ctrl[num / 8] &= ~(0xf << shift); |
| 193 | mpp_ctrl[num / 8] |= sel << shift; |
| 194 | gpio_mode = GPIO_OUTPUT_OK | GPIO_INPUT_OK; |
| 195 | } |
| 196 | |
| 197 | orion_gpio_set_valid(num, gpio_mode); |
| 198 | } |
| 199 | |
| 200 | for (i = 0; i < MPP_NR_REGS; i++) |
| 201 | writel(mpp_ctrl[i], MPP_CTRL(i)); |
| 202 | |
| 203 | for (i = 0; i < PMU_SIG_REGS; i++) |
| 204 | writel(pmu_sig_ctrl[i], PMU_SIG_CTRL(i)); |
| 205 | |
| 206 | writel(pmu_mpp_ctrl, DOVE_PMU_MPP_GENERAL_CTRL); |
| 207 | |
| 208 | dove_mpp_dump_regs(); |
| 209 | } |