Path: blob/master/arch/cris/arch-v32/mach-a3/pinmux.c
15125 views
/*1* Allocator for I/O pins. All pins are allocated to GPIO at bootup.2* Unassigned pins and GPIO pins can be allocated to a fixed interface3* or the I/O processor instead.4*5* Copyright (c) 2005-2007 Axis Communications AB.6*/78#include <linux/init.h>9#include <linux/errno.h>10#include <linux/kernel.h>11#include <linux/string.h>12#include <linux/spinlock.h>13#include <hwregs/reg_map.h>14#include <hwregs/reg_rdwr.h>15#include <pinmux.h>16#include <hwregs/pinmux_defs.h>17#include <hwregs/clkgen_defs.h>1819#undef DEBUG2021#define PINS 8022#define PORT_PINS 3223#define PORTS 32425static char pins[PINS];26static DEFINE_SPINLOCK(pinmux_lock);2728static void crisv32_pinmux_set(int port);2930int31crisv32_pinmux_init(void)32{33static int initialized;3435if (!initialized) {36initialized = 1;37REG_WR_INT(pinmux, regi_pinmux, rw_hwprot, 0);38crisv32_pinmux_alloc(PORT_A, 0, 31, pinmux_gpio);39crisv32_pinmux_alloc(PORT_B, 0, 31, pinmux_gpio);40crisv32_pinmux_alloc(PORT_C, 0, 15, pinmux_gpio);41}4243return 0;44}4546int47crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode)48{49int i;50unsigned long flags;5152crisv32_pinmux_init();5354if (port >= PORTS)55return -EINVAL;5657spin_lock_irqsave(&pinmux_lock, flags);5859for (i = first_pin; i <= last_pin; i++) {60if ((pins[port * PORT_PINS + i] != pinmux_none) &&61(pins[port * PORT_PINS + i] != pinmux_gpio) &&62(pins[port * PORT_PINS + i] != mode)) {63spin_unlock_irqrestore(&pinmux_lock, flags);64#ifdef DEBUG65panic("Pinmux alloc failed!\n");66#endif67return -EPERM;68}69}7071for (i = first_pin; i <= last_pin; i++)72pins[port * PORT_PINS + i] = mode;7374crisv32_pinmux_set(port);7576spin_unlock_irqrestore(&pinmux_lock, flags);7778return 0;79}8081int82crisv32_pinmux_alloc_fixed(enum fixed_function function)83{84int ret = -EINVAL;85char saved[sizeof pins];86unsigned long flags;8788spin_lock_irqsave(&pinmux_lock, flags);8990/* Save internal data for recovery */91memcpy(saved, pins, sizeof pins);9293crisv32_pinmux_init(); /* must be done before we read rw_hwprot */9495reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);96reg_clkgen_rw_clk_ctrl clk_ctrl = REG_RD(clkgen, regi_clkgen,97rw_clk_ctrl);9899switch (function) {100case pinmux_eth:101clk_ctrl.eth = regk_clkgen_yes;102clk_ctrl.dma0_1_eth = regk_clkgen_yes;103ret = crisv32_pinmux_alloc(PORT_B, 8, 23, pinmux_fixed);104ret |= crisv32_pinmux_alloc(PORT_B, 24, 25, pinmux_fixed);105hwprot.eth = hwprot.eth_mdio = regk_pinmux_yes;106break;107case pinmux_geth:108ret = crisv32_pinmux_alloc(PORT_B, 0, 7, pinmux_fixed);109hwprot.geth = regk_pinmux_yes;110break;111case pinmux_tg_cmos:112clk_ctrl.ccd_tg_100 = clk_ctrl.ccd_tg_200 = regk_clkgen_yes;113ret = crisv32_pinmux_alloc(PORT_B, 27, 29, pinmux_fixed);114hwprot.tg_clk = regk_pinmux_yes;115break;116case pinmux_tg_ccd:117clk_ctrl.ccd_tg_100 = clk_ctrl.ccd_tg_200 = regk_clkgen_yes;118ret = crisv32_pinmux_alloc(PORT_B, 27, 31, pinmux_fixed);119ret |= crisv32_pinmux_alloc(PORT_C, 0, 15, pinmux_fixed);120hwprot.tg = hwprot.tg_clk = regk_pinmux_yes;121break;122case pinmux_vout:123clk_ctrl.strdma0_2_video = regk_clkgen_yes;124ret = crisv32_pinmux_alloc(PORT_A, 8, 18, pinmux_fixed);125hwprot.vout = hwprot.vout_sync = regk_pinmux_yes;126break;127case pinmux_ser1:128clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;129ret = crisv32_pinmux_alloc(PORT_A, 24, 25, pinmux_fixed);130hwprot.ser1 = regk_pinmux_yes;131break;132case pinmux_ser2:133clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;134ret = crisv32_pinmux_alloc(PORT_A, 26, 27, pinmux_fixed);135hwprot.ser2 = regk_pinmux_yes;136break;137case pinmux_ser3:138clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;139ret = crisv32_pinmux_alloc(PORT_A, 28, 29, pinmux_fixed);140hwprot.ser3 = regk_pinmux_yes;141break;142case pinmux_ser4:143clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;144ret = crisv32_pinmux_alloc(PORT_A, 30, 31, pinmux_fixed);145hwprot.ser4 = regk_pinmux_yes;146break;147case pinmux_sser:148clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;149ret = crisv32_pinmux_alloc(PORT_A, 19, 23, pinmux_fixed);150hwprot.sser = regk_pinmux_yes;151break;152case pinmux_pio:153hwprot.pio = regk_pinmux_yes;154ret = 0;155break;156case pinmux_pwm0:157ret = crisv32_pinmux_alloc(PORT_A, 30, 30, pinmux_fixed);158hwprot.pwm0 = regk_pinmux_yes;159break;160case pinmux_pwm1:161ret = crisv32_pinmux_alloc(PORT_A, 31, 31, pinmux_fixed);162hwprot.pwm1 = regk_pinmux_yes;163break;164case pinmux_pwm2:165ret = crisv32_pinmux_alloc(PORT_B, 26, 26, pinmux_fixed);166hwprot.pwm2 = regk_pinmux_yes;167break;168case pinmux_i2c0:169ret = crisv32_pinmux_alloc(PORT_A, 0, 1, pinmux_fixed);170hwprot.i2c0 = regk_pinmux_yes;171break;172case pinmux_i2c1:173ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed);174hwprot.i2c1 = regk_pinmux_yes;175break;176case pinmux_i2c1_3wire:177ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed);178ret |= crisv32_pinmux_alloc(PORT_A, 7, 7, pinmux_fixed);179hwprot.i2c1 = hwprot.i2c1_sen = regk_pinmux_yes;180break;181case pinmux_i2c1_sda1:182ret = crisv32_pinmux_alloc(PORT_A, 2, 4, pinmux_fixed);183hwprot.i2c1 = hwprot.i2c1_sda1 = regk_pinmux_yes;184break;185case pinmux_i2c1_sda2:186ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed);187ret |= crisv32_pinmux_alloc(PORT_A, 5, 5, pinmux_fixed);188hwprot.i2c1 = hwprot.i2c1_sda2 = regk_pinmux_yes;189break;190case pinmux_i2c1_sda3:191ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed);192ret |= crisv32_pinmux_alloc(PORT_A, 6, 6, pinmux_fixed);193hwprot.i2c1 = hwprot.i2c1_sda3 = regk_pinmux_yes;194break;195default:196ret = -EINVAL;197break;198}199200if (!ret) {201REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);202REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl);203} else204memcpy(pins, saved, sizeof pins);205206spin_unlock_irqrestore(&pinmux_lock, flags);207208return ret;209}210211void212crisv32_pinmux_set(int port)213{214int i;215int gpio_val = 0;216int iop_val = 0;217int pin = port * PORT_PINS;218219for (i = 0; (i < PORT_PINS) && (pin < PINS); i++, pin++) {220if (pins[pin] == pinmux_gpio)221gpio_val |= (1 << i);222else if (pins[pin] == pinmux_iop)223iop_val |= (1 << i);224}225226REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_gio_pa + 4 * port,227gpio_val);228REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_iop_pa + 4 * port,229iop_val);230231#ifdef DEBUG232crisv32_pinmux_dump();233#endif234}235236int237crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)238{239int i;240unsigned long flags;241242crisv32_pinmux_init();243244if (port > PORTS || port < 0)245return -EINVAL;246247spin_lock_irqsave(&pinmux_lock, flags);248249for (i = first_pin; i <= last_pin; i++)250pins[port * PORT_PINS + i] = pinmux_none;251252crisv32_pinmux_set(port);253spin_unlock_irqrestore(&pinmux_lock, flags);254255return 0;256}257258int259crisv32_pinmux_dealloc_fixed(enum fixed_function function)260{261int ret = -EINVAL;262char saved[sizeof pins];263unsigned long flags;264265spin_lock_irqsave(&pinmux_lock, flags);266267/* Save internal data for recovery */268memcpy(saved, pins, sizeof pins);269270crisv32_pinmux_init(); /* must be done before we read rw_hwprot */271272reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);273274switch (function) {275case pinmux_eth:276ret = crisv32_pinmux_dealloc(PORT_B, 8, 23);277ret |= crisv32_pinmux_dealloc(PORT_B, 24, 25);278ret |= crisv32_pinmux_dealloc(PORT_B, 0, 7);279hwprot.eth = hwprot.eth_mdio = hwprot.geth = regk_pinmux_no;280break;281case pinmux_tg_cmos:282ret = crisv32_pinmux_dealloc(PORT_B, 27, 29);283hwprot.tg_clk = regk_pinmux_no;284break;285case pinmux_tg_ccd:286ret = crisv32_pinmux_dealloc(PORT_B, 27, 31);287ret |= crisv32_pinmux_dealloc(PORT_C, 0, 15);288hwprot.tg = hwprot.tg_clk = regk_pinmux_no;289break;290case pinmux_vout:291ret = crisv32_pinmux_dealloc(PORT_A, 8, 18);292hwprot.vout = hwprot.vout_sync = regk_pinmux_no;293break;294case pinmux_ser1:295ret = crisv32_pinmux_dealloc(PORT_A, 24, 25);296hwprot.ser1 = regk_pinmux_no;297break;298case pinmux_ser2:299ret = crisv32_pinmux_dealloc(PORT_A, 26, 27);300hwprot.ser2 = regk_pinmux_no;301break;302case pinmux_ser3:303ret = crisv32_pinmux_dealloc(PORT_A, 28, 29);304hwprot.ser3 = regk_pinmux_no;305break;306case pinmux_ser4:307ret = crisv32_pinmux_dealloc(PORT_A, 30, 31);308hwprot.ser4 = regk_pinmux_no;309break;310case pinmux_sser:311ret = crisv32_pinmux_dealloc(PORT_A, 19, 23);312hwprot.sser = regk_pinmux_no;313break;314case pinmux_pwm0:315ret = crisv32_pinmux_dealloc(PORT_A, 30, 30);316hwprot.pwm0 = regk_pinmux_no;317break;318case pinmux_pwm1:319ret = crisv32_pinmux_dealloc(PORT_A, 31, 31);320hwprot.pwm1 = regk_pinmux_no;321break;322case pinmux_pwm2:323ret = crisv32_pinmux_dealloc(PORT_B, 26, 26);324hwprot.pwm2 = regk_pinmux_no;325break;326case pinmux_i2c0:327ret = crisv32_pinmux_dealloc(PORT_A, 0, 1);328hwprot.i2c0 = regk_pinmux_no;329break;330case pinmux_i2c1:331ret = crisv32_pinmux_dealloc(PORT_A, 2, 3);332hwprot.i2c1 = regk_pinmux_no;333break;334case pinmux_i2c1_3wire:335ret = crisv32_pinmux_dealloc(PORT_A, 2, 3);336ret |= crisv32_pinmux_dealloc(PORT_A, 7, 7);337hwprot.i2c1 = hwprot.i2c1_sen = regk_pinmux_no;338break;339case pinmux_i2c1_sda1:340ret = crisv32_pinmux_dealloc(PORT_A, 2, 4);341hwprot.i2c1_sda1 = regk_pinmux_no;342break;343case pinmux_i2c1_sda2:344ret = crisv32_pinmux_dealloc(PORT_A, 2, 3);345ret |= crisv32_pinmux_dealloc(PORT_A, 5, 5);346hwprot.i2c1_sda2 = regk_pinmux_no;347break;348case pinmux_i2c1_sda3:349ret = crisv32_pinmux_dealloc(PORT_A, 2, 3);350ret |= crisv32_pinmux_dealloc(PORT_A, 6, 6);351hwprot.i2c1_sda3 = regk_pinmux_no;352break;353default:354ret = -EINVAL;355break;356}357358if (!ret)359REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);360else361memcpy(pins, saved, sizeof pins);362363spin_unlock_irqrestore(&pinmux_lock, flags);364365return ret;366}367368void369crisv32_pinmux_dump(void)370{371int i, j;372int pin = 0;373374crisv32_pinmux_init();375376for (i = 0; i < PORTS; i++) {377pin++;378printk(KERN_DEBUG "Port %c\n", 'A'+i);379for (j = 0; (j < PORT_PINS) && (pin < PINS); j++, pin++)380printk(KERN_DEBUG381" Pin %d = %d\n", j, pins[i * PORT_PINS + j]);382}383}384385__initcall(crisv32_pinmux_init);386387388