Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: tegra: emc: convert tegra2_emc to a platform driver

This is the first step in making it device-tree aware and get rid of the
in-kernel EMC tables (of which there are none in mainline, thankfully).

Changes since v3:

* moved to devm_request_and_ioremap() in probe()

Changes since v2:

* D'oh -- missed a couple of variables that were added, never used and then
later removed in a later patch.

Changes since v1:

* Fixed messed up indentation
* Removed code that should be gone (was added here and removed later in series)

Signed-off-by: Olof Johansson <olof@lixom.net>
Acked-by: Stephen Warren <swarren@nvidia.com>

+107 -30
+69 -23
arch/arm/mach-tegra/tegra2_emc.c
··· 16 16 */ 17 17 18 18 #include <linux/kernel.h> 19 + #include <linux/device.h> 19 20 #include <linux/clk.h> 20 21 #include <linux/err.h> 21 22 #include <linux/io.h> 22 23 #include <linux/module.h> 24 + #include <linux/platform_device.h> 25 + #include <linux/platform_data/tegra_emc.h> 23 26 24 27 #include <mach/iomap.h> 25 28 ··· 35 32 #endif 36 33 module_param(emc_enable, bool, 0644); 37 34 38 - static void __iomem *emc = IO_ADDRESS(TEGRA_EMC_BASE); 39 - static const struct tegra_emc_table *tegra_emc_table; 40 - static int tegra_emc_table_size; 35 + static struct platform_device *emc_pdev; 36 + static void __iomem *emc_regbase; 41 37 42 38 static inline void emc_writel(u32 val, unsigned long addr) 43 39 { 44 - writel(val, emc + addr); 40 + writel(val, emc_regbase + addr); 45 41 } 46 42 47 43 static inline u32 emc_readl(unsigned long addr) 48 44 { 49 - return readl(emc + addr); 45 + return readl(emc_regbase + addr); 50 46 } 51 47 52 48 static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { ··· 100 98 /* Select the closest EMC rate that is higher than the requested rate */ 101 99 long tegra_emc_round_rate(unsigned long rate) 102 100 { 101 + struct tegra_emc_pdata *pdata; 103 102 int i; 104 103 int best = -1; 105 104 unsigned long distance = ULONG_MAX; 106 105 107 - if (!tegra_emc_table) 106 + if (!emc_pdev) 108 107 return -EINVAL; 109 108 110 - if (!emc_enable) 111 - return -EINVAL; 109 + pdata = emc_pdev->dev.platform_data; 112 110 113 111 pr_debug("%s: %lu\n", __func__, rate); 114 112 ··· 118 116 */ 119 117 rate = rate / 2 / 1000; 120 118 121 - for (i = 0; i < tegra_emc_table_size; i++) { 122 - if (tegra_emc_table[i].rate >= rate && 123 - (tegra_emc_table[i].rate - rate) < distance) { 124 - distance = tegra_emc_table[i].rate - rate; 119 + for (i = 0; i < pdata->num_tables; i++) { 120 + if (pdata->tables[i].rate >= rate && 121 + (pdata->tables[i].rate - rate) < distance) { 122 + distance = pdata->tables[i].rate - rate; 125 123 best = i; 126 124 } 127 125 } ··· 129 127 if (best < 0) 130 128 return -EINVAL; 131 129 132 - pr_debug("%s: using %lu\n", __func__, tegra_emc_table[best].rate); 130 + pr_debug("%s: using %lu\n", __func__, pdata->tables[best].rate); 133 131 134 - return tegra_emc_table[best].rate * 2 * 1000; 132 + return pdata->tables[best].rate * 2 * 1000; 135 133 } 136 134 137 135 /* ··· 144 142 */ 145 143 int tegra_emc_set_rate(unsigned long rate) 146 144 { 145 + struct tegra_emc_pdata *pdata; 147 146 int i; 148 147 int j; 149 148 150 - if (!tegra_emc_table) 149 + if (!emc_pdev) 151 150 return -EINVAL; 151 + 152 + pdata = emc_pdev->dev.platform_data; 152 153 153 154 /* 154 155 * The EMC clock rate is twice the bus rate, and the bus rate is ··· 159 154 */ 160 155 rate = rate / 2 / 1000; 161 156 162 - for (i = 0; i < tegra_emc_table_size; i++) 163 - if (tegra_emc_table[i].rate == rate) 157 + for (i = 0; i < pdata->num_tables; i++) 158 + if (pdata->tables[i].rate == rate) 164 159 break; 165 160 166 - if (i >= tegra_emc_table_size) 161 + if (i >= pdata->num_tables) 167 162 return -EINVAL; 168 163 169 164 pr_debug("%s: setting to %lu\n", __func__, rate); 170 165 171 166 for (j = 0; j < TEGRA_EMC_NUM_REGS; j++) 172 - emc_writel(tegra_emc_table[i].regs[j], emc_reg_addr[j]); 167 + emc_writel(pdata->tables[i].regs[j], emc_reg_addr[j]); 173 168 174 - emc_readl(tegra_emc_table[i].regs[TEGRA_EMC_NUM_REGS - 1]); 169 + emc_readl(pdata->tables[i].regs[TEGRA_EMC_NUM_REGS - 1]); 175 170 176 171 return 0; 177 172 } 178 173 179 - void tegra_init_emc(const struct tegra_emc_table *table, int table_size) 174 + static int __devinit tegra_emc_probe(struct platform_device *pdev) 180 175 { 181 - tegra_emc_table = table; 182 - tegra_emc_table_size = table_size; 176 + struct tegra_emc_pdata *pdata; 177 + struct resource *res; 178 + 179 + if (!emc_enable) { 180 + dev_err(&pdev->dev, "disabled per module parameter\n"); 181 + return -ENODEV; 182 + } 183 + 184 + pdata = pdev->dev.platform_data; 185 + 186 + if (!pdata) { 187 + dev_err(&pdev->dev, "missing platform data\n"); 188 + return -ENXIO; 189 + } 190 + 191 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 192 + if (!res) { 193 + dev_err(&pdev->dev, "missing register base\n"); 194 + return -ENOMEM; 195 + } 196 + 197 + emc_regbase = devm_request_and_ioremap(&pdev->dev, res); 198 + if (!emc_regbase) { 199 + dev_err(&pdev->dev, "failed to remap registers\n"); 200 + return -ENOMEM; 201 + } 202 + emc_pdev = pdev; 203 + 204 + return 0; 183 205 } 206 + 207 + static struct platform_driver tegra_emc_driver = { 208 + .driver = { 209 + .name = "tegra-emc", 210 + .owner = THIS_MODULE, 211 + }, 212 + .probe = tegra_emc_probe, 213 + }; 214 + 215 + static int __init tegra_emc_init(void) 216 + { 217 + return platform_driver_register(&tegra_emc_driver); 218 + } 219 + device_initcall(tegra_emc_init);
+4 -7
arch/arm/mach-tegra/tegra2_emc.h
··· 15 15 * 16 16 */ 17 17 18 - #define TEGRA_EMC_NUM_REGS 46 19 - 20 - struct tegra_emc_table { 21 - unsigned long rate; 22 - u32 regs[TEGRA_EMC_NUM_REGS]; 23 - }; 18 + #ifndef __MACH_TEGRA_TEGRA2_EMC_H_ 19 + #define __MACH_TEGRA_TEGRA2_EMC_H 24 20 25 21 int tegra_emc_set_rate(unsigned long rate); 26 22 long tegra_emc_round_rate(unsigned long rate); 27 - void tegra_init_emc(const struct tegra_emc_table *table, int table_size); 23 + 24 + #endif
+34
include/linux/platform_data/tegra_emc.h
··· 1 + /* 2 + * Copyright (C) 2011 Google, Inc. 3 + * 4 + * Author: 5 + * Colin Cross <ccross@android.com> 6 + * Olof Johansson <olof@lixom.net> 7 + * 8 + * This software is licensed under the terms of the GNU General Public 9 + * License version 2, as published by the Free Software Foundation, and 10 + * may be copied, distributed, and modified under those terms. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + * 17 + */ 18 + 19 + #ifndef __TEGRA_EMC_H_ 20 + #define __TEGRA_EMC_H_ 21 + 22 + #define TEGRA_EMC_NUM_REGS 46 23 + 24 + struct tegra_emc_table { 25 + unsigned long rate; 26 + u32 regs[TEGRA_EMC_NUM_REGS]; 27 + }; 28 + 29 + struct tegra_emc_pdata { 30 + int num_tables; 31 + struct tegra_emc_table *tables; 32 + }; 33 + 34 + #endif