linux/arch/ppc/syslib/ppc_sys.c
<<
>>
Prefs
   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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.