1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183 |
- /* IO interface mux allocator for ETRAX100LX.
- * Copyright 2004-2007, Axis Communications AB
- */
- /* C.f. ETRAX100LX Designer's Reference chapter 19.9 */
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/errno.h>
- #include <linux/module.h>
- #include <linux/init.h>
- #include <arch/svinto.h>
- #include <asm/io.h>
- #include <arch/io_interface_mux.h>
- #include <arch/system.h>
- #define DBG(s)
- /* Macro to access ETRAX 100 registers */
- #define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
- IO_STATE_(reg##_, field##_, _##val)
- enum io_if_group {
- group_a = (1<<0),
- group_b = (1<<1),
- group_c = (1<<2),
- group_d = (1<<3),
- group_e = (1<<4),
- group_f = (1<<5)
- };
- struct watcher
- {
- void (*notify)(const unsigned int gpio_in_available,
- const unsigned int gpio_out_available,
- const unsigned char pa_available,
- const unsigned char pb_available);
- struct watcher *next;
- };
- struct if_group
- {
- enum io_if_group group;
- /* name - the name of the group 'A' to 'F' */
- char *name;
- /* used - a bit mask of all pins in the group in the order listed
- * in the tables in 19.9.1 to 19.9.6. Note that no
- * distinction is made between in, out and in/out pins. */
- unsigned int used;
- };
- struct interface
- {
- enum cris_io_interface ioif;
- /* name - the name of the interface */
- char *name;
- /* groups - OR'ed together io_if_group flags describing what pin groups
- * the interface uses pins in. */
- unsigned char groups;
- /* used - set when the interface is allocated. */
- unsigned char used;
- char *owner;
- /* group_a through group_f - bit masks describing what pins in the
- * pin groups the interface uses. */
- unsigned int group_a;
- unsigned int group_b;
- unsigned int group_c;
- unsigned int group_d;
- unsigned int group_e;
- unsigned int group_f;
- /* gpio_g_in, gpio_g_out, gpio_b - bit masks telling what pins in the
- * GPIO ports the interface uses. This could be reconstucted using
- * the group_X masks and a table of what pins the GPIO ports use,
- * but that would be messy. */
- unsigned int gpio_g_in;
- unsigned int gpio_g_out;
- unsigned char gpio_b;
- };
- static struct if_group if_groups[6] = {
- {
- .group = group_a,
- .name = "A",
- .used = 0,
- },
- {
- .group = group_b,
- .name = "B",
- .used = 0,
- },
- {
- .group = group_c,
- .name = "C",
- .used = 0,
- },
- {
- .group = group_d,
- .name = "D",
- .used = 0,
- },
- {
- .group = group_e,
- .name = "E",
- .used = 0,
- },
- {
- .group = group_f,
- .name = "F",
- .used = 0,
- }
- };
- /* The order in the array must match the order of enum
- * cris_io_interface in io_interface_mux.h */
- static struct interface interfaces[] = {
- /* Begin Non-multiplexed interfaces */
- {
- .ioif = if_eth,
- .name = "ethernet",
- .groups = 0,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0,
- .group_f = 0,
- .gpio_g_in = 0,
- .gpio_g_out = 0,
- .gpio_b = 0
- },
- {
- .ioif = if_serial_0,
- .name = "serial_0",
- .groups = 0,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0,
- .group_f = 0,
- .gpio_g_in = 0,
- .gpio_g_out = 0,
- .gpio_b = 0
- },
- /* End Non-multiplexed interfaces */
- {
- .ioif = if_serial_1,
- .name = "serial_1",
- .groups = group_e,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0x0f,
- .group_f = 0,
- .gpio_g_in = 0x00000000,
- .gpio_g_out = 0x00000000,
- .gpio_b = 0x00
- },
- {
- .ioif = if_serial_2,
- .name = "serial_2",
- .groups = group_b,
- .group_a = 0,
- .group_b = 0x0f,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0,
- .group_f = 0,
- .gpio_g_in = 0x000000c0,
- .gpio_g_out = 0x000000c0,
- .gpio_b = 0x00
- },
- {
- .ioif = if_serial_3,
- .name = "serial_3",
- .groups = group_c,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0x0f,
- .group_d = 0,
- .group_e = 0,
- .group_f = 0,
- .gpio_g_in = 0xc0000000,
- .gpio_g_out = 0xc0000000,
- .gpio_b = 0x00
- },
- {
- .ioif = if_sync_serial_1,
- .name = "sync_serial_1",
- .groups = group_e | group_f,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0x0f,
- .group_f = 0x10,
- .gpio_g_in = 0x00000000,
- .gpio_g_out = 0x00000000,
- .gpio_b = 0x10
- },
- {
- .ioif = if_sync_serial_3,
- .name = "sync_serial_3",
- .groups = group_c | group_f,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0x0f,
- .group_d = 0,
- .group_e = 0,
- .group_f = 0x80,
- .gpio_g_in = 0xc0000000,
- .gpio_g_out = 0xc0000000,
- .gpio_b = 0x80
- },
- {
- .ioif = if_shared_ram,
- .name = "shared_ram",
- .groups = group_a,
- .group_a = 0x7f8ff,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0,
- .group_f = 0,
- .gpio_g_in = 0x0000ff3e,
- .gpio_g_out = 0x0000ff38,
- .gpio_b = 0x00
- },
- {
- .ioif = if_shared_ram_w,
- .name = "shared_ram_w",
- .groups = group_a | group_d,
- .group_a = 0x7f8ff,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0xff,
- .group_e = 0,
- .group_f = 0,
- .gpio_g_in = 0x00ffff3e,
- .gpio_g_out = 0x00ffff38,
- .gpio_b = 0x00
- },
- {
- .ioif = if_par_0,
- .name = "par_0",
- .groups = group_a,
- .group_a = 0x7fbff,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0,
- .group_f = 0,
- .gpio_g_in = 0x0000ff3e,
- .gpio_g_out = 0x0000ff3e,
- .gpio_b = 0x00
- },
- {
- .ioif = if_par_1,
- .name = "par_1",
- .groups = group_d,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0x7feff,
- .group_e = 0,
- .group_f = 0,
- .gpio_g_in = 0x3eff0000,
- .gpio_g_out = 0x3eff0000,
- .gpio_b = 0x00
- },
- {
- .ioif = if_par_w,
- .name = "par_w",
- .groups = group_a | group_d,
- .group_a = 0x7fbff,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0xff,
- .group_e = 0,
- .group_f = 0,
- .gpio_g_in = 0x00ffff3e,
- .gpio_g_out = 0x00ffff3e,
- .gpio_b = 0x00
- },
- {
- .ioif = if_scsi8_0,
- .name = "scsi8_0",
- .groups = group_a | group_b | group_f,
- .group_a = 0x7ffff,
- .group_b = 0x0f,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0,
- .group_f = 0x10,
- .gpio_g_in = 0x0000ffff,
- .gpio_g_out = 0x0000ffff,
- .gpio_b = 0x10
- },
- {
- .ioif = if_scsi8_1,
- .name = "scsi8_1",
- .groups = group_c | group_d | group_f,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0x0f,
- .group_d = 0x7ffff,
- .group_e = 0,
- .group_f = 0x80,
- .gpio_g_in = 0xffff0000,
- .gpio_g_out = 0xffff0000,
- .gpio_b = 0x80
- },
- {
- .ioif = if_scsi_w,
- .name = "scsi_w",
- .groups = group_a | group_b | group_d | group_f,
- .group_a = 0x7ffff,
- .group_b = 0x0f,
- .group_c = 0,
- .group_d = 0x601ff,
- .group_e = 0,
- .group_f = 0x90,
- .gpio_g_in = 0x01ffffff,
- .gpio_g_out = 0x07ffffff,
- .gpio_b = 0x80
- },
- {
- .ioif = if_ata,
- .name = "ata",
- .groups = group_a | group_b | group_c | group_d,
- .group_a = 0x7ffff,
- .group_b = 0x0f,
- .group_c = 0x0f,
- .group_d = 0x7cfff,
- .group_e = 0,
- .group_f = 0,
- .gpio_g_in = 0xf9ffffff,
- .gpio_g_out = 0xffffffff,
- .gpio_b = 0x80
- },
- {
- .ioif = if_csp,
- .name = "csp",
- .groups = group_f,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0,
- .group_f = 0xfc,
- .gpio_g_in = 0x00000000,
- .gpio_g_out = 0x00000000,
- .gpio_b = 0xfc
- },
- {
- .ioif = if_i2c,
- .name = "i2c",
- .groups = group_f,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0,
- .group_f = 0x03,
- .gpio_g_in = 0x00000000,
- .gpio_g_out = 0x00000000,
- .gpio_b = 0x03
- },
- {
- .ioif = if_usb_1,
- .name = "usb_1",
- .groups = group_e | group_f,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0x0f,
- .group_f = 0x2c,
- .gpio_g_in = 0x00000000,
- .gpio_g_out = 0x00000000,
- .gpio_b = 0x2c
- },
- {
- .ioif = if_usb_2,
- .name = "usb_2",
- .groups = group_d,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0x33e00,
- .group_f = 0,
- .gpio_g_in = 0x3e000000,
- .gpio_g_out = 0x0c000000,
- .gpio_b = 0x00
- },
- /* GPIO pins */
- {
- .ioif = if_gpio_grp_a,
- .name = "gpio_a",
- .groups = group_a,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0,
- .group_f = 0,
- .gpio_g_in = 0x0000ff3f,
- .gpio_g_out = 0x0000ff3f,
- .gpio_b = 0x00
- },
- {
- .ioif = if_gpio_grp_b,
- .name = "gpio_b",
- .groups = group_b,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0,
- .group_f = 0,
- .gpio_g_in = 0x000000c0,
- .gpio_g_out = 0x000000c0,
- .gpio_b = 0x00
- },
- {
- .ioif = if_gpio_grp_c,
- .name = "gpio_c",
- .groups = group_c,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0,
- .group_f = 0,
- .gpio_g_in = 0xc0000000,
- .gpio_g_out = 0xc0000000,
- .gpio_b = 0x00
- },
- {
- .ioif = if_gpio_grp_d,
- .name = "gpio_d",
- .groups = group_d,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0,
- .group_f = 0,
- .gpio_g_in = 0x3fff0000,
- .gpio_g_out = 0x3fff0000,
- .gpio_b = 0x00
- },
- {
- .ioif = if_gpio_grp_e,
- .name = "gpio_e",
- .groups = group_e,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0,
- .group_f = 0,
- .gpio_g_in = 0x00000000,
- .gpio_g_out = 0x00000000,
- .gpio_b = 0x00
- },
- {
- .ioif = if_gpio_grp_f,
- .name = "gpio_f",
- .groups = group_f,
- .group_a = 0,
- .group_b = 0,
- .group_c = 0,
- .group_d = 0,
- .group_e = 0,
- .group_f = 0,
- .gpio_g_in = 0x00000000,
- .gpio_g_out = 0x00000000,
- .gpio_b = 0xff
- }
- /* Array end */
- };
- static struct watcher *watchers = NULL;
- /* The pins that are free to use in the GPIO ports. */
- static unsigned int gpio_in_pins = 0xffffffff;
- static unsigned int gpio_out_pins = 0xffffffff;
- static unsigned char gpio_pb_pins = 0xff;
- static unsigned char gpio_pa_pins = 0xff;
- /* Identifiers for the owners of the GPIO pins. */
- static enum cris_io_interface gpio_pa_owners[8];
- static enum cris_io_interface gpio_pb_owners[8];
- static enum cris_io_interface gpio_pg_owners[32];
- static int cris_io_interface_init(void);
- static unsigned char clear_group_from_set(const unsigned char groups, struct if_group *group)
- {
- return (groups & ~group->group);
- }
- static struct if_group *get_group(const unsigned char groups)
- {
- int i;
- for (i = 0; i < ARRAY_SIZE(if_groups); i++) {
- if (groups & if_groups[i].group) {
- return &if_groups[i];
- }
- }
- return NULL;
- }
- static void notify_watchers(void)
- {
- struct watcher *w = watchers;
- DBG(printk("io_interface_mux: notifying watchers\n"));
- while (NULL != w) {
- w->notify((const unsigned int)gpio_in_pins,
- (const unsigned int)gpio_out_pins,
- (const unsigned char)gpio_pa_pins,
- (const unsigned char)gpio_pb_pins);
- w = w->next;
- }
- }
- int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id)
- {
- int set_gen_config = 0;
- int set_gen_config_ii = 0;
- unsigned long int gens;
- unsigned long int gens_ii;
- struct if_group *grp;
- unsigned char group_set;
- unsigned long flags;
- int res = 0;
- (void)cris_io_interface_init();
- DBG(printk("cris_request_io_interface(%d, \"%s\")\n", ioif, device_id));
- if ((ioif >= if_max_interfaces) || (ioif < 0)) {
- printk(KERN_CRIT "cris_request_io_interface: Bad interface "
- "%u submitted for %s\n",
- ioif,
- device_id);
- return -EINVAL;
- }
- local_irq_save(flags);
- if (interfaces[ioif].used) {
- printk(KERN_CRIT "cris_io_interface: Cannot allocate interface "
- "%s for %s, in use by %s\n",
- interfaces[ioif].name,
- device_id,
- interfaces[ioif].owner);
- res = -EBUSY;
- goto exit;
- }
- /* Check that all required pins in the used groups are free
- * before allocating. */
- group_set = interfaces[ioif].groups;
- while (NULL != (grp = get_group(group_set))) {
- unsigned int if_group_use = 0;
- switch (grp->group) {
- case group_a:
- if_group_use = interfaces[ioif].group_a;
- break;
- case group_b:
- if_group_use = interfaces[ioif].group_b;
- break;
- case group_c:
- if_group_use = interfaces[ioif].group_c;
- break;
- case group_d:
- if_group_use = interfaces[ioif].group_d;
- break;
- case group_e:
- if_group_use = interfaces[ioif].group_e;
- break;
- case group_f:
- if_group_use = interfaces[ioif].group_f;
- break;
- default:
- BUG_ON(1);
- }
- if (if_group_use & grp->used) {
- printk(KERN_INFO "cris_request_io_interface: group "
- "%s needed by %s not available\n",
- grp->name, interfaces[ioif].name);
- res = -EBUSY;
- goto exit;
- }
- group_set = clear_group_from_set(group_set, grp);
- }
- /* Are the required GPIO pins available too? */
- if (((interfaces[ioif].gpio_g_in & gpio_in_pins) !=
- interfaces[ioif].gpio_g_in) ||
- ((interfaces[ioif].gpio_g_out & gpio_out_pins) !=
- interfaces[ioif].gpio_g_out) ||
- ((interfaces[ioif].gpio_b & gpio_pb_pins) !=
- interfaces[ioif].gpio_b)) {
- printk(KERN_CRIT "cris_request_io_interface: Could not get "
- "required pins for interface %u\n", ioif);
- res = -EBUSY;
- goto exit;
- }
- /* Check which registers need to be reconfigured. */
- gens = genconfig_shadow;
- gens_ii = gen_config_ii_shadow;
- set_gen_config = 1;
- switch (ioif)
- {
- /* Begin Non-multiplexed interfaces */
- case if_eth:
- /* fall through */
- case if_serial_0:
- set_gen_config = 0;
- break;
- /* End Non-multiplexed interfaces */
- case if_serial_1:
- set_gen_config_ii = 1;
- SETS(gens_ii, R_GEN_CONFIG_II, sermode1, async);
- break;
- case if_serial_2:
- SETS(gens, R_GEN_CONFIG, ser2, select);
- break;
- case if_serial_3:
- SETS(gens, R_GEN_CONFIG, ser3, select);
- set_gen_config_ii = 1;
- SETS(gens_ii, R_GEN_CONFIG_II, sermode3, async);
- break;
- case if_sync_serial_1:
- set_gen_config_ii = 1;
- SETS(gens_ii, R_GEN_CONFIG_II, sermode1, sync);
- break;
- case if_sync_serial_3:
- SETS(gens, R_GEN_CONFIG, ser3, select);
- set_gen_config_ii = 1;
- SETS(gens_ii, R_GEN_CONFIG_II, sermode3, sync);
- break;
- case if_shared_ram:
- SETS(gens, R_GEN_CONFIG, mio, select);
- break;
- case if_shared_ram_w:
- SETS(gens, R_GEN_CONFIG, mio_w, select);
- break;
- case if_par_0:
- SETS(gens, R_GEN_CONFIG, par0, select);
- break;
- case if_par_1:
- SETS(gens, R_GEN_CONFIG, par1, select);
- break;
- case if_par_w:
- SETS(gens, R_GEN_CONFIG, par0, select);
- SETS(gens, R_GEN_CONFIG, par_w, select);
- break;
- case if_scsi8_0:
- SETS(gens, R_GEN_CONFIG, scsi0, select);
- break;
- case if_scsi8_1:
- SETS(gens, R_GEN_CONFIG, scsi1, select);
- break;
- case if_scsi_w:
- SETS(gens, R_GEN_CONFIG, scsi0, select);
- SETS(gens, R_GEN_CONFIG, scsi0w, select);
- break;
- case if_ata:
- SETS(gens, R_GEN_CONFIG, ata, select);
- break;
- case if_csp:
- /* fall through */
- case if_i2c:
- set_gen_config = 0;
- break;
- case if_usb_1:
- SETS(gens, R_GEN_CONFIG, usb1, select);
- break;
- case if_usb_2:
- SETS(gens, R_GEN_CONFIG, usb2, select);
- break;
- case if_gpio_grp_a:
- /* GPIO groups are only accounted, don't do configuration changes. */
- /* fall through */
- case if_gpio_grp_b:
- /* fall through */
- case if_gpio_grp_c:
- /* fall through */
- case if_gpio_grp_d:
- /* fall through */
- case if_gpio_grp_e:
- /* fall through */
- case if_gpio_grp_f:
- set_gen_config = 0;
- break;
- default:
- printk(KERN_INFO "cris_request_io_interface: Bad interface "
- "%u submitted for %s\n",
- ioif, device_id);
- res = -EBUSY;
- goto exit;
- }
- /* All needed I/O pins and pin groups are free, allocate. */
- group_set = interfaces[ioif].groups;
- while (NULL != (grp = get_group(group_set))) {
- unsigned int if_group_use = 0;
- switch (grp->group) {
- case group_a:
- if_group_use = interfaces[ioif].group_a;
- break;
- case group_b:
- if_group_use = interfaces[ioif].group_b;
- break;
- case group_c:
- if_group_use = interfaces[ioif].group_c;
- break;
- case group_d:
- if_group_use = interfaces[ioif].group_d;
- break;
- case group_e:
- if_group_use = interfaces[ioif].group_e;
- break;
- case group_f:
- if_group_use = interfaces[ioif].group_f;
- break;
- default:
- BUG_ON(1);
- }
- grp->used |= if_group_use;
- group_set = clear_group_from_set(group_set, grp);
- }
- interfaces[ioif].used = 1;
- interfaces[ioif].owner = (char*)device_id;
- if (set_gen_config) {
- volatile int i;
- genconfig_shadow = gens;
- *R_GEN_CONFIG = genconfig_shadow;
- /* Wait 12 cycles before doing any DMA command */
- for(i = 6; i > 0; i--)
- nop();
- }
- if (set_gen_config_ii) {
- gen_config_ii_shadow = gens_ii;
- *R_GEN_CONFIG_II = gen_config_ii_shadow;
- }
- DBG(printk(KERN_DEBUG "GPIO pins: available before: "
- "g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
- gpio_in_pins, gpio_out_pins, gpio_pb_pins));
- DBG(printk(KERN_DEBUG
- "grabbing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
- interfaces[ioif].gpio_g_in,
- interfaces[ioif].gpio_g_out,
- interfaces[ioif].gpio_b));
- gpio_in_pins &= ~interfaces[ioif].gpio_g_in;
- gpio_out_pins &= ~interfaces[ioif].gpio_g_out;
- gpio_pb_pins &= ~interfaces[ioif].gpio_b;
- DBG(printk(KERN_DEBUG "GPIO pins: available after: "
- "g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
- gpio_in_pins, gpio_out_pins, gpio_pb_pins));
- exit:
- local_irq_restore(flags);
- if (res == 0)
- notify_watchers();
- return res;
- }
- void cris_free_io_interface(enum cris_io_interface ioif)
- {
- struct if_group *grp;
- unsigned char group_set;
- unsigned long flags;
- (void)cris_io_interface_init();
- if ((ioif >= if_max_interfaces) || (ioif < 0)) {
- printk(KERN_CRIT "cris_free_io_interface: Bad interface %u\n",
- ioif);
- return;
- }
- local_irq_save(flags);
- if (!interfaces[ioif].used) {
- printk(KERN_CRIT "cris_free_io_interface: Freeing free interface %u\n",
- ioif);
- local_irq_restore(flags);
- return;
- }
- group_set = interfaces[ioif].groups;
- while (NULL != (grp = get_group(group_set))) {
- unsigned int if_group_use = 0;
- switch (grp->group) {
- case group_a:
- if_group_use = interfaces[ioif].group_a;
- break;
- case group_b:
- if_group_use = interfaces[ioif].group_b;
- break;
- case group_c:
- if_group_use = interfaces[ioif].group_c;
- break;
- case group_d:
- if_group_use = interfaces[ioif].group_d;
- break;
- case group_e:
- if_group_use = interfaces[ioif].group_e;
- break;
- case group_f:
- if_group_use = interfaces[ioif].group_f;
- break;
- default:
- BUG_ON(1);
- }
- if ((grp->used & if_group_use) != if_group_use)
- BUG_ON(1);
- grp->used = grp->used & ~if_group_use;
- group_set = clear_group_from_set(group_set, grp);
- }
- interfaces[ioif].used = 0;
- interfaces[ioif].owner = NULL;
- DBG(printk("GPIO pins: available before: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
- gpio_in_pins, gpio_out_pins, gpio_pb_pins));
- DBG(printk("freeing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
- interfaces[ioif].gpio_g_in,
- interfaces[ioif].gpio_g_out,
- interfaces[ioif].gpio_b));
- gpio_in_pins |= interfaces[ioif].gpio_g_in;
- gpio_out_pins |= interfaces[ioif].gpio_g_out;
- gpio_pb_pins |= interfaces[ioif].gpio_b;
- DBG(printk("GPIO pins: available after: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
- gpio_in_pins, gpio_out_pins, gpio_pb_pins));
- local_irq_restore(flags);
- notify_watchers();
- }
- /* Create a bitmask from bit 0 (inclusive) to bit stop_bit
- (non-inclusive). stop_bit == 0 returns 0x0 */
- static inline unsigned int create_mask(const unsigned stop_bit)
- {
- /* Avoid overflow */
- if (stop_bit >= 32) {
- return 0xffffffff;
- }
- return (1<<stop_bit)-1;
- }
- /* port can be 'a', 'b' or 'g' */
- int cris_io_interface_allocate_pins(const enum cris_io_interface ioif,
- const char port,
- const unsigned start_bit,
- const unsigned stop_bit)
- {
- unsigned int i;
- unsigned int mask = 0;
- unsigned int tmp_mask;
- unsigned long int flags;
- enum cris_io_interface *owners;
- (void)cris_io_interface_init();
- DBG(printk("cris_io_interface_allocate_pins: if=%d port=%c start=%u stop=%u\n",
- ioif, port, start_bit, stop_bit));
- if (!((start_bit <= stop_bit) &&
- ((((port == 'a') || (port == 'b')) && (stop_bit < 8)) ||
- ((port == 'g') && (stop_bit < 32))))) {
- return -EINVAL;
- }
- mask = create_mask(stop_bit + 1);
- tmp_mask = create_mask(start_bit);
- mask &= ~tmp_mask;
- DBG(printk("cris_io_interface_allocate_pins: port=%c start=%u stop=%u mask=0x%08x\n",
- port, start_bit, stop_bit, mask));
- local_irq_save(flags);
- switch (port) {
- case 'a':
- if ((gpio_pa_pins & mask) != mask) {
- local_irq_restore(flags);
- return -EBUSY;
- }
- owners = gpio_pa_owners;
- gpio_pa_pins &= ~mask;
- break;
- case 'b':
- if ((gpio_pb_pins & mask) != mask) {
- local_irq_restore(flags);
- return -EBUSY;
- }
- owners = gpio_pb_owners;
- gpio_pb_pins &= ~mask;
- break;
- case 'g':
- if (((gpio_in_pins & mask) != mask) ||
- ((gpio_out_pins & mask) != mask)) {
- local_irq_restore(flags);
- return -EBUSY;
- }
- owners = gpio_pg_owners;
- gpio_in_pins &= ~mask;
- gpio_out_pins &= ~mask;
- break;
- default:
- local_irq_restore(flags);
- return -EINVAL;
- }
- for (i = start_bit; i <= stop_bit; i++) {
- owners[i] = ioif;
- }
- local_irq_restore(flags);
- notify_watchers();
- return 0;
- }
- /* port can be 'a', 'b' or 'g' */
- int cris_io_interface_free_pins(const enum cris_io_interface ioif,
- const char port,
- const unsigned start_bit,
- const unsigned stop_bit)
- {
- unsigned int i;
- unsigned int mask = 0;
- unsigned int tmp_mask;
- unsigned long int flags;
- enum cris_io_interface *owners;
- (void)cris_io_interface_init();
- if (!((start_bit <= stop_bit) &&
- ((((port == 'a') || (port == 'b')) && (stop_bit < 8)) ||
- ((port == 'g') && (stop_bit < 32))))) {
- return -EINVAL;
- }
- mask = create_mask(stop_bit + 1);
- tmp_mask = create_mask(start_bit);
- mask &= ~tmp_mask;
- DBG(printk("cris_io_interface_free_pins: port=%c start=%u stop=%u mask=0x%08x\n",
- port, start_bit, stop_bit, mask));
- local_irq_save(flags);
- switch (port) {
- case 'a':
- if ((~gpio_pa_pins & mask) != mask) {
- local_irq_restore(flags);
- printk(KERN_CRIT "cris_io_interface_free_pins: Freeing free pins");
- }
- owners = gpio_pa_owners;
- break;
- case 'b':
- if ((~gpio_pb_pins & mask) != mask) {
- local_irq_restore(flags);
- printk(KERN_CRIT "cris_io_interface_free_pins: Freeing free pins");
- }
- owners = gpio_pb_owners;
- break;
- case 'g':
- if (((~gpio_in_pins & mask) != mask) ||
- ((~gpio_out_pins & mask) != mask)) {
- local_irq_restore(flags);
- printk(KERN_CRIT "cris_io_interface_free_pins: Freeing free pins");
- }
- owners = gpio_pg_owners;
- break;
- default:
- owners = NULL; /* Cannot happen. Shut up, gcc! */
- }
- for (i = start_bit; i <= stop_bit; i++) {
- if (owners[i] != ioif) {
- printk(KERN_CRIT "cris_io_interface_free_pins: Freeing unowned pins");
- }
- }
- /* All was ok, change data. */
- switch (port) {
- case 'a':
- gpio_pa_pins |= mask;
- break;
- case 'b':
- gpio_pb_pins |= mask;
- break;
- case 'g':
- gpio_in_pins |= mask;
- gpio_out_pins |= mask;
- break;
- }
- for (i = start_bit; i <= stop_bit; i++) {
- owners[i] = if_unclaimed;
- }
- local_irq_restore(flags);
- notify_watchers();
- return 0;
- }
- int cris_io_interface_register_watcher(void (*notify)(const unsigned int gpio_in_available,
- const unsigned int gpio_out_available,
- const unsigned char pa_available,
- const unsigned char pb_available))
- {
- struct watcher *w;
- (void)cris_io_interface_init();
- if (NULL == notify) {
- return -EINVAL;
- }
- w = kmalloc(sizeof(*w), GFP_KERNEL);
- if (!w) {
- return -ENOMEM;
- }
- w->notify = notify;
- w->next = watchers;
- watchers = w;
- w->notify((const unsigned int)gpio_in_pins,
- (const unsigned int)gpio_out_pins,
- (const unsigned char)gpio_pa_pins,
- (const unsigned char)gpio_pb_pins);
- return 0;
- }
- void cris_io_interface_delete_watcher(void (*notify)(const unsigned int gpio_in_available,
- const unsigned int gpio_out_available,
- const unsigned char pa_available,
- const unsigned char pb_available))
- {
- struct watcher *w = watchers, *prev = NULL;
- (void)cris_io_interface_init();
- while ((NULL != w) && (w->notify != notify)){
- prev = w;
- w = w->next;
- }
- if (NULL != w) {
- if (NULL != prev) {
- prev->next = w->next;
- } else {
- watchers = w->next;
- }
- kfree(w);
- return;
- }
- printk(KERN_WARNING "cris_io_interface_delete_watcher: Deleting unknown watcher 0x%p\n", notify);
- }
- static int cris_io_interface_init(void)
- {
- static int first = 1;
- int i;
- if (!first) {
- return 0;
- }
- first = 0;
- for (i = 0; i<8; i++) {
- gpio_pa_owners[i] = if_unclaimed;
- gpio_pb_owners[i] = if_unclaimed;
- gpio_pg_owners[i] = if_unclaimed;
- }
- for (; i<32; i++) {
- gpio_pg_owners[i] = if_unclaimed;
- }
- return 0;
- }
- module_init(cris_io_interface_init);
- EXPORT_SYMBOL(cris_request_io_interface);
- EXPORT_SYMBOL(cris_free_io_interface);
- EXPORT_SYMBOL(cris_io_interface_allocate_pins);
- EXPORT_SYMBOL(cris_io_interface_free_pins);
- EXPORT_SYMBOL(cris_io_interface_register_watcher);
- EXPORT_SYMBOL(cris_io_interface_delete_watcher);
|