18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/arm/mach-footbridge/netwinder-hw.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Netwinder machine fixup 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 1998, 1999 Russell King, Phil Blundell 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/ioport.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/leds.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <asm/hardware/dec21285.h> 208c2ecf20Sopenharmony_ci#include <asm/mach-types.h> 218c2ecf20Sopenharmony_ci#include <asm/setup.h> 228c2ecf20Sopenharmony_ci#include <asm/system_misc.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <asm/mach/arch.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "common.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define IRDA_IO_BASE 0x180 298c2ecf20Sopenharmony_ci#define GP1_IO_BASE 0x338 308c2ecf20Sopenharmony_ci#define GP2_IO_BASE 0x33a 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * Winbond WB83977F accessibility stuff 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_cistatic inline void wb977_open(void) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci outb(0x87, 0x370); 388c2ecf20Sopenharmony_ci outb(0x87, 0x370); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic inline void wb977_close(void) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci outb(0xaa, 0x370); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic inline void wb977_wb(int reg, int val) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci outb(reg, 0x370); 498c2ecf20Sopenharmony_ci outb(val, 0x371); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic inline void wb977_ww(int reg, int val) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci outb(reg, 0x370); 558c2ecf20Sopenharmony_ci outb(val >> 8, 0x371); 568c2ecf20Sopenharmony_ci outb(reg + 1, 0x370); 578c2ecf20Sopenharmony_ci outb(val & 255, 0x371); 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define wb977_device_select(dev) wb977_wb(0x07, dev) 618c2ecf20Sopenharmony_ci#define wb977_device_disable() wb977_wb(0x30, 0x00) 628c2ecf20Sopenharmony_ci#define wb977_device_enable() wb977_wb(0x30, 0x01) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* 658c2ecf20Sopenharmony_ci * This is a lock for accessing ports GP1_IO_BASE and GP2_IO_BASE 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ciDEFINE_RAW_SPINLOCK(nw_gpio_lock); 688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nw_gpio_lock); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic unsigned int current_gpio_op; 718c2ecf20Sopenharmony_cistatic unsigned int current_gpio_io; 728c2ecf20Sopenharmony_cistatic unsigned int current_cpld; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_civoid nw_gpio_modify_op(unsigned int mask, unsigned int set) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci unsigned int new_gpio, changed; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci new_gpio = (current_gpio_op & ~mask) | set; 798c2ecf20Sopenharmony_ci changed = new_gpio ^ current_gpio_op; 808c2ecf20Sopenharmony_ci current_gpio_op = new_gpio; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (changed & 0xff) 838c2ecf20Sopenharmony_ci outb(new_gpio, GP1_IO_BASE); 848c2ecf20Sopenharmony_ci if (changed & 0xff00) 858c2ecf20Sopenharmony_ci outb(new_gpio >> 8, GP2_IO_BASE); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nw_gpio_modify_op); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic inline void __gpio_modify_io(int mask, int in) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci unsigned int new_gpio, changed; 928c2ecf20Sopenharmony_ci int port; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci new_gpio = (current_gpio_io & ~mask) | in; 958c2ecf20Sopenharmony_ci changed = new_gpio ^ current_gpio_io; 968c2ecf20Sopenharmony_ci current_gpio_io = new_gpio; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci changed >>= 1; 998c2ecf20Sopenharmony_ci new_gpio >>= 1; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci wb977_device_select(7); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci for (port = 0xe1; changed && port < 0xe8; changed >>= 1) { 1048c2ecf20Sopenharmony_ci wb977_wb(port, new_gpio & 1); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci port += 1; 1078c2ecf20Sopenharmony_ci new_gpio >>= 1; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci wb977_device_select(8); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci for (port = 0xe8; changed && port < 0xec; changed >>= 1) { 1138c2ecf20Sopenharmony_ci wb977_wb(port, new_gpio & 1); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci port += 1; 1168c2ecf20Sopenharmony_ci new_gpio >>= 1; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_civoid nw_gpio_modify_io(unsigned int mask, unsigned int in) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci /* Open up the SuperIO chip */ 1238c2ecf20Sopenharmony_ci wb977_open(); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci __gpio_modify_io(mask, in); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* Close up the EFER gate */ 1288c2ecf20Sopenharmony_ci wb977_close(); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nw_gpio_modify_io); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ciunsigned int nw_gpio_read(void) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci return inb(GP1_IO_BASE) | inb(GP2_IO_BASE) << 8; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nw_gpio_read); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* 1398c2ecf20Sopenharmony_ci * Initialise the Winbond W83977F global registers 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_cistatic inline void wb977_init_global(void) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci /* 1448c2ecf20Sopenharmony_ci * Enable R/W config registers 1458c2ecf20Sopenharmony_ci */ 1468c2ecf20Sopenharmony_ci wb977_wb(0x26, 0x40); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* 1498c2ecf20Sopenharmony_ci * Power down FDC (not used) 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_ci wb977_wb(0x22, 0xfe); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* 1548c2ecf20Sopenharmony_ci * GP12, GP11, CIRRX, IRRXH, GP10 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_ci wb977_wb(0x2a, 0xc1); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* 1598c2ecf20Sopenharmony_ci * GP23, GP22, GP21, GP20, GP13 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_ci wb977_wb(0x2b, 0x6b); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci /* 1648c2ecf20Sopenharmony_ci * GP17, GP16, GP15, GP14 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_ci wb977_wb(0x2c, 0x55); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/* 1708c2ecf20Sopenharmony_ci * Initialise the Winbond W83977F printer port 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_cistatic inline void wb977_init_printer(void) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci wb977_device_select(1); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci /* 1778c2ecf20Sopenharmony_ci * mode 1 == EPP 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci wb977_wb(0xf0, 0x01); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* 1838c2ecf20Sopenharmony_ci * Initialise the Winbond W83977F keyboard controller 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_cistatic inline void wb977_init_keyboard(void) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci wb977_device_select(5); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* 1908c2ecf20Sopenharmony_ci * Keyboard controller address 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ci wb977_ww(0x60, 0x0060); 1938c2ecf20Sopenharmony_ci wb977_ww(0x62, 0x0064); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* 1968c2ecf20Sopenharmony_ci * Keyboard IRQ 1, active high, edge trigger 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci wb977_wb(0x70, 1); 1998c2ecf20Sopenharmony_ci wb977_wb(0x71, 0x02); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* 2028c2ecf20Sopenharmony_ci * Mouse IRQ 5, active high, edge trigger 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_ci wb977_wb(0x72, 5); 2058c2ecf20Sopenharmony_ci wb977_wb(0x73, 0x02); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* 2088c2ecf20Sopenharmony_ci * KBC 8MHz 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_ci wb977_wb(0xf0, 0x40); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* 2138c2ecf20Sopenharmony_ci * Enable device 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_ci wb977_device_enable(); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/* 2198c2ecf20Sopenharmony_ci * Initialise the Winbond W83977F Infra-Red device 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_cistatic inline void wb977_init_irda(void) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci wb977_device_select(6); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* 2268c2ecf20Sopenharmony_ci * IR base address 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ci wb977_ww(0x60, IRDA_IO_BASE); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* 2318c2ecf20Sopenharmony_ci * IRDA IRQ 6, active high, edge trigger 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_ci wb977_wb(0x70, 6); 2348c2ecf20Sopenharmony_ci wb977_wb(0x71, 0x02); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* 2378c2ecf20Sopenharmony_ci * RX DMA - ISA DMA 0 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_ci wb977_wb(0x74, 0x00); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* 2428c2ecf20Sopenharmony_ci * TX DMA - Disable Tx DMA 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_ci wb977_wb(0x75, 0x04); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* 2478c2ecf20Sopenharmony_ci * Append CRC, Enable bank selection 2488c2ecf20Sopenharmony_ci */ 2498c2ecf20Sopenharmony_ci wb977_wb(0xf0, 0x03); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* 2528c2ecf20Sopenharmony_ci * Enable device 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_ci wb977_device_enable(); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/* 2588c2ecf20Sopenharmony_ci * Initialise Winbond W83977F general purpose IO 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_cistatic inline void wb977_init_gpio(void) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci unsigned long flags; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* 2658c2ecf20Sopenharmony_ci * Set up initial I/O definitions 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci current_gpio_io = -1; 2688c2ecf20Sopenharmony_ci __gpio_modify_io(-1, GPIO_DONE | GPIO_WDTIMER); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci wb977_device_select(7); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* 2738c2ecf20Sopenharmony_ci * Group1 base address 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_ci wb977_ww(0x60, GP1_IO_BASE); 2768c2ecf20Sopenharmony_ci wb977_ww(0x62, 0); 2778c2ecf20Sopenharmony_ci wb977_ww(0x64, 0); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* 2808c2ecf20Sopenharmony_ci * GP10 (Orage button) IRQ 10, active high, edge trigger 2818c2ecf20Sopenharmony_ci */ 2828c2ecf20Sopenharmony_ci wb977_wb(0x70, 10); 2838c2ecf20Sopenharmony_ci wb977_wb(0x71, 0x02); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* 2868c2ecf20Sopenharmony_ci * GP10: Debounce filter enabled, IRQ, input 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ci wb977_wb(0xe0, 0x19); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* 2918c2ecf20Sopenharmony_ci * Enable Group1 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci wb977_device_enable(); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci wb977_device_select(8); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* 2988c2ecf20Sopenharmony_ci * Group2 base address 2998c2ecf20Sopenharmony_ci */ 3008c2ecf20Sopenharmony_ci wb977_ww(0x60, GP2_IO_BASE); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* 3038c2ecf20Sopenharmony_ci * Clear watchdog timer regs 3048c2ecf20Sopenharmony_ci * - timer disable 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_ci wb977_wb(0xf2, 0x00); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* 3098c2ecf20Sopenharmony_ci * - disable LED, no mouse nor keyboard IRQ 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_ci wb977_wb(0xf3, 0x00); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* 3148c2ecf20Sopenharmony_ci * - timer counting, disable power LED, disable timeouot 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci wb977_wb(0xf4, 0x00); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* 3198c2ecf20Sopenharmony_ci * Enable group2 3208c2ecf20Sopenharmony_ci */ 3218c2ecf20Sopenharmony_ci wb977_device_enable(); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* 3248c2ecf20Sopenharmony_ci * Set Group1/Group2 outputs 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&nw_gpio_lock, flags); 3278c2ecf20Sopenharmony_ci nw_gpio_modify_op(-1, GPIO_RED_LED | GPIO_FAN); 3288c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci/* 3328c2ecf20Sopenharmony_ci * Initialise the Winbond W83977F chip. 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_cistatic void __init wb977_init(void) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci request_region(0x370, 2, "W83977AF configuration"); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* 3398c2ecf20Sopenharmony_ci * Open up the SuperIO chip 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_ci wb977_open(); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* 3448c2ecf20Sopenharmony_ci * Initialise the global registers 3458c2ecf20Sopenharmony_ci */ 3468c2ecf20Sopenharmony_ci wb977_init_global(); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* 3498c2ecf20Sopenharmony_ci * Initialise the various devices in 3508c2ecf20Sopenharmony_ci * the multi-IO chip. 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_ci wb977_init_printer(); 3538c2ecf20Sopenharmony_ci wb977_init_keyboard(); 3548c2ecf20Sopenharmony_ci wb977_init_irda(); 3558c2ecf20Sopenharmony_ci wb977_init_gpio(); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* 3588c2ecf20Sopenharmony_ci * Close up the EFER gate 3598c2ecf20Sopenharmony_ci */ 3608c2ecf20Sopenharmony_ci wb977_close(); 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_civoid nw_cpld_modify(unsigned int mask, unsigned int set) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci int msk; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci current_cpld = (current_cpld & ~mask) | set; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci nw_gpio_modify_io(GPIO_DATA | GPIO_IOCLK | GPIO_IOLOAD, 0); 3708c2ecf20Sopenharmony_ci nw_gpio_modify_op(GPIO_IOLOAD, 0); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci for (msk = 8; msk; msk >>= 1) { 3738c2ecf20Sopenharmony_ci int bit = current_cpld & msk; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci nw_gpio_modify_op(GPIO_DATA | GPIO_IOCLK, bit ? GPIO_DATA : 0); 3768c2ecf20Sopenharmony_ci nw_gpio_modify_op(GPIO_IOCLK, GPIO_IOCLK); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci nw_gpio_modify_op(GPIO_IOCLK|GPIO_DATA, 0); 3808c2ecf20Sopenharmony_ci nw_gpio_modify_op(GPIO_IOLOAD|GPIO_DSCLK, GPIO_IOLOAD|GPIO_DSCLK); 3818c2ecf20Sopenharmony_ci nw_gpio_modify_op(GPIO_IOLOAD, 0); 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nw_cpld_modify); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic void __init cpld_init(void) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci unsigned long flags; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&nw_gpio_lock, flags); 3908c2ecf20Sopenharmony_ci nw_cpld_modify(-1, CPLD_UNMUTE | CPLD_7111_DISABLE); 3918c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic unsigned char rwa_unlock[] __initdata = 3958c2ecf20Sopenharmony_ci{ 0x00, 0x00, 0x6a, 0xb5, 0xda, 0xed, 0xf6, 0xfb, 0x7d, 0xbe, 0xdf, 0x6f, 0x37, 0x1b, 3968c2ecf20Sopenharmony_ci 0x0d, 0x86, 0xc3, 0x61, 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, 0xd1, 0xe8, 0x74, 3978c2ecf20Sopenharmony_ci 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 }; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci#ifndef DEBUG 4008c2ecf20Sopenharmony_ci#define dprintk(x...) 4018c2ecf20Sopenharmony_ci#else 4028c2ecf20Sopenharmony_ci#define dprintk(x...) printk(x) 4038c2ecf20Sopenharmony_ci#endif 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci#define WRITE_RWA(r,v) do { outb((r), 0x279); udelay(10); outb((v), 0xa79); } while (0) 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic inline void rwa010_unlock(void) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci int i; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci WRITE_RWA(2, 2); 4128c2ecf20Sopenharmony_ci mdelay(10); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(rwa_unlock); i++) { 4158c2ecf20Sopenharmony_ci outb(rwa_unlock[i], 0x279); 4168c2ecf20Sopenharmony_ci udelay(10); 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic inline void rwa010_read_ident(void) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci unsigned char si[9]; 4238c2ecf20Sopenharmony_ci int i, j; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci WRITE_RWA(3, 0); 4268c2ecf20Sopenharmony_ci WRITE_RWA(0, 128); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci outb(1, 0x279); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci mdelay(1); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci dprintk("Identifier: "); 4338c2ecf20Sopenharmony_ci for (i = 0; i < 9; i++) { 4348c2ecf20Sopenharmony_ci si[i] = 0; 4358c2ecf20Sopenharmony_ci for (j = 0; j < 8; j++) { 4368c2ecf20Sopenharmony_ci int bit; 4378c2ecf20Sopenharmony_ci udelay(250); 4388c2ecf20Sopenharmony_ci inb(0x203); 4398c2ecf20Sopenharmony_ci udelay(250); 4408c2ecf20Sopenharmony_ci bit = inb(0x203); 4418c2ecf20Sopenharmony_ci dprintk("%02X ", bit); 4428c2ecf20Sopenharmony_ci bit = (bit == 0xaa) ? 1 : 0; 4438c2ecf20Sopenharmony_ci si[i] |= bit << j; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci dprintk("(%02X) ", si[i]); 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci dprintk("\n"); 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic inline void rwa010_global_init(void) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci WRITE_RWA(6, 2); // Assign a card no = 2 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci dprintk("Card no = %d\n", inb(0x203)); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* disable the modem section of the chip */ 4578c2ecf20Sopenharmony_ci WRITE_RWA(7, 3); 4588c2ecf20Sopenharmony_ci WRITE_RWA(0x30, 0); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci /* disable the cdrom section of the chip */ 4618c2ecf20Sopenharmony_ci WRITE_RWA(7, 4); 4628c2ecf20Sopenharmony_ci WRITE_RWA(0x30, 0); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* disable the MPU-401 section of the chip */ 4658c2ecf20Sopenharmony_ci WRITE_RWA(7, 2); 4668c2ecf20Sopenharmony_ci WRITE_RWA(0x30, 0); 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic inline void rwa010_game_port_init(void) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci int i; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci WRITE_RWA(7, 5); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci dprintk("Slider base: "); 4768c2ecf20Sopenharmony_ci WRITE_RWA(0x61, 1); 4778c2ecf20Sopenharmony_ci i = inb(0x203); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci WRITE_RWA(0x60, 2); 4808c2ecf20Sopenharmony_ci dprintk("%02X%02X (201)\n", inb(0x203), i); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci WRITE_RWA(0x30, 1); 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic inline void rwa010_waveartist_init(int base, int irq, int dma) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci int i; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci WRITE_RWA(7, 0); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci dprintk("WaveArtist base: "); 4928c2ecf20Sopenharmony_ci WRITE_RWA(0x61, base & 255); 4938c2ecf20Sopenharmony_ci i = inb(0x203); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci WRITE_RWA(0x60, base >> 8); 4968c2ecf20Sopenharmony_ci dprintk("%02X%02X (%X),", inb(0x203), i, base); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci WRITE_RWA(0x70, irq); 4998c2ecf20Sopenharmony_ci dprintk(" irq: %d (%d),", inb(0x203), irq); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci WRITE_RWA(0x74, dma); 5028c2ecf20Sopenharmony_ci dprintk(" dma: %d (%d)\n", inb(0x203), dma); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci WRITE_RWA(0x30, 1); 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic inline void rwa010_soundblaster_init(int sb_base, int al_base, int irq, int dma) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci int i; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci WRITE_RWA(7, 1); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci dprintk("SoundBlaster base: "); 5148c2ecf20Sopenharmony_ci WRITE_RWA(0x61, sb_base & 255); 5158c2ecf20Sopenharmony_ci i = inb(0x203); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci WRITE_RWA(0x60, sb_base >> 8); 5188c2ecf20Sopenharmony_ci dprintk("%02X%02X (%X),", inb(0x203), i, sb_base); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci dprintk(" irq: "); 5218c2ecf20Sopenharmony_ci WRITE_RWA(0x70, irq); 5228c2ecf20Sopenharmony_ci dprintk("%d (%d),", inb(0x203), irq); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci dprintk(" 8-bit DMA: "); 5258c2ecf20Sopenharmony_ci WRITE_RWA(0x74, dma); 5268c2ecf20Sopenharmony_ci dprintk("%d (%d)\n", inb(0x203), dma); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci dprintk("AdLib base: "); 5298c2ecf20Sopenharmony_ci WRITE_RWA(0x63, al_base & 255); 5308c2ecf20Sopenharmony_ci i = inb(0x203); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci WRITE_RWA(0x62, al_base >> 8); 5338c2ecf20Sopenharmony_ci dprintk("%02X%02X (%X)\n", inb(0x203), i, al_base); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci WRITE_RWA(0x30, 1); 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic void rwa010_soundblaster_reset(void) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci int i; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci outb(1, 0x226); 5438c2ecf20Sopenharmony_ci udelay(3); 5448c2ecf20Sopenharmony_ci outb(0, 0x226); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 5478c2ecf20Sopenharmony_ci if (inb(0x22e) & 0x80) 5488c2ecf20Sopenharmony_ci break; 5498c2ecf20Sopenharmony_ci mdelay(1); 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci if (i == 5) 5528c2ecf20Sopenharmony_ci printk("SoundBlaster: DSP reset failed\n"); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci dprintk("SoundBlaster DSP reset: %02X (AA)\n", inb(0x22a)); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 5578c2ecf20Sopenharmony_ci if ((inb(0x22c) & 0x80) == 0) 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci mdelay(1); 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (i == 5) 5638c2ecf20Sopenharmony_ci printk("SoundBlaster: DSP not ready\n"); 5648c2ecf20Sopenharmony_ci else { 5658c2ecf20Sopenharmony_ci outb(0xe1, 0x22c); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci dprintk("SoundBlaster DSP id: "); 5688c2ecf20Sopenharmony_ci i = inb(0x22a); 5698c2ecf20Sopenharmony_ci udelay(1); 5708c2ecf20Sopenharmony_ci i |= inb(0x22a) << 8; 5718c2ecf20Sopenharmony_ci dprintk("%04X\n", i); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 5748c2ecf20Sopenharmony_ci if ((inb(0x22c) & 0x80) == 0) 5758c2ecf20Sopenharmony_ci break; 5768c2ecf20Sopenharmony_ci mdelay(1); 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (i == 5) 5808c2ecf20Sopenharmony_ci printk("SoundBlaster: could not turn speaker off\n"); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci outb(0xd3, 0x22c); 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* turn on OPL3 */ 5868c2ecf20Sopenharmony_ci outb(5, 0x38a); 5878c2ecf20Sopenharmony_ci outb(1, 0x38b); 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic void __init rwa010_init(void) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci rwa010_unlock(); 5938c2ecf20Sopenharmony_ci rwa010_read_ident(); 5948c2ecf20Sopenharmony_ci rwa010_global_init(); 5958c2ecf20Sopenharmony_ci rwa010_game_port_init(); 5968c2ecf20Sopenharmony_ci rwa010_waveartist_init(0x250, 3, 7); 5978c2ecf20Sopenharmony_ci rwa010_soundblaster_init(0x220, 0x388, 3, 1); 5988c2ecf20Sopenharmony_ci rwa010_soundblaster_reset(); 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci/* 6028c2ecf20Sopenharmony_ci * Initialise any other hardware after we've got the PCI bus 6038c2ecf20Sopenharmony_ci * initialised. We may need the PCI bus to talk to this other 6048c2ecf20Sopenharmony_ci * hardware. 6058c2ecf20Sopenharmony_ci */ 6068c2ecf20Sopenharmony_cistatic int __init nw_hw_init(void) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci if (machine_is_netwinder()) { 6098c2ecf20Sopenharmony_ci wb977_init(); 6108c2ecf20Sopenharmony_ci cpld_init(); 6118c2ecf20Sopenharmony_ci rwa010_init(); 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci return 0; 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci__initcall(nw_hw_init); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci/* 6198c2ecf20Sopenharmony_ci * Older NeTTroms either do not provide a parameters 6208c2ecf20Sopenharmony_ci * page, or they don't supply correct information in 6218c2ecf20Sopenharmony_ci * the parameter page. 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_cistatic void __init 6248c2ecf20Sopenharmony_cifixup_netwinder(struct tag *tags, char **cmdline) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci#ifdef CONFIG_ISAPNP 6278c2ecf20Sopenharmony_ci extern int isapnp_disable; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* 6308c2ecf20Sopenharmony_ci * We must not use the kernels ISAPnP code 6318c2ecf20Sopenharmony_ci * on the NetWinder - it will reset the settings 6328c2ecf20Sopenharmony_ci * for the WaveArtist chip and render it inoperable. 6338c2ecf20Sopenharmony_ci */ 6348c2ecf20Sopenharmony_ci isapnp_disable = 1; 6358c2ecf20Sopenharmony_ci#endif 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic void netwinder_restart(enum reboot_mode mode, const char *cmd) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci if (mode == REBOOT_SOFT) { 6418c2ecf20Sopenharmony_ci /* Jump into the ROM */ 6428c2ecf20Sopenharmony_ci soft_restart(0x41000000); 6438c2ecf20Sopenharmony_ci } else { 6448c2ecf20Sopenharmony_ci local_irq_disable(); 6458c2ecf20Sopenharmony_ci local_fiq_disable(); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* open up the SuperIO chip */ 6488c2ecf20Sopenharmony_ci outb(0x87, 0x370); 6498c2ecf20Sopenharmony_ci outb(0x87, 0x370); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci /* aux function group 1 (logical device 7) */ 6528c2ecf20Sopenharmony_ci outb(0x07, 0x370); 6538c2ecf20Sopenharmony_ci outb(0x07, 0x371); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci /* set GP16 for WD-TIMER output */ 6568c2ecf20Sopenharmony_ci outb(0xe6, 0x370); 6578c2ecf20Sopenharmony_ci outb(0x00, 0x371); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* set a RED LED and toggle WD_TIMER for rebooting */ 6608c2ecf20Sopenharmony_ci outb(0xc4, 0x338); 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci/* LEDs */ 6658c2ecf20Sopenharmony_ci#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) 6668c2ecf20Sopenharmony_cistruct netwinder_led { 6678c2ecf20Sopenharmony_ci struct led_classdev cdev; 6688c2ecf20Sopenharmony_ci u8 mask; 6698c2ecf20Sopenharmony_ci}; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci/* 6728c2ecf20Sopenharmony_ci * The triggers lines up below will only be used if the 6738c2ecf20Sopenharmony_ci * LED triggers are compiled in. 6748c2ecf20Sopenharmony_ci */ 6758c2ecf20Sopenharmony_cistatic const struct { 6768c2ecf20Sopenharmony_ci const char *name; 6778c2ecf20Sopenharmony_ci const char *trigger; 6788c2ecf20Sopenharmony_ci} netwinder_leds[] = { 6798c2ecf20Sopenharmony_ci { "netwinder:green", "heartbeat", }, 6808c2ecf20Sopenharmony_ci { "netwinder:red", "cpu0", }, 6818c2ecf20Sopenharmony_ci}; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci/* 6848c2ecf20Sopenharmony_ci * The LED control in Netwinder is reversed: 6858c2ecf20Sopenharmony_ci * - setting bit means turn off LED 6868c2ecf20Sopenharmony_ci * - clearing bit means turn on LED 6878c2ecf20Sopenharmony_ci */ 6888c2ecf20Sopenharmony_cistatic void netwinder_led_set(struct led_classdev *cdev, 6898c2ecf20Sopenharmony_ci enum led_brightness b) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci struct netwinder_led *led = container_of(cdev, 6928c2ecf20Sopenharmony_ci struct netwinder_led, cdev); 6938c2ecf20Sopenharmony_ci unsigned long flags; 6948c2ecf20Sopenharmony_ci u32 reg; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&nw_gpio_lock, flags); 6978c2ecf20Sopenharmony_ci reg = nw_gpio_read(); 6988c2ecf20Sopenharmony_ci if (b != LED_OFF) 6998c2ecf20Sopenharmony_ci reg &= ~led->mask; 7008c2ecf20Sopenharmony_ci else 7018c2ecf20Sopenharmony_ci reg |= led->mask; 7028c2ecf20Sopenharmony_ci nw_gpio_modify_op(led->mask, reg); 7038c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic enum led_brightness netwinder_led_get(struct led_classdev *cdev) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci struct netwinder_led *led = container_of(cdev, 7098c2ecf20Sopenharmony_ci struct netwinder_led, cdev); 7108c2ecf20Sopenharmony_ci unsigned long flags; 7118c2ecf20Sopenharmony_ci u32 reg; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&nw_gpio_lock, flags); 7148c2ecf20Sopenharmony_ci reg = nw_gpio_read(); 7158c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci return (reg & led->mask) ? LED_OFF : LED_FULL; 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic int __init netwinder_leds_init(void) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci int i; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (!machine_is_netwinder()) 7258c2ecf20Sopenharmony_ci return -ENODEV; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(netwinder_leds); i++) { 7288c2ecf20Sopenharmony_ci struct netwinder_led *led; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci led = kzalloc(sizeof(*led), GFP_KERNEL); 7318c2ecf20Sopenharmony_ci if (!led) 7328c2ecf20Sopenharmony_ci break; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci led->cdev.name = netwinder_leds[i].name; 7358c2ecf20Sopenharmony_ci led->cdev.brightness_set = netwinder_led_set; 7368c2ecf20Sopenharmony_ci led->cdev.brightness_get = netwinder_led_get; 7378c2ecf20Sopenharmony_ci led->cdev.default_trigger = netwinder_leds[i].trigger; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (i == 0) 7408c2ecf20Sopenharmony_ci led->mask = GPIO_GREEN_LED; 7418c2ecf20Sopenharmony_ci else 7428c2ecf20Sopenharmony_ci led->mask = GPIO_RED_LED; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (led_classdev_register(NULL, &led->cdev) < 0) { 7458c2ecf20Sopenharmony_ci kfree(led); 7468c2ecf20Sopenharmony_ci break; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci return 0; 7518c2ecf20Sopenharmony_ci} 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci/* 7548c2ecf20Sopenharmony_ci * Since we may have triggers on any subsystem, defer registration 7558c2ecf20Sopenharmony_ci * until after subsystem_init. 7568c2ecf20Sopenharmony_ci */ 7578c2ecf20Sopenharmony_cifs_initcall(netwinder_leds_init); 7588c2ecf20Sopenharmony_ci#endif 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ciMACHINE_START(NETWINDER, "Rebel-NetWinder") 7618c2ecf20Sopenharmony_ci /* Maintainer: Russell King/Rebel.com */ 7628c2ecf20Sopenharmony_ci .atag_offset = 0x100, 7638c2ecf20Sopenharmony_ci .video_start = 0x000a0000, 7648c2ecf20Sopenharmony_ci .video_end = 0x000bffff, 7658c2ecf20Sopenharmony_ci .reserve_lp0 = 1, 7668c2ecf20Sopenharmony_ci .reserve_lp2 = 1, 7678c2ecf20Sopenharmony_ci .fixup = fixup_netwinder, 7688c2ecf20Sopenharmony_ci .map_io = footbridge_map_io, 7698c2ecf20Sopenharmony_ci .init_irq = footbridge_init_irq, 7708c2ecf20Sopenharmony_ci .init_time = isa_timer_init, 7718c2ecf20Sopenharmony_ci .restart = netwinder_restart, 7728c2ecf20Sopenharmony_ciMACHINE_END 773