static int pd6729_set_socket()

in pd6729.c [294:420]


static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
{
	struct pd6729_socket *socket
			= container_of(sock, struct pd6729_socket, socket);
	unsigned char reg, data;

	/* First, set the global controller options */
	indirect_write(socket, I365_GBLCTL, 0x00);
	indirect_write(socket, I365_GENCTL, 0x00);

	/* Values for the IGENC register */
	socket->card_irq = state->io_irq;

	reg = 0;
	/* The reset bit has "inverse" logic */
	if (!(state->flags & SS_RESET))
		reg |= I365_PC_RESET;
	if (state->flags & SS_IOCARD)
		reg |= I365_PC_IOCARD;

	/* IGENC, Interrupt and General Control Register */
	indirect_write(socket, I365_INTCTL, reg);

	/* Power registers */

	reg = I365_PWR_NORESET; /* default: disable resetdrv on resume */

	if (state->flags & SS_PWR_AUTO) {
		dev_dbg(&sock->dev, "Auto power\n");
		reg |= I365_PWR_AUTO;	/* automatic power mngmnt */
	}
	if (state->flags & SS_OUTPUT_ENA) {
		dev_dbg(&sock->dev, "Power Enabled\n");
		reg |= I365_PWR_OUT;	/* enable power */
	}

	switch (state->Vcc) {
	case 0:
		break;
	case 33:
		dev_dbg(&sock->dev,
			"setting voltage to Vcc to 3.3V on socket %i\n",
			socket->number);
		reg |= I365_VCC_5V;
		indirect_setbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
		break;
	case 50:
		dev_dbg(&sock->dev,
			"setting voltage to Vcc to 5V on socket %i\n",
			socket->number);
		reg |= I365_VCC_5V;
		indirect_resetbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
		break;
	default:
		dev_dbg(&sock->dev,
			"pd6729_set_socket called with invalid VCC power "
			"value: %i\n", state->Vcc);
		return -EINVAL;
	}

	switch (state->Vpp) {
	case 0:
		dev_dbg(&sock->dev, "not setting Vpp on socket %i\n",
			socket->number);
		break;
	case 33:
	case 50:
		dev_dbg(&sock->dev, "setting Vpp to Vcc for socket %i\n",
			socket->number);
		reg |= I365_VPP1_5V;
		break;
	case 120:
		dev_dbg(&sock->dev, "setting Vpp to 12.0\n");
		reg |= I365_VPP1_12V;
		break;
	default:
		dev_dbg(&sock->dev, "pd6729: pd6729_set_socket called with "
			"invalid VPP power value: %i\n", state->Vpp);
		return -EINVAL;
	}

	/* only write if changed */
	if (reg != indirect_read(socket, I365_POWER))
		indirect_write(socket, I365_POWER, reg);

	if (irq_mode == 1) {
		/* all interrupts are to be done as PCI interrupts */
		data = PD67_EC1_INV_MGMT_IRQ | PD67_EC1_INV_CARD_IRQ;
	} else
		data = 0;

	indirect_write(socket, PD67_EXT_INDEX, PD67_EXT_CTL_1);
	indirect_write(socket, PD67_EXT_DATA, data);

	/* Enable specific interrupt events */

	reg = 0x00;
	if (state->csc_mask & SS_DETECT)
		reg |= I365_CSC_DETECT;

	if (state->flags & SS_IOCARD) {
		if (state->csc_mask & SS_STSCHG)
			reg |= I365_CSC_STSCHG;
	} else {
		if (state->csc_mask & SS_BATDEAD)
			reg |= I365_CSC_BVD1;
		if (state->csc_mask & SS_BATWARN)
			reg |= I365_CSC_BVD2;
		if (state->csc_mask & SS_READY)
			reg |= I365_CSC_READY;
	}
	if (irq_mode == 1)
		reg |= 0x30;	/* management IRQ: PCI INTA# = "irq 3" */
	indirect_write(socket, I365_CSCINT, reg);

	reg = indirect_read(socket, I365_INTCTL);
	if (irq_mode == 1)
		reg |= 0x03;	/* card IRQ: PCI INTA# = "irq 3" */
	else
		reg |= socket->card_irq;
	indirect_write(socket, I365_INTCTL, reg);

	/* now clear the (probably bogus) pending stuff by doing a dummy read */
	(void)indirect_read(socket, I365_CSC);

	return 0;
}