Path: blob/master/arch/cris/arch-v10/kernel/io_interface_mux.c
15125 views
/* IO interface mux allocator for ETRAX100LX.1* Copyright 2004-2007, Axis Communications AB2*/345/* C.f. ETRAX100LX Designer's Reference chapter 19.9 */67#include <linux/kernel.h>8#include <linux/slab.h>9#include <linux/errno.h>10#include <linux/module.h>11#include <linux/init.h>1213#include <arch/svinto.h>14#include <asm/io.h>15#include <arch/io_interface_mux.h>161718#define DBG(s)1920/* Macro to access ETRAX 100 registers */21#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \22IO_STATE_(reg##_, field##_, _##val)2324enum io_if_group {25group_a = (1<<0),26group_b = (1<<1),27group_c = (1<<2),28group_d = (1<<3),29group_e = (1<<4),30group_f = (1<<5)31};3233struct watcher34{35void (*notify)(const unsigned int gpio_in_available,36const unsigned int gpio_out_available,37const unsigned char pa_available,38const unsigned char pb_available);39struct watcher *next;40};414243struct if_group44{45enum io_if_group group;46/* name - the name of the group 'A' to 'F' */47char *name;48/* used - a bit mask of all pins in the group in the order listed49* in the tables in 19.9.1 to 19.9.6. Note that no50* distinction is made between in, out and in/out pins. */51unsigned int used;52};535455struct interface56{57enum cris_io_interface ioif;58/* name - the name of the interface */59char *name;60/* groups - OR'ed together io_if_group flags describing what pin groups61* the interface uses pins in. */62unsigned char groups;63/* used - set when the interface is allocated. */64unsigned char used;65char *owner;66/* group_a through group_f - bit masks describing what pins in the67* pin groups the interface uses. */68unsigned int group_a;69unsigned int group_b;70unsigned int group_c;71unsigned int group_d;72unsigned int group_e;73unsigned int group_f;7475/* gpio_g_in, gpio_g_out, gpio_b - bit masks telling what pins in the76* GPIO ports the interface uses. This could be reconstucted using77* the group_X masks and a table of what pins the GPIO ports use,78* but that would be messy. */79unsigned int gpio_g_in;80unsigned int gpio_g_out;81unsigned char gpio_b;82};8384static struct if_group if_groups[6] = {85{86.group = group_a,87.name = "A",88.used = 0,89},90{91.group = group_b,92.name = "B",93.used = 0,94},95{96.group = group_c,97.name = "C",98.used = 0,99},100{101.group = group_d,102.name = "D",103.used = 0,104},105{106.group = group_e,107.name = "E",108.used = 0,109},110{111.group = group_f,112.name = "F",113.used = 0,114}115};116117/* The order in the array must match the order of enum118* cris_io_interface in io_interface_mux.h */119static struct interface interfaces[] = {120/* Begin Non-multiplexed interfaces */121{122.ioif = if_eth,123.name = "ethernet",124.groups = 0,125126.group_a = 0,127.group_b = 0,128.group_c = 0,129.group_d = 0,130.group_e = 0,131.group_f = 0,132133.gpio_g_in = 0,134.gpio_g_out = 0,135.gpio_b = 0136},137{138.ioif = if_serial_0,139.name = "serial_0",140.groups = 0,141142.group_a = 0,143.group_b = 0,144.group_c = 0,145.group_d = 0,146.group_e = 0,147.group_f = 0,148149.gpio_g_in = 0,150.gpio_g_out = 0,151.gpio_b = 0152},153/* End Non-multiplexed interfaces */154{155.ioif = if_serial_1,156.name = "serial_1",157.groups = group_e,158159.group_a = 0,160.group_b = 0,161.group_c = 0,162.group_d = 0,163.group_e = 0x0f,164.group_f = 0,165166.gpio_g_in = 0x00000000,167.gpio_g_out = 0x00000000,168.gpio_b = 0x00169},170{171.ioif = if_serial_2,172.name = "serial_2",173.groups = group_b,174175.group_a = 0,176.group_b = 0x0f,177.group_c = 0,178.group_d = 0,179.group_e = 0,180.group_f = 0,181182.gpio_g_in = 0x000000c0,183.gpio_g_out = 0x000000c0,184.gpio_b = 0x00185},186{187.ioif = if_serial_3,188.name = "serial_3",189.groups = group_c,190191.group_a = 0,192.group_b = 0,193.group_c = 0x0f,194.group_d = 0,195.group_e = 0,196.group_f = 0,197198.gpio_g_in = 0xc0000000,199.gpio_g_out = 0xc0000000,200.gpio_b = 0x00201},202{203.ioif = if_sync_serial_1,204.name = "sync_serial_1",205.groups = group_e | group_f,206207.group_a = 0,208.group_b = 0,209.group_c = 0,210.group_d = 0,211.group_e = 0x0f,212.group_f = 0x10,213214.gpio_g_in = 0x00000000,215.gpio_g_out = 0x00000000,216.gpio_b = 0x10217},218{219.ioif = if_sync_serial_3,220.name = "sync_serial_3",221.groups = group_c | group_f,222223.group_a = 0,224.group_b = 0,225.group_c = 0x0f,226.group_d = 0,227.group_e = 0,228.group_f = 0x80,229230.gpio_g_in = 0xc0000000,231.gpio_g_out = 0xc0000000,232.gpio_b = 0x80233},234{235.ioif = if_shared_ram,236.name = "shared_ram",237.groups = group_a,238239.group_a = 0x7f8ff,240.group_b = 0,241.group_c = 0,242.group_d = 0,243.group_e = 0,244.group_f = 0,245246.gpio_g_in = 0x0000ff3e,247.gpio_g_out = 0x0000ff38,248.gpio_b = 0x00249},250{251.ioif = if_shared_ram_w,252.name = "shared_ram_w",253.groups = group_a | group_d,254255.group_a = 0x7f8ff,256.group_b = 0,257.group_c = 0,258.group_d = 0xff,259.group_e = 0,260.group_f = 0,261262.gpio_g_in = 0x00ffff3e,263.gpio_g_out = 0x00ffff38,264.gpio_b = 0x00265},266{267.ioif = if_par_0,268.name = "par_0",269.groups = group_a,270271.group_a = 0x7fbff,272.group_b = 0,273.group_c = 0,274.group_d = 0,275.group_e = 0,276.group_f = 0,277278.gpio_g_in = 0x0000ff3e,279.gpio_g_out = 0x0000ff3e,280.gpio_b = 0x00281},282{283.ioif = if_par_1,284.name = "par_1",285.groups = group_d,286287.group_a = 0,288.group_b = 0,289.group_c = 0,290.group_d = 0x7feff,291.group_e = 0,292.group_f = 0,293294.gpio_g_in = 0x3eff0000,295.gpio_g_out = 0x3eff0000,296.gpio_b = 0x00297},298{299.ioif = if_par_w,300.name = "par_w",301.groups = group_a | group_d,302303.group_a = 0x7fbff,304.group_b = 0,305.group_c = 0,306.group_d = 0xff,307.group_e = 0,308.group_f = 0,309310.gpio_g_in = 0x00ffff3e,311.gpio_g_out = 0x00ffff3e,312.gpio_b = 0x00313},314{315.ioif = if_scsi8_0,316.name = "scsi8_0",317.groups = group_a | group_b | group_f,318319.group_a = 0x7ffff,320.group_b = 0x0f,321.group_c = 0,322.group_d = 0,323.group_e = 0,324.group_f = 0x10,325326.gpio_g_in = 0x0000ffff,327.gpio_g_out = 0x0000ffff,328.gpio_b = 0x10329},330{331.ioif = if_scsi8_1,332.name = "scsi8_1",333.groups = group_c | group_d | group_f,334335.group_a = 0,336.group_b = 0,337.group_c = 0x0f,338.group_d = 0x7ffff,339.group_e = 0,340.group_f = 0x80,341342.gpio_g_in = 0xffff0000,343.gpio_g_out = 0xffff0000,344.gpio_b = 0x80345},346{347.ioif = if_scsi_w,348.name = "scsi_w",349.groups = group_a | group_b | group_d | group_f,350351.group_a = 0x7ffff,352.group_b = 0x0f,353.group_c = 0,354.group_d = 0x601ff,355.group_e = 0,356.group_f = 0x90,357358.gpio_g_in = 0x01ffffff,359.gpio_g_out = 0x07ffffff,360.gpio_b = 0x80361},362{363.ioif = if_ata,364.name = "ata",365.groups = group_a | group_b | group_c | group_d,366367.group_a = 0x7ffff,368.group_b = 0x0f,369.group_c = 0x0f,370.group_d = 0x7cfff,371.group_e = 0,372.group_f = 0,373374.gpio_g_in = 0xf9ffffff,375.gpio_g_out = 0xffffffff,376.gpio_b = 0x80377},378{379.ioif = if_csp,380.name = "csp",381.groups = group_f,382383.group_a = 0,384.group_b = 0,385.group_c = 0,386.group_d = 0,387.group_e = 0,388.group_f = 0xfc,389390.gpio_g_in = 0x00000000,391.gpio_g_out = 0x00000000,392.gpio_b = 0xfc393},394{395.ioif = if_i2c,396.name = "i2c",397.groups = group_f,398399.group_a = 0,400.group_b = 0,401.group_c = 0,402.group_d = 0,403.group_e = 0,404.group_f = 0x03,405406.gpio_g_in = 0x00000000,407.gpio_g_out = 0x00000000,408.gpio_b = 0x03409},410{411.ioif = if_usb_1,412.name = "usb_1",413.groups = group_e | group_f,414415.group_a = 0,416.group_b = 0,417.group_c = 0,418.group_d = 0,419.group_e = 0x0f,420.group_f = 0x2c,421422.gpio_g_in = 0x00000000,423.gpio_g_out = 0x00000000,424.gpio_b = 0x2c425},426{427.ioif = if_usb_2,428.name = "usb_2",429.groups = group_d,430431.group_a = 0,432.group_b = 0,433.group_c = 0,434.group_d = 0,435.group_e = 0x33e00,436.group_f = 0,437438.gpio_g_in = 0x3e000000,439.gpio_g_out = 0x0c000000,440.gpio_b = 0x00441},442/* GPIO pins */443{444.ioif = if_gpio_grp_a,445.name = "gpio_a",446.groups = group_a,447448.group_a = 0,449.group_b = 0,450.group_c = 0,451.group_d = 0,452.group_e = 0,453.group_f = 0,454455.gpio_g_in = 0x0000ff3f,456.gpio_g_out = 0x0000ff3f,457.gpio_b = 0x00458},459{460.ioif = if_gpio_grp_b,461.name = "gpio_b",462.groups = group_b,463464.group_a = 0,465.group_b = 0,466.group_c = 0,467.group_d = 0,468.group_e = 0,469.group_f = 0,470471.gpio_g_in = 0x000000c0,472.gpio_g_out = 0x000000c0,473.gpio_b = 0x00474},475{476.ioif = if_gpio_grp_c,477.name = "gpio_c",478.groups = group_c,479480.group_a = 0,481.group_b = 0,482.group_c = 0,483.group_d = 0,484.group_e = 0,485.group_f = 0,486487.gpio_g_in = 0xc0000000,488.gpio_g_out = 0xc0000000,489.gpio_b = 0x00490},491{492.ioif = if_gpio_grp_d,493.name = "gpio_d",494.groups = group_d,495496.group_a = 0,497.group_b = 0,498.group_c = 0,499.group_d = 0,500.group_e = 0,501.group_f = 0,502503.gpio_g_in = 0x3fff0000,504.gpio_g_out = 0x3fff0000,505.gpio_b = 0x00506},507{508.ioif = if_gpio_grp_e,509.name = "gpio_e",510.groups = group_e,511512.group_a = 0,513.group_b = 0,514.group_c = 0,515.group_d = 0,516.group_e = 0,517.group_f = 0,518519.gpio_g_in = 0x00000000,520.gpio_g_out = 0x00000000,521.gpio_b = 0x00522},523{524.ioif = if_gpio_grp_f,525.name = "gpio_f",526.groups = group_f,527528.group_a = 0,529.group_b = 0,530.group_c = 0,531.group_d = 0,532.group_e = 0,533.group_f = 0,534535.gpio_g_in = 0x00000000,536.gpio_g_out = 0x00000000,537.gpio_b = 0xff538}539/* Array end */540};541542static struct watcher *watchers = NULL;543544/* The pins that are free to use in the GPIO ports. */545static unsigned int gpio_in_pins = 0xffffffff;546static unsigned int gpio_out_pins = 0xffffffff;547static unsigned char gpio_pb_pins = 0xff;548static unsigned char gpio_pa_pins = 0xff;549550/* Identifiers for the owners of the GPIO pins. */551static enum cris_io_interface gpio_pa_owners[8];552static enum cris_io_interface gpio_pb_owners[8];553static enum cris_io_interface gpio_pg_owners[32];554555static int cris_io_interface_init(void);556557static unsigned char clear_group_from_set(const unsigned char groups, struct if_group *group)558{559return (groups & ~group->group);560}561562563static struct if_group *get_group(const unsigned char groups)564{565int i;566for (i = 0; i < ARRAY_SIZE(if_groups); i++) {567if (groups & if_groups[i].group) {568return &if_groups[i];569}570}571return NULL;572}573574575static void notify_watchers(void)576{577struct watcher *w = watchers;578579DBG(printk("io_interface_mux: notifying watchers\n"));580581while (NULL != w) {582w->notify((const unsigned int)gpio_in_pins,583(const unsigned int)gpio_out_pins,584(const unsigned char)gpio_pa_pins,585(const unsigned char)gpio_pb_pins);586w = w->next;587}588}589590591int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id)592{593int set_gen_config = 0;594int set_gen_config_ii = 0;595unsigned long int gens;596unsigned long int gens_ii;597struct if_group *grp;598unsigned char group_set;599unsigned long flags;600int res = 0;601602(void)cris_io_interface_init();603604DBG(printk("cris_request_io_interface(%d, \"%s\")\n", ioif, device_id));605606if ((ioif >= if_max_interfaces) || (ioif < 0)) {607printk(KERN_CRIT "cris_request_io_interface: Bad interface "608"%u submitted for %s\n",609ioif,610device_id);611return -EINVAL;612}613614local_irq_save(flags);615616if (interfaces[ioif].used) {617printk(KERN_CRIT "cris_io_interface: Cannot allocate interface "618"%s for %s, in use by %s\n",619interfaces[ioif].name,620device_id,621interfaces[ioif].owner);622res = -EBUSY;623goto exit;624}625626/* Check that all required pins in the used groups are free627* before allocating. */628group_set = interfaces[ioif].groups;629while (NULL != (grp = get_group(group_set))) {630unsigned int if_group_use = 0;631632switch (grp->group) {633case group_a:634if_group_use = interfaces[ioif].group_a;635break;636case group_b:637if_group_use = interfaces[ioif].group_b;638break;639case group_c:640if_group_use = interfaces[ioif].group_c;641break;642case group_d:643if_group_use = interfaces[ioif].group_d;644break;645case group_e:646if_group_use = interfaces[ioif].group_e;647break;648case group_f:649if_group_use = interfaces[ioif].group_f;650break;651default:652BUG_ON(1);653}654655if (if_group_use & grp->used) {656printk(KERN_INFO "cris_request_io_interface: group "657"%s needed by %s not available\n",658grp->name, interfaces[ioif].name);659res = -EBUSY;660goto exit;661}662663group_set = clear_group_from_set(group_set, grp);664}665666/* Are the required GPIO pins available too? */667if (((interfaces[ioif].gpio_g_in & gpio_in_pins) !=668interfaces[ioif].gpio_g_in) ||669((interfaces[ioif].gpio_g_out & gpio_out_pins) !=670interfaces[ioif].gpio_g_out) ||671((interfaces[ioif].gpio_b & gpio_pb_pins) !=672interfaces[ioif].gpio_b)) {673printk(KERN_CRIT "cris_request_io_interface: Could not get "674"required pins for interface %u\n", ioif);675res = -EBUSY;676goto exit;677}678679/* Check which registers need to be reconfigured. */680gens = genconfig_shadow;681gens_ii = gen_config_ii_shadow;682683set_gen_config = 1;684switch (ioif)685{686/* Begin Non-multiplexed interfaces */687case if_eth:688/* fall through */689case if_serial_0:690set_gen_config = 0;691break;692/* End Non-multiplexed interfaces */693case if_serial_1:694set_gen_config_ii = 1;695SETS(gens_ii, R_GEN_CONFIG_II, sermode1, async);696break;697case if_serial_2:698SETS(gens, R_GEN_CONFIG, ser2, select);699break;700case if_serial_3:701SETS(gens, R_GEN_CONFIG, ser3, select);702set_gen_config_ii = 1;703SETS(gens_ii, R_GEN_CONFIG_II, sermode3, async);704break;705case if_sync_serial_1:706set_gen_config_ii = 1;707SETS(gens_ii, R_GEN_CONFIG_II, sermode1, sync);708break;709case if_sync_serial_3:710SETS(gens, R_GEN_CONFIG, ser3, select);711set_gen_config_ii = 1;712SETS(gens_ii, R_GEN_CONFIG_II, sermode3, sync);713break;714case if_shared_ram:715SETS(gens, R_GEN_CONFIG, mio, select);716break;717case if_shared_ram_w:718SETS(gens, R_GEN_CONFIG, mio_w, select);719break;720case if_par_0:721SETS(gens, R_GEN_CONFIG, par0, select);722break;723case if_par_1:724SETS(gens, R_GEN_CONFIG, par1, select);725break;726case if_par_w:727SETS(gens, R_GEN_CONFIG, par0, select);728SETS(gens, R_GEN_CONFIG, par_w, select);729break;730case if_scsi8_0:731SETS(gens, R_GEN_CONFIG, scsi0, select);732break;733case if_scsi8_1:734SETS(gens, R_GEN_CONFIG, scsi1, select);735break;736case if_scsi_w:737SETS(gens, R_GEN_CONFIG, scsi0, select);738SETS(gens, R_GEN_CONFIG, scsi0w, select);739break;740case if_ata:741SETS(gens, R_GEN_CONFIG, ata, select);742break;743case if_csp:744/* fall through */745case if_i2c:746set_gen_config = 0;747break;748case if_usb_1:749SETS(gens, R_GEN_CONFIG, usb1, select);750break;751case if_usb_2:752SETS(gens, R_GEN_CONFIG, usb2, select);753break;754case if_gpio_grp_a:755/* GPIO groups are only accounted, don't do configuration changes. */756/* fall through */757case if_gpio_grp_b:758/* fall through */759case if_gpio_grp_c:760/* fall through */761case if_gpio_grp_d:762/* fall through */763case if_gpio_grp_e:764/* fall through */765case if_gpio_grp_f:766set_gen_config = 0;767break;768default:769printk(KERN_INFO "cris_request_io_interface: Bad interface "770"%u submitted for %s\n",771ioif, device_id);772res = -EBUSY;773goto exit;774}775776/* All needed I/O pins and pin groups are free, allocate. */777group_set = interfaces[ioif].groups;778while (NULL != (grp = get_group(group_set))) {779unsigned int if_group_use = 0;780781switch (grp->group) {782case group_a:783if_group_use = interfaces[ioif].group_a;784break;785case group_b:786if_group_use = interfaces[ioif].group_b;787break;788case group_c:789if_group_use = interfaces[ioif].group_c;790break;791case group_d:792if_group_use = interfaces[ioif].group_d;793break;794case group_e:795if_group_use = interfaces[ioif].group_e;796break;797case group_f:798if_group_use = interfaces[ioif].group_f;799break;800default:801BUG_ON(1);802}803grp->used |= if_group_use;804805group_set = clear_group_from_set(group_set, grp);806}807808interfaces[ioif].used = 1;809interfaces[ioif].owner = (char*)device_id;810811if (set_gen_config) {812volatile int i;813genconfig_shadow = gens;814*R_GEN_CONFIG = genconfig_shadow;815/* Wait 12 cycles before doing any DMA command */816for(i = 6; i > 0; i--)817nop();818}819if (set_gen_config_ii) {820gen_config_ii_shadow = gens_ii;821*R_GEN_CONFIG_II = gen_config_ii_shadow;822}823824DBG(printk(KERN_DEBUG "GPIO pins: available before: "825"g_in=0x%08x g_out=0x%08x pb=0x%02x\n",826gpio_in_pins, gpio_out_pins, gpio_pb_pins));827DBG(printk(KERN_DEBUG828"grabbing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",829interfaces[ioif].gpio_g_in,830interfaces[ioif].gpio_g_out,831interfaces[ioif].gpio_b));832833gpio_in_pins &= ~interfaces[ioif].gpio_g_in;834gpio_out_pins &= ~interfaces[ioif].gpio_g_out;835gpio_pb_pins &= ~interfaces[ioif].gpio_b;836837DBG(printk(KERN_DEBUG "GPIO pins: available after: "838"g_in=0x%08x g_out=0x%08x pb=0x%02x\n",839gpio_in_pins, gpio_out_pins, gpio_pb_pins));840841exit:842local_irq_restore(flags);843if (res == 0)844notify_watchers();845return res;846}847848849void cris_free_io_interface(enum cris_io_interface ioif)850{851struct if_group *grp;852unsigned char group_set;853unsigned long flags;854855(void)cris_io_interface_init();856857if ((ioif >= if_max_interfaces) || (ioif < 0)) {858printk(KERN_CRIT "cris_free_io_interface: Bad interface %u\n",859ioif);860return;861}862local_irq_save(flags);863if (!interfaces[ioif].used) {864printk(KERN_CRIT "cris_free_io_interface: Freeing free interface %u\n",865ioif);866local_irq_restore(flags);867return;868}869group_set = interfaces[ioif].groups;870while (NULL != (grp = get_group(group_set))) {871unsigned int if_group_use = 0;872873switch (grp->group) {874case group_a:875if_group_use = interfaces[ioif].group_a;876break;877case group_b:878if_group_use = interfaces[ioif].group_b;879break;880case group_c:881if_group_use = interfaces[ioif].group_c;882break;883case group_d:884if_group_use = interfaces[ioif].group_d;885break;886case group_e:887if_group_use = interfaces[ioif].group_e;888break;889case group_f:890if_group_use = interfaces[ioif].group_f;891break;892default:893BUG_ON(1);894}895896if ((grp->used & if_group_use) != if_group_use)897BUG_ON(1);898grp->used = grp->used & ~if_group_use;899900group_set = clear_group_from_set(group_set, grp);901}902interfaces[ioif].used = 0;903interfaces[ioif].owner = NULL;904905DBG(printk("GPIO pins: available before: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",906gpio_in_pins, gpio_out_pins, gpio_pb_pins));907DBG(printk("freeing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",908interfaces[ioif].gpio_g_in,909interfaces[ioif].gpio_g_out,910interfaces[ioif].gpio_b));911912gpio_in_pins |= interfaces[ioif].gpio_g_in;913gpio_out_pins |= interfaces[ioif].gpio_g_out;914gpio_pb_pins |= interfaces[ioif].gpio_b;915916DBG(printk("GPIO pins: available after: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",917gpio_in_pins, gpio_out_pins, gpio_pb_pins));918919local_irq_restore(flags);920921notify_watchers();922}923924/* Create a bitmask from bit 0 (inclusive) to bit stop_bit925(non-inclusive). stop_bit == 0 returns 0x0 */926static inline unsigned int create_mask(const unsigned stop_bit)927{928/* Avoid overflow */929if (stop_bit >= 32) {930return 0xffffffff;931}932return (1<<stop_bit)-1;933}934935936/* port can be 'a', 'b' or 'g' */937int cris_io_interface_allocate_pins(const enum cris_io_interface ioif,938const char port,939const unsigned start_bit,940const unsigned stop_bit)941{942unsigned int i;943unsigned int mask = 0;944unsigned int tmp_mask;945unsigned long int flags;946enum cris_io_interface *owners;947948(void)cris_io_interface_init();949950DBG(printk("cris_io_interface_allocate_pins: if=%d port=%c start=%u stop=%u\n",951ioif, port, start_bit, stop_bit));952953if (!((start_bit <= stop_bit) &&954((((port == 'a') || (port == 'b')) && (stop_bit < 8)) ||955((port == 'g') && (stop_bit < 32))))) {956return -EINVAL;957}958959mask = create_mask(stop_bit + 1);960tmp_mask = create_mask(start_bit);961mask &= ~tmp_mask;962963DBG(printk("cris_io_interface_allocate_pins: port=%c start=%u stop=%u mask=0x%08x\n",964port, start_bit, stop_bit, mask));965966local_irq_save(flags);967968switch (port) {969case 'a':970if ((gpio_pa_pins & mask) != mask) {971local_irq_restore(flags);972return -EBUSY;973}974owners = gpio_pa_owners;975gpio_pa_pins &= ~mask;976break;977case 'b':978if ((gpio_pb_pins & mask) != mask) {979local_irq_restore(flags);980return -EBUSY;981}982owners = gpio_pb_owners;983gpio_pb_pins &= ~mask;984break;985case 'g':986if (((gpio_in_pins & mask) != mask) ||987((gpio_out_pins & mask) != mask)) {988local_irq_restore(flags);989return -EBUSY;990}991owners = gpio_pg_owners;992gpio_in_pins &= ~mask;993gpio_out_pins &= ~mask;994break;995default:996local_irq_restore(flags);997return -EINVAL;998}9991000for (i = start_bit; i <= stop_bit; i++) {1001owners[i] = ioif;1002}1003local_irq_restore(flags);10041005notify_watchers();1006return 0;1007}100810091010/* port can be 'a', 'b' or 'g' */1011int cris_io_interface_free_pins(const enum cris_io_interface ioif,1012const char port,1013const unsigned start_bit,1014const unsigned stop_bit)1015{1016unsigned int i;1017unsigned int mask = 0;1018unsigned int tmp_mask;1019unsigned long int flags;1020enum cris_io_interface *owners;10211022(void)cris_io_interface_init();10231024if (!((start_bit <= stop_bit) &&1025((((port == 'a') || (port == 'b')) && (stop_bit < 8)) ||1026((port == 'g') && (stop_bit < 32))))) {1027return -EINVAL;1028}10291030mask = create_mask(stop_bit + 1);1031tmp_mask = create_mask(start_bit);1032mask &= ~tmp_mask;10331034DBG(printk("cris_io_interface_free_pins: port=%c start=%u stop=%u mask=0x%08x\n",1035port, start_bit, stop_bit, mask));10361037local_irq_save(flags);10381039switch (port) {1040case 'a':1041if ((~gpio_pa_pins & mask) != mask) {1042local_irq_restore(flags);1043printk(KERN_CRIT "cris_io_interface_free_pins: Freeing free pins");1044}1045owners = gpio_pa_owners;1046break;1047case 'b':1048if ((~gpio_pb_pins & mask) != mask) {1049local_irq_restore(flags);1050printk(KERN_CRIT "cris_io_interface_free_pins: Freeing free pins");1051}1052owners = gpio_pb_owners;1053break;1054case 'g':1055if (((~gpio_in_pins & mask) != mask) ||1056((~gpio_out_pins & mask) != mask)) {1057local_irq_restore(flags);1058printk(KERN_CRIT "cris_io_interface_free_pins: Freeing free pins");1059}1060owners = gpio_pg_owners;1061break;1062default:1063owners = NULL; /* Cannot happen. Shut up, gcc! */1064}10651066for (i = start_bit; i <= stop_bit; i++) {1067if (owners[i] != ioif) {1068printk(KERN_CRIT "cris_io_interface_free_pins: Freeing unowned pins");1069}1070}10711072/* All was ok, change data. */1073switch (port) {1074case 'a':1075gpio_pa_pins |= mask;1076break;1077case 'b':1078gpio_pb_pins |= mask;1079break;1080case 'g':1081gpio_in_pins |= mask;1082gpio_out_pins |= mask;1083break;1084}10851086for (i = start_bit; i <= stop_bit; i++) {1087owners[i] = if_unclaimed;1088}1089local_irq_restore(flags);1090notify_watchers();10911092return 0;1093}109410951096int cris_io_interface_register_watcher(void (*notify)(const unsigned int gpio_in_available,1097const unsigned int gpio_out_available,1098const unsigned char pa_available,1099const unsigned char pb_available))1100{1101struct watcher *w;11021103(void)cris_io_interface_init();11041105if (NULL == notify) {1106return -EINVAL;1107}1108w = kmalloc(sizeof(*w), GFP_KERNEL);1109if (!w) {1110return -ENOMEM;1111}1112w->notify = notify;1113w->next = watchers;1114watchers = w;11151116w->notify((const unsigned int)gpio_in_pins,1117(const unsigned int)gpio_out_pins,1118(const unsigned char)gpio_pa_pins,1119(const unsigned char)gpio_pb_pins);11201121return 0;1122}11231124void cris_io_interface_delete_watcher(void (*notify)(const unsigned int gpio_in_available,1125const unsigned int gpio_out_available,1126const unsigned char pa_available,1127const unsigned char pb_available))1128{1129struct watcher *w = watchers, *prev = NULL;11301131(void)cris_io_interface_init();11321133while ((NULL != w) && (w->notify != notify)){1134prev = w;1135w = w->next;1136}1137if (NULL != w) {1138if (NULL != prev) {1139prev->next = w->next;1140} else {1141watchers = w->next;1142}1143kfree(w);1144return;1145}1146printk(KERN_WARNING "cris_io_interface_delete_watcher: Deleting unknown watcher 0x%p\n", notify);1147}114811491150static int cris_io_interface_init(void)1151{1152static int first = 1;1153int i;11541155if (!first) {1156return 0;1157}1158first = 0;11591160for (i = 0; i<8; i++) {1161gpio_pa_owners[i] = if_unclaimed;1162gpio_pb_owners[i] = if_unclaimed;1163gpio_pg_owners[i] = if_unclaimed;1164}1165for (; i<32; i++) {1166gpio_pg_owners[i] = if_unclaimed;1167}1168return 0;1169}117011711172module_init(cris_io_interface_init);117311741175EXPORT_SYMBOL(cris_request_io_interface);1176EXPORT_SYMBOL(cris_free_io_interface);1177EXPORT_SYMBOL(cris_io_interface_allocate_pins);1178EXPORT_SYMBOL(cris_io_interface_free_pins);1179EXPORT_SYMBOL(cris_io_interface_register_watcher);1180EXPORT_SYMBOL(cris_io_interface_delete_watcher);118111821183