linux/arch/mips/ar7/platform.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org>
   3 * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.org>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  18 */
  19
  20#include <linux/init.h>
  21#include <linux/types.h>
  22#include <linux/module.h>
  23#include <linux/delay.h>
  24#include <linux/dma-mapping.h>
  25#include <linux/platform_device.h>
  26#include <linux/mtd/physmap.h>
  27#include <linux/serial.h>
  28#include <linux/serial_8250.h>
  29#include <linux/ioport.h>
  30#include <linux/io.h>
  31#include <linux/vlynq.h>
  32#include <linux/leds.h>
  33#include <linux/string.h>
  34#include <linux/etherdevice.h>
  35#include <linux/phy.h>
  36#include <linux/phy_fixed.h>
  37#include <linux/gpio.h>
  38#include <linux/clk.h>
  39
  40#include <asm/addrspace.h>
  41#include <asm/mach-ar7/ar7.h>
  42#include <asm/mach-ar7/gpio.h>
  43#include <asm/mach-ar7/prom.h>
  44
  45/*****************************************************************************
  46 * VLYNQ Bus
  47 ****************************************************************************/
  48struct plat_vlynq_data {
  49        struct plat_vlynq_ops ops;
  50        int gpio_bit;
  51        int reset_bit;
  52};
  53
  54static int vlynq_on(struct vlynq_device *dev)
  55{
  56        int ret;
  57        struct plat_vlynq_data *pdata = dev->dev.platform_data;
  58
  59        ret = gpio_request(pdata->gpio_bit, "vlynq");
  60        if (ret)
  61                goto out;
  62
  63        ar7_device_reset(pdata->reset_bit);
  64
  65        ret = ar7_gpio_disable(pdata->gpio_bit);
  66        if (ret)
  67                goto out_enabled;
  68
  69        ret = ar7_gpio_enable(pdata->gpio_bit);
  70        if (ret)
  71                goto out_enabled;
  72
  73        ret = gpio_direction_output(pdata->gpio_bit, 0);
  74        if (ret)
  75                goto out_gpio_enabled;
  76
  77        msleep(50);
  78
  79        gpio_set_value(pdata->gpio_bit, 1);
  80
  81        msleep(50);
  82
  83        return 0;
  84
  85out_gpio_enabled:
  86        ar7_gpio_disable(pdata->gpio_bit);
  87out_enabled:
  88        ar7_device_disable(pdata->reset_bit);
  89        gpio_free(pdata->gpio_bit);
  90out:
  91        return ret;
  92}
  93
  94static void vlynq_off(struct vlynq_device *dev)
  95{
  96        struct plat_vlynq_data *pdata = dev->dev.platform_data;
  97
  98        ar7_gpio_disable(pdata->gpio_bit);
  99        gpio_free(pdata->gpio_bit);
 100        ar7_device_disable(pdata->reset_bit);
 101}
 102
 103static struct resource vlynq_low_res[] = {
 104        {
 105                .name   = "regs",
 106                .flags  = IORESOURCE_MEM,
 107                .start  = AR7_REGS_VLYNQ0,
 108                .end    = AR7_REGS_VLYNQ0 + 0xff,
 109        },
 110        {
 111                .name   = "irq",
 112                .flags  = IORESOURCE_IRQ,
 113                .start  = 29,
 114                .end    = 29,
 115        },
 116        {
 117                .name   = "mem",
 118                .flags  = IORESOURCE_MEM,
 119                .start  = 0x04000000,
 120                .end    = 0x04ffffff,
 121        },
 122        {
 123                .name   = "devirq",
 124                .flags  = IORESOURCE_IRQ,
 125                .start  = 80,
 126                .end    = 111,
 127        },
 128};
 129
 130static struct resource vlynq_high_res[] = {
 131        {
 132                .name   = "regs",
 133                .flags  = IORESOURCE_MEM,
 134                .start  = AR7_REGS_VLYNQ1,
 135                .end    = AR7_REGS_VLYNQ1 + 0xff,
 136        },
 137        {
 138                .name   = "irq",
 139                .flags  = IORESOURCE_IRQ,
 140                .start  = 33,
 141                .end    = 33,
 142        },
 143        {
 144                .name   = "mem",
 145                .flags  = IORESOURCE_MEM,
 146                .start  = 0x0c000000,
 147                .end    = 0x0cffffff,
 148        },
 149        {
 150                .name   = "devirq",
 151                .flags  = IORESOURCE_IRQ,
 152                .start  = 112,
 153                .end    = 143,
 154        },
 155};
 156
 157static struct plat_vlynq_data vlynq_low_data = {
 158        .ops = {
 159                .on     = vlynq_on,
 160                .off    = vlynq_off,
 161        },
 162        .reset_bit      = 20,
 163        .gpio_bit       = 18,
 164};
 165
 166static struct plat_vlynq_data vlynq_high_data = {
 167        .ops = {
 168                .on     = vlynq_on,
 169                .off    = vlynq_off,
 170        },
 171        .reset_bit      = 16,
 172        .gpio_bit       = 19,
 173};
 174
 175static struct platform_device vlynq_low = {
 176        .id             = 0,
 177        .name           = "vlynq",
 178        .dev = {
 179                .platform_data  = &vlynq_low_data,
 180        },
 181        .resource       = vlynq_low_res,
 182        .num_resources  = ARRAY_SIZE(vlynq_low_res),
 183};
 184
 185static struct platform_device vlynq_high = {
 186        .id             = 1,
 187        .name           = "vlynq",
 188        .dev = {
 189                .platform_data  = &vlynq_high_data,
 190        },
 191        .resource       = vlynq_high_res,
 192        .num_resources  = ARRAY_SIZE(vlynq_high_res),
 193};
 194
 195/*****************************************************************************
 196 * Flash
 197 ****************************************************************************/
 198static struct resource physmap_flash_resource = {
 199        .name   = "mem",
 200        .flags  = IORESOURCE_MEM,
 201        .start  = 0x10000000,
 202        .end    = 0x107fffff,
 203};
 204
 205static struct physmap_flash_data physmap_flash_data = {
 206        .width  = 2,
 207};
 208
 209static struct platform_device physmap_flash = {
 210        .name           = "physmap-flash",
 211        .dev = {
 212                .platform_data  = &physmap_flash_data,
 213        },
 214        .resource       = &physmap_flash_resource,
 215        .num_resources  = 1,
 216};
 217
 218/*****************************************************************************
 219 * Ethernet
 220 ****************************************************************************/
 221static struct resource cpmac_low_res[] = {
 222        {
 223                .name   = "regs",
 224                .flags  = IORESOURCE_MEM,
 225                .start  = AR7_REGS_MAC0,
 226                .end    = AR7_REGS_MAC0 + 0x7ff,
 227        },
 228        {
 229                .name   = "irq",
 230                .flags  = IORESOURCE_IRQ,
 231                .start  = 27,
 232                .end    = 27,
 233        },
 234};
 235
 236static struct resource cpmac_high_res[] = {
 237        {
 238                .name   = "regs",
 239                .flags  = IORESOURCE_MEM,
 240                .start  = AR7_REGS_MAC1,
 241                .end    = AR7_REGS_MAC1 + 0x7ff,
 242        },
 243        {
 244                .name   = "irq",
 245                .flags  = IORESOURCE_IRQ,
 246                .start  = 41,
 247                .end    = 41,
 248        },
 249};
 250
 251static struct fixed_phy_status fixed_phy_status __initdata = {
 252        .link           = 1,
 253        .speed          = 100,
 254        .duplex         = 1,
 255};
 256
 257static struct plat_cpmac_data cpmac_low_data = {
 258        .reset_bit      = 17,
 259        .power_bit      = 20,
 260        .phy_mask       = 0x80000000,
 261};
 262
 263static struct plat_cpmac_data cpmac_high_data = {
 264        .reset_bit      = 21,
 265        .power_bit      = 22,
 266        .phy_mask       = 0x7fffffff,
 267};
 268
 269static u64 cpmac_dma_mask = DMA_BIT_MASK(32);
 270
 271static struct platform_device cpmac_low = {
 272        .id             = 0,
 273        .name           = "cpmac",
 274        .dev = {
 275                .dma_mask               = &cpmac_dma_mask,
 276                .coherent_dma_mask      = DMA_BIT_MASK(32),
 277                .platform_data          = &cpmac_low_data,
 278        },
 279        .resource       = cpmac_low_res,
 280        .num_resources  = ARRAY_SIZE(cpmac_low_res),
 281};
 282
 283static struct platform_device cpmac_high = {
 284        .id             = 1,
 285        .name           = "cpmac",
 286        .dev = {
 287                .dma_mask               = &cpmac_dma_mask,
 288                .coherent_dma_mask      = DMA_BIT_MASK(32),
 289                .platform_data          = &cpmac_high_data,
 290        },
 291        .resource       = cpmac_high_res,
 292        .num_resources  = ARRAY_SIZE(cpmac_high_res),
 293};
 294
 295static void __init cpmac_get_mac(int instance, unsigned char *dev_addr)
 296{
 297        char name[5], *mac;
 298
 299        sprintf(name, "mac%c", 'a' + instance);
 300        mac = prom_getenv(name);
 301        if (!mac && instance) {
 302                sprintf(name, "mac%c", 'a');
 303                mac = prom_getenv(name);
 304        }
 305
 306        if (mac) {
 307                if (sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
 308                                        &dev_addr[0], &dev_addr[1],
 309                                        &dev_addr[2], &dev_addr[3],
 310                                        &dev_addr[4], &dev_addr[5]) != 6) {
 311                        pr_warning("cannot parse mac address, "
 312                                        "using random address\n");
 313                        random_ether_addr(dev_addr);
 314                }
 315        } else
 316                random_ether_addr(dev_addr);
 317}
 318
 319/*****************************************************************************
 320 * USB
 321 ****************************************************************************/
 322static struct resource usb_res[] = {
 323        {
 324                .name   = "regs",
 325                .flags  = IORESOURCE_MEM,
 326                .start  = AR7_REGS_USB,
 327                .end    = AR7_REGS_USB + 0xff,
 328        },
 329        {
 330                .name   = "irq",
 331                .flags  = IORESOURCE_IRQ,
 332                .start  = 32,
 333                .end    = 32,
 334        },
 335        {
 336                .name   = "mem",
 337                .flags  = IORESOURCE_MEM,
 338                .start  = 0x03400000,
 339                .end    = 0x03401fff,
 340        },
 341};
 342
 343static struct platform_device ar7_udc = {
 344        .name           = "ar7_udc",
 345        .resource       = usb_res,
 346        .num_resources  = ARRAY_SIZE(usb_res),
 347};
 348
 349/*****************************************************************************
 350 * LEDs
 351 ****************************************************************************/
 352static struct gpio_led default_leds[] = {
 353        {
 354                .name                   = "status",
 355                .gpio                   = 8,
 356                .active_low             = 1,
 357        },
 358};
 359
 360static struct gpio_led titan_leds[] = {
 361        { .name = "status", .gpio = 8, .active_low = 1, },
 362        { .name = "wifi", .gpio = 13, .active_low = 1, },
 363};
 364
 365static struct gpio_led dsl502t_leds[] = {
 366        {
 367                .name                   = "status",
 368                .gpio                   = 9,
 369                .active_low             = 1,
 370        },
 371        {
 372                .name                   = "ethernet",
 373                .gpio                   = 7,
 374                .active_low             = 1,
 375        },
 376        {
 377                .name                   = "usb",
 378                .gpio                   = 12,
 379                .active_low             = 1,
 380        },
 381};
 382
 383static struct gpio_led dg834g_leds[] = {
 384        {
 385                .name                   = "ppp",
 386                .gpio                   = 6,
 387                .active_low             = 1,
 388        },
 389        {
 390                .name                   = "status",
 391                .gpio                   = 7,
 392                .active_low             = 1,
 393        },
 394        {
 395                .name                   = "adsl",
 396                .gpio                   = 8,
 397                .active_low             = 1,
 398        },
 399        {
 400                .name                   = "wifi",
 401                .gpio                   = 12,
 402                .active_low             = 1,
 403        },
 404        {
 405                .name                   = "power",
 406                .gpio                   = 14,
 407                .active_low             = 1,
 408                .default_trigger        = "default-on",
 409        },
 410};
 411
 412static struct gpio_led fb_sl_leds[] = {
 413        {
 414                .name                   = "1",
 415                .gpio                   = 7,
 416        },
 417        {
 418                .name                   = "2",
 419                .gpio                   = 13,
 420                .active_low             = 1,
 421        },
 422        {
 423                .name                   = "3",
 424                .gpio                   = 10,
 425                .active_low             = 1,
 426        },
 427        {
 428                .name                   = "4",
 429                .gpio                   = 12,
 430                .active_low             = 1,
 431        },
 432        {
 433                .name                   = "5",
 434                .gpio                   = 9,
 435                .active_low             = 1,
 436        },
 437};
 438
 439static struct gpio_led fb_fon_leds[] = {
 440        {
 441                .name                   = "1",
 442                .gpio                   = 8,
 443        },
 444        {
 445                .name                   = "2",
 446                .gpio                   = 3,
 447                .active_low             = 1,
 448        },
 449        {
 450                .name                   = "3",
 451                .gpio                   = 5,
 452        },
 453        {
 454                .name                   = "4",
 455                .gpio                   = 4,
 456                .active_low             = 1,
 457        },
 458        {
 459                .name                   = "5",
 460                .gpio                   = 11,
 461                .active_low             = 1,
 462        },
 463};
 464
 465static struct gpio_led_platform_data ar7_led_data;
 466
 467static struct platform_device ar7_gpio_leds = {
 468        .name = "leds-gpio",
 469        .dev = {
 470                .platform_data = &ar7_led_data,
 471        }
 472};
 473
 474static void __init detect_leds(void)
 475{
 476        char *prid, *usb_prod;
 477
 478        /* Default LEDs */
 479        ar7_led_data.num_leds = ARRAY_SIZE(default_leds);
 480        ar7_led_data.leds = default_leds;
 481
 482        /* FIXME: the whole thing is unreliable */
 483        prid = prom_getenv("ProductID");
 484        usb_prod = prom_getenv("usb_prod");
 485
 486        /* If we can't get the product id from PROM, use the default LEDs */
 487        if (!prid)
 488                return;
 489
 490        if (strstr(prid, "Fritz_Box_FON")) {
 491                ar7_led_data.num_leds = ARRAY_SIZE(fb_fon_leds);
 492                ar7_led_data.leds = fb_fon_leds;
 493        } else if (strstr(prid, "Fritz_Box_")) {
 494                ar7_led_data.num_leds = ARRAY_SIZE(fb_sl_leds);
 495                ar7_led_data.leds = fb_sl_leds;
 496        } else if ((!strcmp(prid, "AR7RD") || !strcmp(prid, "AR7DB"))
 497                && usb_prod != NULL && strstr(usb_prod, "DSL-502T")) {
 498                ar7_led_data.num_leds = ARRAY_SIZE(dsl502t_leds);
 499                ar7_led_data.leds = dsl502t_leds;
 500        } else if (strstr(prid, "DG834")) {
 501                ar7_led_data.num_leds = ARRAY_SIZE(dg834g_leds);
 502                ar7_led_data.leds = dg834g_leds;
 503        } else if (strstr(prid, "CYWM") || strstr(prid, "CYWL")) {
 504                ar7_led_data.num_leds = ARRAY_SIZE(titan_leds);
 505                ar7_led_data.leds = titan_leds;
 506        }
 507}
 508
 509/*****************************************************************************
 510 * Watchdog
 511 ****************************************************************************/
 512static struct resource ar7_wdt_res = {
 513        .name           = "regs",
 514        .flags          = IORESOURCE_MEM,
 515        .start          = -1,   /* Filled at runtime */
 516        .end            = -1,   /* Filled at runtime */
 517};
 518
 519static struct platform_device ar7_wdt = {
 520        .name           = "ar7_wdt",
 521        .resource       = &ar7_wdt_res,
 522        .num_resources  = 1,
 523};
 524
 525/*****************************************************************************
 526 * Init
 527 ****************************************************************************/
 528static int __init ar7_register_uarts(void)
 529{
 530#ifdef CONFIG_SERIAL_8250
 531        static struct uart_port uart_port __initdata;
 532        struct clk *bus_clk;
 533        int res;
 534
 535        memset(&uart_port, 0, sizeof(struct uart_port));
 536
 537        bus_clk = clk_get(NULL, "bus");
 538        if (IS_ERR(bus_clk))
 539                panic("unable to get bus clk\n");
 540
 541        uart_port.type          = PORT_AR7;
 542        uart_port.uartclk       = clk_get_rate(bus_clk) / 2;
 543        uart_port.iotype        = UPIO_MEM32;
 544        uart_port.regshift      = 2;
 545
 546        uart_port.line          = 0;
 547        uart_port.irq           = AR7_IRQ_UART0;
 548        uart_port.mapbase       = AR7_REGS_UART0;
 549        uart_port.membase       = ioremap(uart_port.mapbase, 256);
 550
 551        res = early_serial_setup(&uart_port);
 552        if (res)
 553                return res;
 554
 555        /* Only TNETD73xx have a second serial port */
 556        if (ar7_has_second_uart()) {
 557                uart_port.line          = 1;
 558                uart_port.irq           = AR7_IRQ_UART1;
 559                uart_port.mapbase       = UR8_REGS_UART1;
 560                uart_port.membase       = ioremap(uart_port.mapbase, 256);
 561
 562                res = early_serial_setup(&uart_port);
 563                if (res)
 564                        return res;
 565        }
 566#endif
 567
 568        return 0;
 569}
 570
 571static void __init titan_fixup_devices(void)
 572{
 573        /* Set vlynq0 data */
 574        vlynq_low_data.reset_bit = 15;
 575        vlynq_low_data.gpio_bit = 14;
 576
 577        /* Set vlynq1 data */
 578        vlynq_high_data.reset_bit = 16;
 579        vlynq_high_data.gpio_bit = 7;
 580
 581        /* Set vlynq0 resources */
 582        vlynq_low_res[0].start = TITAN_REGS_VLYNQ0;
 583        vlynq_low_res[0].end = TITAN_REGS_VLYNQ0 + 0xff;
 584        vlynq_low_res[1].start = 33;
 585        vlynq_low_res[1].end = 33;
 586        vlynq_low_res[2].start = 0x0c000000;
 587        vlynq_low_res[2].end = 0x0fffffff;
 588        vlynq_low_res[3].start = 80;
 589        vlynq_low_res[3].end = 111;
 590
 591        /* Set vlynq1 resources */
 592        vlynq_high_res[0].start = TITAN_REGS_VLYNQ1;
 593        vlynq_high_res[0].end = TITAN_REGS_VLYNQ1 + 0xff;
 594        vlynq_high_res[1].start = 34;
 595        vlynq_high_res[1].end = 34;
 596        vlynq_high_res[2].start = 0x40000000;
 597        vlynq_high_res[2].end = 0x43ffffff;
 598        vlynq_high_res[3].start = 112;
 599        vlynq_high_res[3].end = 143;
 600
 601        /* Set cpmac0 data */
 602        cpmac_low_data.phy_mask = 0x40000000;
 603
 604        /* Set cpmac1 data */
 605        cpmac_high_data.phy_mask = 0x80000000;
 606
 607        /* Set cpmac0 resources */
 608        cpmac_low_res[0].start = TITAN_REGS_MAC0;
 609        cpmac_low_res[0].end = TITAN_REGS_MAC0 + 0x7ff;
 610
 611        /* Set cpmac1 resources */
 612        cpmac_high_res[0].start = TITAN_REGS_MAC1;
 613        cpmac_high_res[0].end = TITAN_REGS_MAC1 + 0x7ff;
 614}
 615
 616static int __init ar7_register_devices(void)
 617{
 618        void __iomem *bootcr;
 619        u32 val;
 620        int res;
 621
 622        res = ar7_register_uarts();
 623        if (res)
 624                pr_err("unable to setup uart(s): %d\n", res);
 625
 626        res = platform_device_register(&physmap_flash);
 627        if (res)
 628                pr_warning("unable to register physmap-flash: %d\n", res);
 629
 630        if (ar7_is_titan())
 631                titan_fixup_devices();
 632
 633        ar7_device_disable(vlynq_low_data.reset_bit);
 634        res = platform_device_register(&vlynq_low);
 635        if (res)
 636                pr_warning("unable to register vlynq-low: %d\n", res);
 637
 638        if (ar7_has_high_vlynq()) {
 639                ar7_device_disable(vlynq_high_data.reset_bit);
 640                res = platform_device_register(&vlynq_high);
 641                if (res)
 642                        pr_warning("unable to register vlynq-high: %d\n", res);
 643        }
 644
 645        if (ar7_has_high_cpmac()) {
 646                res = fixed_phy_add(PHY_POLL, cpmac_high.id, &fixed_phy_status);
 647                if (!res) {
 648                        cpmac_get_mac(1, cpmac_high_data.dev_addr);
 649
 650                        res = platform_device_register(&cpmac_high);
 651                        if (res)
 652                                pr_warning("unable to register cpmac-high: %d\n", res);
 653                } else
 654                        pr_warning("unable to add cpmac-high phy: %d\n", res);
 655        } else
 656                cpmac_low_data.phy_mask = 0xffffffff;
 657
 658        res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status);
 659        if (!res) {
 660                cpmac_get_mac(0, cpmac_low_data.dev_addr);
 661                res = platform_device_register(&cpmac_low);
 662                if (res)
 663                        pr_warning("unable to register cpmac-low: %d\n", res);
 664        } else
 665                pr_warning("unable to add cpmac-low phy: %d\n", res);
 666
 667        detect_leds();
 668        res = platform_device_register(&ar7_gpio_leds);
 669        if (res)
 670                pr_warning("unable to register leds: %d\n", res);
 671
 672        res = platform_device_register(&ar7_udc);
 673        if (res)
 674                pr_warning("unable to register usb slave: %d\n", res);
 675
 676        /* Register watchdog only if enabled in hardware */
 677        bootcr = ioremap_nocache(AR7_REGS_DCL, 4);
 678        val = readl(bootcr);
 679        iounmap(bootcr);
 680        if (val & AR7_WDT_HW_ENA) {
 681                if (ar7_has_high_vlynq())
 682                        ar7_wdt_res.start = UR8_REGS_WDT;
 683                else
 684                        ar7_wdt_res.start = AR7_REGS_WDT;
 685
 686                ar7_wdt_res.end = ar7_wdt_res.start + 0x20;
 687                res = platform_device_register(&ar7_wdt);
 688                if (res)
 689                        pr_warning("unable to register watchdog: %d\n", res);
 690        }
 691
 692        return 0;
 693}
 694device_initcall(ar7_register_devices);
 695