1/* 2 * PPC System library functions 3 * 4 * Maintainer: Kumar Gala <galak@kernel.crashing.org> 5 * 6 * Copyright 2005 Freescale Semiconductor Inc. 7 * Copyright 2005 MontaVista, Inc. by Vitaly Bordug <vbordug@ru.mvista.com> 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the 11 * Free Software Foundation; either version 2 of the License, or (at your 12 * option) any later version. 13 */ 14 15#include <linux/string.h> 16#include <linux/bootmem.h> 17#include <asm/ppc_sys.h> 18 19int (*ppc_sys_device_fixup) (struct platform_device * pdev); 20 21static int ppc_sys_inited; 22static int ppc_sys_func_inited; 23 24static const char *ppc_sys_func_names[] = { 25 [PPC_SYS_FUNC_DUMMY] = "dummy", 26 [PPC_SYS_FUNC_ETH] = "eth", 27 [PPC_SYS_FUNC_UART] = "uart", 28 [PPC_SYS_FUNC_HLDC] = "hldc", 29 [PPC_SYS_FUNC_USB] = "usb", 30 [PPC_SYS_FUNC_IRDA] = "irda", 31}; 32 33void __init identify_ppc_sys_by_id(u32 id) 34{ 35 unsigned int i = 0; 36 while (1) { 37 if ((ppc_sys_specs[i].mask & id) == ppc_sys_specs[i].value) 38 break; 39 i++; 40 } 41 42 cur_ppc_sys_spec = &ppc_sys_specs[i]; 43 44 return; 45} 46 47void __init identify_ppc_sys_by_name(char *name) 48{ 49 unsigned int i = 0; 50 while (ppc_sys_specs[i].ppc_sys_name[0]) { 51 if (!strcmp(ppc_sys_specs[i].ppc_sys_name, name)) 52 break; 53 i++; 54 } 55 cur_ppc_sys_spec = &ppc_sys_specs[i]; 56 57 return; 58} 59 60static int __init count_sys_specs(void) 61{ 62 int i = 0; 63 while (ppc_sys_specs[i].ppc_sys_name[0]) 64 i++; 65 return i; 66} 67 68static int __init find_chip_by_name_and_id(char *name, u32 id) 69{ 70 int ret = -1; 71 unsigned int i = 0; 72 unsigned int j = 0; 73 unsigned int dups = 0; 74 75 unsigned char matched[count_sys_specs()]; 76 77 while (ppc_sys_specs[i].ppc_sys_name[0]) { 78 if (!strcmp(ppc_sys_specs[i].ppc_sys_name, name)) 79 matched[j++] = i; 80 i++; 81 } 82 83 ret = i; 84 85 if (j != 0) { 86 for (i = 0; i < j; i++) { 87 if ((ppc_sys_specs[matched[i]].mask & id) == 88 ppc_sys_specs[matched[i]].value) { 89 ret = matched[i]; 90 dups++; 91 } 92 } 93 ret = (dups == 1) ? ret : (-1 * dups); 94 } 95 return ret; 96} 97 98void __init identify_ppc_sys_by_name_and_id(char *name, u32 id) 99{ 100 int i = find_chip_by_name_and_id(name, id); 101 BUG_ON(i < 0); 102 cur_ppc_sys_spec = &ppc_sys_specs[i]; 103} 104 105/* Update all memory resources by paddr, call before platform_device_register */ 106void __init 107ppc_sys_fixup_mem_resource(struct platform_device *pdev, phys_addr_t paddr) 108{ 109 int i; 110 for (i = 0; i < pdev->num_resources; i++) { 111 struct resource *r = &pdev->resource[i]; 112 if (((r->flags & IORESOURCE_MEM) == IORESOURCE_MEM) && 113 ((r->flags & PPC_SYS_IORESOURCE_FIXUPPED) != PPC_SYS_IORESOURCE_FIXUPPED)) { 114 r->start += paddr; 115 r->end += paddr; 116 r->flags |= PPC_SYS_IORESOURCE_FIXUPPED; 117 } 118 } 119} 120 121/* Get platform_data pointer out of platform device, call before platform_device_register */ 122void *__init ppc_sys_get_pdata(enum ppc_sys_devices dev) 123{ 124 return ppc_sys_platform_devices[dev].dev.platform_data; 125} 126 127void ppc_sys_device_remove(enum ppc_sys_devices dev) 128{ 129 unsigned int i; 130 131 if (ppc_sys_inited) { 132 platform_device_unregister(&ppc_sys_platform_devices[dev]); 133 } else { 134 if (cur_ppc_sys_spec == NULL) 135 return; 136 for (i = 0; i < cur_ppc_sys_spec->num_devices; i++) 137 if (cur_ppc_sys_spec->device_list[i] == dev) 138 cur_ppc_sys_spec->device_list[i] = -1; 139 } 140} 141 142/* Platform-notify mapping 143 * Helper function for BSP code to assign board-specific platfom-divice bits 144 */ 145 146void platform_notify_map(const struct platform_notify_dev_map *map, 147 struct device *dev) 148{ 149 struct platform_device *pdev; 150 int len, idx; 151 const char *s; 152 153 /* do nothing if no device or no bus_id */ 154 if (!dev || !dev->bus_id) 155 return; 156 157 /* call per device map */ 158 while (map->bus_id != NULL) { 159 idx = -1; 160 s = strrchr(dev->bus_id, '.'); 161 if (s != NULL) { 162 idx = (int)simple_strtol(s + 1, NULL, 10); 163 len = s - dev->bus_id; 164 } else { 165 s = dev->bus_id; 166 len = strlen(dev->bus_id); 167 } 168 169 if (!strncmp(dev->bus_id, map->bus_id, len)) { 170 pdev = container_of(dev, struct platform_device, dev); 171 map->rtn(pdev, idx); 172 } 173 map++; 174 } 175} 176 177/* 178 Function assignment stuff. 179 Intended to work as follows: 180 the device name defined in foo_devices.c will be concatenated with :"func", 181 where func is string map of respective function from platfom_device_func enum 182 183 The PPC_SYS_FUNC_DUMMY function is intended to remove all assignments, making the device to appear 184 in platform bus with unmodified name. 185 */ 186 187/* 188 Here we'll replace .name pointers with fixed-lenght strings 189 Hereby, this should be called *before* any func stuff triggeded. 190 */ 191void ppc_sys_device_initfunc(void) 192{ 193 int i; 194 const char *name; 195 static char new_names[NUM_PPC_SYS_DEVS][BUS_ID_SIZE]; 196 enum ppc_sys_devices cur_dev; 197 198 /* If inited yet, do nothing */ 199 if (ppc_sys_func_inited) 200 return; 201 202 for (i = 0; i < cur_ppc_sys_spec->num_devices; i++) { 203 if ((cur_dev = cur_ppc_sys_spec->device_list[i]) < 0) 204 continue; 205 206 if (ppc_sys_platform_devices[cur_dev].name) { 207 /*backup name */ 208 name = ppc_sys_platform_devices[cur_dev].name; 209 strlcpy(new_names[i], name, BUS_ID_SIZE); 210 ppc_sys_platform_devices[cur_dev].name = new_names[i]; 211 } 212 } 213 214 ppc_sys_func_inited = 1; 215} 216 217/*The "engine" of the func stuff. Here we either concat specified function string description 218 to the name, or remove it if PPC_SYS_FUNC_DUMMY parameter is passed here*/ 219void ppc_sys_device_setfunc(enum ppc_sys_devices dev, 220 enum platform_device_func func) 221{ 222 char *s; 223 char *name = (char *)ppc_sys_platform_devices[dev].name; 224 char tmp[BUS_ID_SIZE]; 225 226 if (!ppc_sys_func_inited) { 227 printk(KERN_ERR "Unable to alter function - not inited!\n"); 228 return; 229 } 230 231 if (ppc_sys_inited) { 232 platform_device_unregister(&ppc_sys_platform_devices[dev]); 233 } 234 235 if ((s = (char *)strchr(name, ':')) != NULL) { /* reassign */ 236 /* Either change the name after ':' or remove func modifications */ 237 if (func != PPC_SYS_FUNC_DUMMY) 238 strlcpy(s + 1, ppc_sys_func_names[func], BUS_ID_SIZE); 239 else 240 *s = 0; 241 } else if (func != PPC_SYS_FUNC_DUMMY) { 242 /* do assignment if it is not just "clear" request */ 243 sprintf(tmp, "%s:%s", name, ppc_sys_func_names[func]); 244 strlcpy(name, tmp, BUS_ID_SIZE); 245 } 246 247 if (ppc_sys_inited) { 248 platform_device_register(&ppc_sys_platform_devices[dev]); 249 } 250} 251 252void ppc_sys_device_disable(enum ppc_sys_devices dev) 253{ 254 BUG_ON(cur_ppc_sys_spec == NULL); 255 256 /*Check if it is enabled*/ 257 if(!(cur_ppc_sys_spec->config[dev] & PPC_SYS_CONFIG_DISABLED)) { 258 if (ppc_sys_inited) { 259 platform_device_unregister(&ppc_sys_platform_devices[dev]); 260 } 261 cur_ppc_sys_spec->config[dev] |= PPC_SYS_CONFIG_DISABLED; 262 } 263} 264 265void ppc_sys_device_enable(enum ppc_sys_devices dev) 266{ 267 BUG_ON(cur_ppc_sys_spec == NULL); 268 269 /*Check if it is disabled*/ 270 if(cur_ppc_sys_spec->config[dev] & PPC_SYS_CONFIG_DISABLED) { 271 if (ppc_sys_inited) { 272 platform_device_register(&ppc_sys_platform_devices[dev]); 273 } 274 cur_ppc_sys_spec->config[dev] &= ~PPC_SYS_CONFIG_DISABLED; 275 } 276 277} 278 279void ppc_sys_device_enable_all(void) 280{ 281 enum ppc_sys_devices cur_dev; 282 int i; 283 284 for (i = 0; i < cur_ppc_sys_spec->num_devices; i++) { 285 cur_dev = cur_ppc_sys_spec->device_list[i]; 286 ppc_sys_device_enable(cur_dev); 287 } 288} 289 290void ppc_sys_device_disable_all(void) 291{ 292 enum ppc_sys_devices cur_dev; 293 int i; 294 295 for (i = 0; i < cur_ppc_sys_spec->num_devices; i++) { 296 cur_dev = cur_ppc_sys_spec->device_list[i]; 297 ppc_sys_device_disable(cur_dev); 298 } 299} 300 301 302static int __init ppc_sys_init(void) 303{ 304 unsigned int i, dev_id, ret = 0; 305 306 BUG_ON(cur_ppc_sys_spec == NULL); 307 308 for (i = 0; i < cur_ppc_sys_spec->num_devices; i++) { 309 dev_id = cur_ppc_sys_spec->device_list[i]; 310 if ((dev_id != -1) && 311 !(cur_ppc_sys_spec->config[dev_id] & PPC_SYS_CONFIG_DISABLED)) { 312 if (ppc_sys_device_fixup != NULL) 313 ppc_sys_device_fixup(&ppc_sys_platform_devices 314 [dev_id]); 315 if (platform_device_register 316 (&ppc_sys_platform_devices[dev_id])) { 317 ret = 1; 318 printk(KERN_ERR 319 "unable to register device %d\n", 320 dev_id); 321 } 322 } 323 } 324 325 ppc_sys_inited = 1; 326 return ret; 327} 328 329subsys_initcall(ppc_sys_init); 330