source: trunk/target/linux/omap24xx/patches-3.1/200-omap-platform.patch @ 29007

Last change on this file since 29007 was 29007, checked in by jogo, 5 years ago

linux: update 3.1 to 3.1.1

File size: 22.2 KB
  • new file arch/arm/plat-omap/bootreason.c

    - +  
     1/* 
     2 * linux/arch/arm/plat-omap/bootreason.c 
     3 * 
     4 * OMAP Bootreason passing 
     5 * 
     6 * Copyright (c) 2004 Nokia 
     7 * 
     8 * Written by David Weinehall <david.weinehall@nokia.com> 
     9 * 
     10 * This program is free software; you can redistribute it and/or modify it 
     11 * under the terms of the GNU General Public License as published by the 
     12 * Free Software Foundation; either version 2 of the License, or (at your 
     13 * option) any later version. 
     14 * 
     15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 
     16 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
     17 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 
     18 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
     19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
     20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 
     21 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
     22 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
     23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
     24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     25 * 
     26 * You should have received a copy of the GNU General Public License along 
     27 * with this program; if not, write to the Free Software Foundation, Inc., 
     28 * 675 Mass Ave, Cambridge, MA 02139, USA. 
     29 */ 
     30#include <linux/proc_fs.h> 
     31#include <linux/errno.h> 
     32#include <plat/board.h> 
     33 
     34static char boot_reason[16]; 
     35 
     36static int omap_bootreason_read_proc(char *page, char **start, off_t off, 
     37                                         int count, int *eof, void *data) 
     38{ 
     39        int len = 0; 
     40 
     41        len += sprintf(page + len, "%s\n", boot_reason); 
     42 
     43        *start = page + off; 
     44 
     45        if (len > off) 
     46                len -= off; 
     47        else 
     48                len = 0; 
     49 
     50        return len < count ? len  : count; 
     51} 
     52 
     53static int __init bootreason_init(void) 
     54{ 
     55        const struct omap_boot_reason_config *cfg; 
     56        int reason_valid = 0; 
     57 
     58        cfg = omap_get_config(OMAP_TAG_BOOT_REASON, struct omap_boot_reason_config); 
     59        if (cfg != NULL) { 
     60                strncpy(boot_reason, cfg->reason_str, sizeof(cfg->reason_str)); 
     61                boot_reason[sizeof(cfg->reason_str)] = 0; 
     62                reason_valid = 1; 
     63        } else { 
     64                /* Read the boot reason from the OMAP registers */ 
     65        } 
     66 
     67        if (!reason_valid) 
     68                return -ENOENT; 
     69 
     70        printk(KERN_INFO "Bootup reason: %s\n", boot_reason); 
     71 
     72        if (!create_proc_read_entry("bootreason", S_IRUGO, NULL, 
     73                                        omap_bootreason_read_proc, NULL)) 
     74                return -ENOMEM; 
     75 
     76        return 0; 
     77} 
     78 
     79late_initcall(bootreason_init); 
  • arch/arm/plat-omap/common.c

    a b  
    2121#include <plat/vram.h> 
    2222#include <plat/dsp.h> 
    2323 
     24#include <asm/setup.h> 
     25 
    2426 
    2527#define NO_LENGTH_CHECK 0xffffffff 
    2628 
    2729struct omap_board_config_kernel *omap_board_config __initdata; 
    2830int omap_board_config_size; 
    2931 
     32unsigned char omap_bootloader_tag[1024]; 
     33int omap_bootloader_tag_len; 
     34 
     35/* used by omap-smp.c and board-4430sdp.c */ 
     36void __iomem *gic_cpu_base_addr; 
     37 
     38#ifdef CONFIG_OMAP_BOOT_TAG 
     39 
     40static int __init parse_tag_omap(const struct tag *tag) 
     41{ 
     42        u32 size = tag->hdr.size - (sizeof(tag->hdr) >> 2); 
     43 
     44        size <<= 2; 
     45        if (size > sizeof(omap_bootloader_tag)) 
     46                return -1; 
     47 
     48        memcpy(omap_bootloader_tag, tag->u.omap.data, size); 
     49        omap_bootloader_tag_len = size; 
     50 
     51        return 0; 
     52} 
     53 
     54__tagtable(ATAG_BOARD, parse_tag_omap); 
     55 
     56#endif 
     57 
    3058static const void *__init get_config(u16 tag, size_t len, 
    3159                int skip, size_t *len_out) 
    3260{ 
    3361        struct omap_board_config_kernel *kinfo = NULL; 
    3462        int i; 
    3563 
     64#ifdef CONFIG_OMAP_BOOT_TAG 
     65        struct omap_board_config_entry *info = NULL; 
     66 
     67        if (omap_bootloader_tag_len > 4) 
     68                info = (struct omap_board_config_entry *) omap_bootloader_tag; 
     69        while (info != NULL) { 
     70                u8 *next; 
     71 
     72                if (info->tag == tag) { 
     73                        if (skip == 0) 
     74                                break; 
     75                        skip--; 
     76                } 
     77 
     78                if ((info->len & 0x03) != 0) { 
     79                        /* We bail out to avoid an alignment fault */ 
     80                        printk(KERN_ERR "OMAP peripheral config: Length (%d) not word-aligned (tag %04x)\n", 
     81                               info->len, info->tag); 
     82                        return NULL; 
     83                } 
     84                next = (u8 *) info + sizeof(*info) + info->len; 
     85                if (next >= omap_bootloader_tag + omap_bootloader_tag_len) 
     86                        info = NULL; 
     87                else 
     88                        info = (struct omap_board_config_entry *) next; 
     89        } 
     90        if (info != NULL) { 
     91                /* Check the length as a lame attempt to check for 
     92                 * binary inconsistency. */ 
     93                if (len != NO_LENGTH_CHECK) { 
     94                        /* Word-align len */ 
     95                        if (len & 0x03) 
     96                                len = (len + 3) & ~0x03; 
     97                        if (info->len != len) { 
     98                                printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n", 
     99                                       tag, len, info->len); 
     100                                return NULL; 
     101                        } 
     102                } 
     103                if (len_out != NULL) 
     104                        *len_out = info->len; 
     105                return info->data; 
     106        } 
     107#endif 
    36108        /* Try to find the config from the board-specific structures 
    37109         * in the kernel. */ 
    38110        for (i = 0; i < omap_board_config_size; i++) { 
  • new file arch/arm/plat-omap/component-version.c

    - +  
     1/* 
     2 *  linux/arch/arm/plat-omap/component-version.c 
     3 * 
     4 *  Copyright (C) 2005 Nokia Corporation 
     5 *  Written by Juha Yrjölä <juha.yrjola@nokia.com> 
     6 * 
     7 * This program is free software; you can redistribute it and/or modify 
     8 * it under the terms of the GNU General Public License version 2 as 
     9 * published by the Free Software Foundation. 
     10 */ 
     11 
     12#include <linux/init.h> 
     13#include <linux/module.h> 
     14#include <linux/err.h> 
     15#include <linux/proc_fs.h> 
     16#include <plat/board.h> 
     17 
     18static int component_version_read_proc(char *page, char **start, off_t off, 
     19                                       int count, int *eof, void *data) 
     20{ 
     21        int len, i; 
     22        const struct omap_version_config *ver; 
     23        char *p; 
     24 
     25        i = 0; 
     26        p = page; 
     27        while ((ver = omap_get_nr_config(OMAP_TAG_VERSION_STR, 
     28                                         struct omap_version_config, i)) != NULL) { 
     29                p += sprintf(p, "%-12s%s\n", ver->component, ver->version); 
     30                i++; 
     31        } 
     32 
     33        len = (p - page) - off; 
     34        if (len < 0) 
     35                len = 0; 
     36 
     37        *eof = (len <= count) ? 1 : 0; 
     38        *start = page + off; 
     39 
     40        return len; 
     41} 
     42 
     43static int __init component_version_init(void) 
     44{ 
     45        if (omap_get_config(OMAP_TAG_VERSION_STR, struct omap_version_config) == NULL) 
     46                return -ENODEV; 
     47        if (!create_proc_read_entry("component_version", S_IRUGO, NULL, 
     48                                    component_version_read_proc, NULL)) 
     49                return -ENOMEM; 
     50 
     51        return 0; 
     52} 
     53 
     54static void __exit component_version_exit(void) 
     55{ 
     56        remove_proc_entry("component_version", NULL); 
     57} 
     58 
     59late_initcall(component_version_init); 
     60module_exit(component_version_exit); 
     61 
     62MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>"); 
     63MODULE_DESCRIPTION("Component version driver"); 
     64MODULE_LICENSE("GPL"); 
  • arch/arm/plat-omap/Kconfig

    a b config OMAP_RESET_CLOCKS 
    8282          probably do not want this option enabled until your 
    8383          device drivers work properly. 
    8484 
     85config OMAP_BOOT_TAG 
     86        bool "OMAP bootloader information passing" 
     87        depends on ARCH_OMAP 
     88        default n 
     89        help 
     90          Say Y, if you have a bootloader which passes information 
     91          about your board and its peripheral configuration. 
     92 
     93config OMAP_BOOT_REASON 
     94        bool "Support for boot reason" 
     95        depends on OMAP_BOOT_TAG 
     96        default n 
     97        help 
     98          Say Y, if you want to have a procfs entry for reading the boot 
     99          reason in user-space. 
     100 
     101config OMAP_COMPONENT_VERSION 
     102        bool "Support for component version display" 
     103        depends on OMAP_BOOT_TAG && PROC_FS 
     104        default n 
     105        help 
     106          Say Y, if you want to have a procfs entry for reading component 
     107          versions (supplied by the bootloader) in user-space. 
     108 
     109config OMAP_GPIO_SWITCH 
     110        bool "GPIO switch support" 
     111        help 
     112          Say Y, if you want to have support for reporting of GPIO 
     113          switches (e.g. cover switches) via sysfs. Your bootloader has 
     114          to provide information about the switches to the kernel via the 
     115          ATAG_BOARD mechanism if they're not defined by the board config. 
     116 
    85117config OMAP_MUX 
    86118        bool "OMAP multiplexing support" 
    87119        depends on ARCH_OMAP 
  • arch/arm/plat-omap/Makefile

    a b obj-$(CONFIG_OMAP_IOMMU_DEBUG) += iommu- 
    2323 
    2424obj-$(CONFIG_CPU_FREQ) += cpu-omap.o 
    2525obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o 
     26obj-$(CONFIG_OMAP_BOOT_REASON) += bootreason.o 
     27obj-$(CONFIG_OMAP_COMPONENT_VERSION) += component-version.o 
     28obj-$(CONFIG_OMAP_GPIO_SWITCH) += gpio-switch.o 
    2629obj-$(CONFIG_OMAP_DEBUG_DEVICES) += debug-devices.o 
    2730obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o 
    2831i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o 
  • arch/arm/include/asm/setup.h

    a b struct tag_acorn { 
    136136        __u8 adfsdrives; 
    137137}; 
    138138 
     139/* TI OMAP specific information */ 
     140#define ATAG_BOARD       0x414f4d50 
     141 
     142struct tag_omap { 
     143        u8 data[0]; 
     144}; 
     145 
    139146/* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */ 
    140147#define ATAG_MEMCLK     0x41000402 
    141148 
    struct tag { 
    162169                struct tag_acorn        acorn; 
    163170 
    164171                /* 
     172                 * OMAP specific 
     173                 */ 
     174                struct tag_omap         omap; 
     175 
     176                /* 
    165177                 * DC21285 specific 
    166178                 */ 
    167179                struct tag_memclk       memclk; 
  • new file arch/arm/plat-omap/gpio-switch.c

    - +  
     1/* 
     2 *  linux/arch/arm/plat-omap/gpio-switch.c 
     3 * 
     4 *  Copyright (C) 2004-2006 Nokia Corporation 
     5 *  Written by Juha Yrjölä <juha.yrjola@nokia.com> 
     6 *         and Paul Mundt <paul.mundt@nokia.com> 
     7 * 
     8 * This program is free software; you can redistribute it and/or modify 
     9 * it under the terms of the GNU General Public License version 2 as 
     10 * published by the Free Software Foundation. 
     11 */ 
     12 
     13#include <linux/sched.h> 
     14#include <linux/init.h> 
     15#include <linux/list.h> 
     16#include <linux/irq.h> 
     17#include <linux/interrupt.h> 
     18#include <linux/module.h> 
     19#include <linux/platform_device.h> 
     20#include <linux/timer.h> 
     21#include <linux/err.h> 
     22#include <linux/slab.h> 
     23#include <linux/gpio.h> 
     24#include <plat/hardware.h> 
     25#include <plat/irqs.h> 
     26#include <plat/mux.h> 
     27#include <plat/board.h> 
     28#include <plat/gpio-switch.h> 
     29 
     30struct gpio_switch { 
     31        char            name[14]; 
     32        u16             gpio; 
     33        unsigned        flags:4; 
     34        unsigned        type:4; 
     35        unsigned        state:1; 
     36        unsigned        both_edges:1; 
     37 
     38        u16             debounce_rising; 
     39        u16             debounce_falling; 
     40 
     41        void (* notify)(void *data, int state); 
     42        void *notify_data; 
     43 
     44        struct work_struct      work; 
     45        struct timer_list       timer; 
     46        struct platform_device  pdev; 
     47 
     48        struct list_head        node; 
     49}; 
     50 
     51static LIST_HEAD(gpio_switches); 
     52static struct platform_device *gpio_sw_platform_dev; 
     53static struct platform_driver gpio_sw_driver; 
     54 
     55static const struct omap_gpio_switch *board_gpio_sw_table; 
     56static int board_gpio_sw_count; 
     57 
     58static const char *cover_str[2] = { "open", "closed" }; 
     59static const char *connection_str[2] = { "disconnected", "connected" }; 
     60static const char *activity_str[2] = { "inactive", "active" }; 
     61 
     62/* 
     63 * GPIO switch state default debounce delay in ms 
     64 */ 
     65#define OMAP_GPIO_SW_DEFAULT_DEBOUNCE           10 
     66 
     67static const char **get_sw_str(struct gpio_switch *sw) 
     68{ 
     69        switch (sw->type) { 
     70        case OMAP_GPIO_SWITCH_TYPE_COVER: 
     71                return cover_str; 
     72        case OMAP_GPIO_SWITCH_TYPE_CONNECTION: 
     73                return connection_str; 
     74        case OMAP_GPIO_SWITCH_TYPE_ACTIVITY: 
     75                return activity_str; 
     76        default: 
     77                BUG(); 
     78                return NULL; 
     79        } 
     80} 
     81 
     82static const char *get_sw_type(struct gpio_switch *sw) 
     83{ 
     84        switch (sw->type) { 
     85        case OMAP_GPIO_SWITCH_TYPE_COVER: 
     86                return "cover"; 
     87        case OMAP_GPIO_SWITCH_TYPE_CONNECTION: 
     88                return "connection"; 
     89        case OMAP_GPIO_SWITCH_TYPE_ACTIVITY: 
     90                return "activity"; 
     91        default: 
     92                BUG(); 
     93                return NULL; 
     94        } 
     95} 
     96 
     97static void print_sw_state(struct gpio_switch *sw, int state) 
     98{ 
     99        const char **str; 
     100 
     101        str = get_sw_str(sw); 
     102        if (str != NULL) 
     103                printk(KERN_INFO "%s (GPIO %d) is now %s\n", sw->name, sw->gpio, str[state]); 
     104} 
     105 
     106static int gpio_sw_get_state(struct gpio_switch *sw) 
     107{ 
     108        int state; 
     109 
     110        state = gpio_get_value(sw->gpio); 
     111        if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED) 
     112                state = !state; 
     113 
     114        return state; 
     115} 
     116 
     117static ssize_t gpio_sw_state_store(struct device *dev, 
     118                                   struct device_attribute *attr, 
     119                                   const char *buf, 
     120                                   size_t count) 
     121{ 
     122        struct gpio_switch *sw = dev_get_drvdata(dev); 
     123        const char **str; 
     124        char state[16]; 
     125        int enable; 
     126 
     127        if (!(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT)) 
     128                return -EPERM; 
     129 
     130        if (sscanf(buf, "%15s", state) != 1) 
     131                return -EINVAL; 
     132 
     133        str = get_sw_str(sw); 
     134        if (strcmp(state, str[0]) == 0) 
     135                sw->state = enable = 0; 
     136        else if (strcmp(state, str[1]) == 0) 
     137                sw->state = enable = 1; 
     138        else 
     139                return -EINVAL; 
     140 
     141        if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED) 
     142                enable = !enable; 
     143        gpio_set_value(sw->gpio, enable); 
     144 
     145        return count; 
     146} 
     147 
     148static ssize_t gpio_sw_state_show(struct device *dev, 
     149                                  struct device_attribute *attr, 
     150                                  char *buf) 
     151{ 
     152        struct gpio_switch *sw = dev_get_drvdata(dev); 
     153        const char **str; 
     154 
     155        str = get_sw_str(sw); 
     156        return sprintf(buf, "%s\n", str[sw->state]); 
     157} 
     158 
     159static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, gpio_sw_state_show, 
     160                   gpio_sw_state_store); 
     161 
     162static ssize_t gpio_sw_type_show(struct device *dev, 
     163                                 struct device_attribute *attr, 
     164                                 char *buf) 
     165{ 
     166        struct gpio_switch *sw = dev_get_drvdata(dev); 
     167 
     168        return sprintf(buf, "%s\n", get_sw_type(sw)); 
     169} 
     170 
     171static DEVICE_ATTR(type, S_IRUGO, gpio_sw_type_show, NULL); 
     172 
     173static ssize_t gpio_sw_direction_show(struct device *dev, 
     174                                      struct device_attribute *attr, 
     175                                      char *buf) 
     176{ 
     177        struct gpio_switch *sw = dev_get_drvdata(dev); 
     178        int is_output; 
     179 
     180        is_output = sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT; 
     181        return sprintf(buf, "%s\n", is_output ? "output" : "input"); 
     182} 
     183 
     184static DEVICE_ATTR(direction, S_IRUGO, gpio_sw_direction_show, NULL); 
     185 
     186 
     187static irqreturn_t gpio_sw_irq_handler(int irq, void *arg) 
     188{ 
     189        struct gpio_switch *sw = arg; 
     190        unsigned long timeout; 
     191        int state; 
     192 
     193        if (!sw->both_edges) { 
     194                if (gpio_get_value(sw->gpio)) 
     195                        irq_set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQ_TYPE_EDGE_FALLING); 
     196                else 
     197                        irq_set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQ_TYPE_EDGE_RISING); 
     198        } 
     199 
     200        state = gpio_sw_get_state(sw); 
     201        if (sw->state == state) 
     202                return IRQ_HANDLED; 
     203 
     204        if (state) 
     205                timeout = sw->debounce_rising; 
     206        else 
     207                timeout = sw->debounce_falling; 
     208        if (!timeout) 
     209                schedule_work(&sw->work); 
     210        else 
     211                mod_timer(&sw->timer, jiffies + msecs_to_jiffies(timeout)); 
     212 
     213        return IRQ_HANDLED; 
     214} 
     215 
     216static void gpio_sw_timer(unsigned long arg) 
     217{ 
     218        struct gpio_switch *sw = (struct gpio_switch *) arg; 
     219 
     220        schedule_work(&sw->work); 
     221} 
     222 
     223static void gpio_sw_handler(struct work_struct *work) 
     224{ 
     225        struct gpio_switch *sw = container_of(work, struct gpio_switch, work); 
     226        int state; 
     227 
     228        state = gpio_sw_get_state(sw); 
     229        if (sw->state == state) 
     230                return; 
     231 
     232        sw->state = state; 
     233        if (sw->notify != NULL) 
     234                sw->notify(sw->notify_data, state); 
     235        sysfs_notify(&sw->pdev.dev.kobj, NULL, "state"); 
     236        print_sw_state(sw, state); 
     237} 
     238 
     239static int __init can_do_both_edges(struct gpio_switch *sw) 
     240{ 
     241        if (!cpu_class_is_omap1()) 
     242                return 1; 
     243        if (OMAP_GPIO_IS_MPUIO(sw->gpio)) 
     244                return 0; 
     245        else 
     246                return 1; 
     247} 
     248 
     249static void gpio_sw_release(struct device *dev) 
     250{ 
     251} 
     252 
     253static int __init new_switch(struct gpio_switch *sw) 
     254{ 
     255        int r, direction, trigger; 
     256 
     257        switch (sw->type) { 
     258        case OMAP_GPIO_SWITCH_TYPE_COVER: 
     259        case OMAP_GPIO_SWITCH_TYPE_CONNECTION: 
     260        case OMAP_GPIO_SWITCH_TYPE_ACTIVITY: 
     261                break; 
     262        default: 
     263                printk(KERN_ERR "invalid GPIO switch type: %d\n", sw->type); 
     264                return -EINVAL; 
     265        } 
     266 
     267        sw->pdev.name   = sw->name; 
     268        sw->pdev.id     = -1; 
     269 
     270        sw->pdev.dev.parent = &gpio_sw_platform_dev->dev; 
     271        sw->pdev.dev.driver = &gpio_sw_driver.driver; 
     272        sw->pdev.dev.release = gpio_sw_release; 
     273 
     274        r = platform_device_register(&sw->pdev); 
     275        if (r) { 
     276                printk(KERN_ERR "gpio-switch: platform device registration " 
     277                       "failed for %s", sw->name); 
     278                return r; 
     279        } 
     280        dev_set_drvdata(&sw->pdev.dev, sw); 
     281 
     282        r = gpio_request(sw->gpio, "gpio-switch"); 
     283        if (r < 0) { 
     284                platform_device_unregister(&sw->pdev); 
     285                return r; 
     286        } 
     287 
     288        /* input: 1, output: 0 */ 
     289        direction = !(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT); 
     290        if (direction) 
     291                gpio_direction_input(sw->gpio); 
     292        else 
     293                gpio_direction_output(sw->gpio, 0); 
     294 
     295        sw->state = gpio_sw_get_state(sw); 
     296 
     297        r = 0; 
     298        r |= device_create_file(&sw->pdev.dev, &dev_attr_state); 
     299        r |= device_create_file(&sw->pdev.dev, &dev_attr_type); 
     300        r |= device_create_file(&sw->pdev.dev, &dev_attr_direction); 
     301        if (r) 
     302                printk(KERN_ERR "gpio-switch: attribute file creation " 
     303                       "failed for %s\n", sw->name); 
     304 
     305        if (!direction) 
     306                return 0; 
     307 
     308        if (can_do_both_edges(sw)) { 
     309                trigger = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING; 
     310                sw->both_edges = 1; 
     311        } else { 
     312                if (gpio_get_value(sw->gpio)) 
     313                        trigger = IRQF_TRIGGER_FALLING; 
     314                else 
     315                        trigger = IRQF_TRIGGER_RISING; 
     316        } 
     317        r = request_irq(OMAP_GPIO_IRQ(sw->gpio), gpio_sw_irq_handler, 
     318                        IRQF_SHARED | trigger, sw->name, sw); 
     319        if (r < 0) { 
     320                printk(KERN_ERR "gpio-switch: request_irq() failed " 
     321                       "for GPIO %d\n", sw->gpio); 
     322                platform_device_unregister(&sw->pdev); 
     323                gpio_free(sw->gpio); 
     324                return r; 
     325        } 
     326 
     327        INIT_WORK(&sw->work, gpio_sw_handler); 
     328        init_timer(&sw->timer); 
     329 
     330        sw->timer.function = gpio_sw_timer; 
     331        sw->timer.data = (unsigned long)sw; 
     332 
     333        list_add(&sw->node, &gpio_switches); 
     334 
     335        return 0; 
     336} 
     337 
     338static int __init add_atag_switches(void) 
     339{ 
     340        const struct omap_gpio_switch_config *cfg; 
     341        struct gpio_switch *sw; 
     342        int i, r; 
     343 
     344        for (i = 0; ; i++) { 
     345                cfg = omap_get_nr_config(OMAP_TAG_GPIO_SWITCH, 
     346                                         struct omap_gpio_switch_config, i); 
     347                if (cfg == NULL) 
     348                        break; 
     349                sw = kzalloc(sizeof(*sw), GFP_KERNEL); 
     350                if (sw == NULL) { 
     351                        printk(KERN_ERR "gpio-switch: kmalloc failed\n"); 
     352                        return -ENOMEM; 
     353                } 
     354                strncpy(sw->name, cfg->name, sizeof(cfg->name)); 
     355                sw->gpio = cfg->gpio; 
     356                sw->flags = cfg->flags; 
     357                sw->type = cfg->type; 
     358                sw->debounce_rising = OMAP_GPIO_SW_DEFAULT_DEBOUNCE; 
     359                sw->debounce_falling = OMAP_GPIO_SW_DEFAULT_DEBOUNCE; 
     360                if ((r = new_switch(sw)) < 0) { 
     361                        kfree(sw); 
     362                        return r; 
     363                } 
     364        } 
     365        return 0; 
     366} 
     367 
     368static struct gpio_switch * __init find_switch(int gpio, const char *name) 
     369{ 
     370        struct gpio_switch *sw; 
     371 
     372        list_for_each_entry(sw, &gpio_switches, node) { 
     373                if ((gpio < 0 || sw->gpio != gpio) && 
     374                    (name == NULL || strcmp(sw->name, name) != 0)) 
     375                        continue; 
     376 
     377                if (gpio < 0 || name == NULL) 
     378                        goto no_check; 
     379 
     380                if (strcmp(sw->name, name) != 0) 
     381                        printk("gpio-switch: name mismatch for %d (%s, %s)\n", 
     382                               gpio, name, sw->name); 
     383                else if (sw->gpio != gpio) 
     384                        printk("gpio-switch: GPIO mismatch for %s (%d, %d)\n", 
     385                               name, gpio, sw->gpio); 
     386no_check: 
     387                return sw; 
     388        } 
     389        return NULL; 
     390} 
     391 
     392static int __init add_board_switches(void) 
     393{ 
     394        int i; 
     395 
     396        for (i = 0; i < board_gpio_sw_count; i++) { 
     397                const struct omap_gpio_switch *cfg; 
     398                struct gpio_switch *sw; 
     399                int r; 
     400 
     401                cfg = board_gpio_sw_table + i; 
     402                if (strlen(cfg->name) > sizeof(sw->name) - 1) 
     403                        return -EINVAL; 
     404                /* Check whether we only update an existing switch 
     405                 * or add a new switch. */ 
     406                sw = find_switch(cfg->gpio, cfg->name); 
     407                if (sw != NULL) { 
     408                        sw->debounce_rising = cfg->debounce_rising; 
     409                        sw->debounce_falling = cfg->debounce_falling; 
     410                        sw->notify = cfg->notify; 
     411                        sw->notify_data = cfg->notify_data; 
     412                        continue; 
     413                } else { 
     414                        if (cfg->gpio < 0 || cfg->name == NULL) { 
     415                                printk("gpio-switch: required switch not " 
     416                                       "found (%d, %s)\n", cfg->gpio, 
     417                                       cfg->name); 
     418                                continue; 
     419                        } 
     420                } 
     421                sw = kzalloc(sizeof(*sw), GFP_KERNEL); 
     422                if (sw == NULL) { 
     423                        printk(KERN_ERR "gpio-switch: kmalloc failed\n"); 
     424                        return -ENOMEM; 
     425                } 
     426                strlcpy(sw->name, cfg->name, sizeof(sw->name)); 
     427                sw->gpio = cfg->gpio; 
     428                sw->flags = cfg->flags; 
     429                sw->type = cfg->type; 
     430                sw->debounce_rising = cfg->debounce_rising; 
     431                sw->debounce_falling = cfg->debounce_falling; 
     432                sw->notify = cfg->notify; 
     433                sw->notify_data = cfg->notify_data; 
     434                if ((r = new_switch(sw)) < 0) { 
     435                        kfree(sw); 
     436                        return r; 
     437                } 
     438        } 
     439        return 0; 
     440} 
     441 
     442static void gpio_sw_cleanup(void) 
     443{ 
     444        struct gpio_switch *sw = NULL, *old = NULL; 
     445 
     446        list_for_each_entry(sw, &gpio_switches, node) { 
     447                if (old != NULL) 
     448                        kfree(old); 
     449                flush_scheduled_work(); 
     450                del_timer_sync(&sw->timer); 
     451 
     452                free_irq(OMAP_GPIO_IRQ(sw->gpio), sw); 
     453 
     454                device_remove_file(&sw->pdev.dev, &dev_attr_state); 
     455                device_remove_file(&sw->pdev.dev, &dev_attr_type); 
     456                device_remove_file(&sw->pdev.dev, &dev_attr_direction); 
     457 
     458                platform_device_unregister(&sw->pdev); 
     459                gpio_free(sw->gpio); 
     460                old = sw; 
     461        } 
     462        kfree(old); 
     463} 
     464 
     465static void __init report_initial_state(void) 
     466{ 
     467        struct gpio_switch *sw; 
     468 
     469        list_for_each_entry(sw, &gpio_switches, node) { 
     470                int state; 
     471 
     472                state = gpio_get_value(sw->gpio); 
     473                if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED) 
     474                        state = !state; 
     475                if (sw->notify != NULL) 
     476                        sw->notify(sw->notify_data, state); 
     477                print_sw_state(sw, state); 
     478        } 
     479} 
     480 
     481static int gpio_sw_remove(struct platform_device *dev) 
     482{ 
     483        return 0; 
     484} 
     485 
     486static struct platform_driver gpio_sw_driver = { 
     487        .remove         = gpio_sw_remove, 
     488        .driver         = { 
     489                .name   = "gpio-switch", 
     490        }, 
     491}; 
     492 
     493void __init omap_register_gpio_switches(const struct omap_gpio_switch *tbl, 
     494                                        int count) 
     495{ 
     496        BUG_ON(board_gpio_sw_table != NULL); 
     497 
     498        board_gpio_sw_table = tbl; 
     499        board_gpio_sw_count = count; 
     500} 
     501 
     502static int __init gpio_sw_init(void) 
     503{ 
     504        int r; 
     505 
     506        printk(KERN_INFO "OMAP GPIO switch handler initializing\n"); 
     507 
     508        r = platform_driver_register(&gpio_sw_driver); 
     509        if (r) 
     510                return r; 
     511 
     512        gpio_sw_platform_dev = platform_device_register_simple("gpio-switch", 
     513                                                               -1, NULL, 0); 
     514        if (IS_ERR(gpio_sw_platform_dev)) { 
     515                r = PTR_ERR(gpio_sw_platform_dev); 
     516                goto err1; 
     517        } 
     518 
     519        r = add_atag_switches(); 
     520        if (r < 0) 
     521                goto err2; 
     522 
     523        r = add_board_switches(); 
     524        if (r < 0) 
     525                goto err2; 
     526 
     527        report_initial_state(); 
     528 
     529        return 0; 
     530err2: 
     531        gpio_sw_cleanup(); 
     532        platform_device_unregister(gpio_sw_platform_dev); 
     533err1: 
     534        platform_driver_unregister(&gpio_sw_driver); 
     535        return r; 
     536} 
     537 
     538static void __exit gpio_sw_exit(void) 
     539{ 
     540        gpio_sw_cleanup(); 
     541        platform_device_unregister(gpio_sw_platform_dev); 
     542        platform_driver_unregister(&gpio_sw_driver); 
     543} 
     544 
     545#ifndef MODULE 
     546late_initcall(gpio_sw_init); 
     547#else 
     548module_init(gpio_sw_init); 
     549#endif 
     550module_exit(gpio_sw_exit); 
     551 
     552MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>, Paul Mundt <paul.mundt@nokia.com"); 
     553MODULE_DESCRIPTION("GPIO switch driver"); 
     554MODULE_LICENSE("GPL"); 
  • arch/arm/plat-omap/include/plat/board.h

    a b struct omap_board_config_kernel { 
    151151        const void *data; 
    152152}; 
    153153 
     154struct omap_gpio_switch_config { 
     155        char name[12]; 
     156        u16 gpio; 
     157        int flags:4; 
     158        int type:4; 
     159        int key_code:24; /* Linux key code */ 
     160}; 
     161 
    154162extern const void *__init __omap_get_config(u16 tag, size_t len, int nr); 
    155163 
    156164#define omap_get_config(tag, type) \ 
Note: See TracBrowser for help on using the repository browser.