int do_pca953x(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
	static uint8_t chip = CONFIG_SYS_I2C_PCA953X_ADDR;
	int val;
	ulong ul_arg2 = 0;
	ulong ul_arg3 = 0;
	cmd_tbl_t *c;

	c = find_cmd_tbl(argv[1], cmd_pca953x, ARRAY_SIZE(cmd_pca953x));

	/* All commands but "device" require 'maxargs' arguments */
	if (!c || !((argc == (c->maxargs)) ||
		(((int)c->cmd == PCA953X_CMD_DEVICE) &&
		 (argc == (c->maxargs - 1))))) {
		cmd_usage(cmdtp);
		return 1;
	}

	/* arg2 used as chip number or pin number */
	if (argc > 2)
		ul_arg2 = simple_strtoul(argv[2], NULL, 16);

	/* arg3 used as pin or invert value */
	if (argc > 3)
		ul_arg3 = simple_strtoul(argv[3], NULL, 16) & 0x1;

	switch ((int)c->cmd) {
#ifdef CONFIG_CMD_PCA953X_INFO
	case PCA953X_CMD_INFO:
		return pca953x_info(chip);
#endif
	case PCA953X_CMD_DEVICE:
		if (argc == 3)
			chip = (uint8_t)ul_arg2;
		printf("Current device address: 0x%x\n", chip);
		return 0;
	case PCA953X_CMD_INPUT:
		pca953x_set_dir(chip, (1 << ul_arg2),
				PCA953X_DIR_IN << ul_arg2);
		val = (pca953x_get_val(chip) & (1 << ul_arg2)) != 0;

		printf("chip 0x%02x, pin 0x%lx = %d\n", chip, ul_arg2, val);
		return val;
	case PCA953X_CMD_OUTPUT:
		pca953x_set_dir(chip, (1 << ul_arg2),
				(PCA953X_DIR_OUT << ul_arg2));
		return pca953x_set_val(chip, (1 << ul_arg2),
					(ul_arg3 << ul_arg2));
	case PCA953X_CMD_INVERT:
		return pca953x_set_pol(chip, (1 << ul_arg2),
					(ul_arg3 << ul_arg2));
	default:
		/* We should never get here */
		return 1;
	}
}
Beispiel #2
0
static void flash_cs_fixup(void)
{
	int flash_sel;

	/*
	 * Print boot dev and swap flash flash chip selects if booted from 2nd
	 * flash.  Swapping chip selects presents user with a common memory
	 * map regardless of which flash was booted from.
	 */
	flash_sel = !((pca953x_get_val(CONFIG_SYS_I2C_PCA953X_ADDR0) &
			CONFIG_SYS_PCA953X_C0_FLASH_PASS_CS));
	printf("Flash: Executed from flash%d\n", flash_sel ? 2 : 1);

	if (flash_sel) {
		set_lbc_br(0, CONFIG_SYS_BR1_PRELIM);
		set_lbc_or(0, CONFIG_SYS_OR1_PRELIM);

		set_lbc_br(1, CONFIG_SYS_BR0_PRELIM);
		set_lbc_or(1, CONFIG_SYS_OR0_PRELIM);
	}
}
static void flash_cs_fixup(void)
{
	volatile ccsr_lbc_t *lbc = (void *)(CONFIG_SYS_MPC85xx_LBC_ADDR);
	int flash_sel;

	/*
	 * Print boot dev and swap flash flash chip selects if booted from 2nd
	 * flash.  Swapping chip selects presents user with a common memory
	 * map regardless of which flash was booted from.
	 */
	flash_sel = !((pca953x_get_val(CONFIG_SYS_I2C_PCA953X_ADDR0) &
			CONFIG_SYS_PCA953X_C0_FLASH_PASS_CS));
	printf("FLASH: Executed from FLASH%d\n", flash_sel ? 2 : 1);

	if (flash_sel) {
		lbc->br0 = CONFIG_SYS_BR1_PRELIM;
		lbc->or0 = CONFIG_SYS_OR1_PRELIM;

		lbc->br1 = CONFIG_SYS_BR0_PRELIM;
		lbc->or1 = CONFIG_SYS_OR0_PRELIM;
	}
}
/*
 * Print out which flash was booted from and if booting from the 2nd flash,
 * swap flash chip selects to maintain consistent flash numbering/addresses.
 */
static void flash_cs_fixup(void)
{
	immap_t *immap = (immap_t *)CONFIG_SYS_IMMR;
	ccsr_lbc_t *lbc = &immap->im_lbc;
	int flash_sel;

	/*
	 * Print boot dev and swap flash flash chip selects if booted from 2nd
	 * flash.  Swapping chip selects presents user with a common memory
	 * map regardless of which flash was booted from.
	 */
	flash_sel = !((pca953x_get_val(CONFIG_SYS_I2C_PCA953X_ADDR0) &
			CONFIG_SYS_PCA953X_C0_FLASH_PASS_CS));
	printf("FLASH: Executed from FLASH%d\n", flash_sel ? 2 : 1);

	if (flash_sel) {
		out_be32(&lbc->br0, CONFIG_SYS_BR1_PRELIM);
		out_be32(&lbc->or0, CONFIG_SYS_OR1_PRELIM);

		out_be32(&lbc->br1, CONFIG_SYS_BR0_PRELIM);
		out_be32(&lbc->or1, CONFIG_SYS_OR0_PRELIM);
	}
}
Beispiel #5
0
int last_stage_init(void)
{
	int slaves;
	uint k;
	uchar mclink_controllers[] = { 0x3c, 0x3d, 0x3e };
	u16 fpga_features;
	bool hw_type_cat = pca9698_get_value(0x20, 20);
	bool ch0_rgmii2_present;

	FPGA_GET_REG(0, fpga_features, &fpga_features);

	/* Turn on Parade DP501 */
	pca9698_direction_output(0x20, 10, 1);
	pca9698_direction_output(0x20, 11, 1);

	ch0_rgmii2_present = !pca9698_get_value(0x20, 30);

	/* wait for FPGA done, then reset FPGA */
	for (k = 0; k < ARRAY_SIZE(mclink_controllers); ++k) {
		uint ctr = 0;

		if (i2c_probe(mclink_controllers[k]))
			continue;

		while (!(pca953x_get_val(mclink_controllers[k])
		       & MCFPGA_DONE)) {
			mdelay(100);
			if (ctr++ > 5) {
				printf("no done for mclink_controller %u\n", k);
				break;
			}
		}

		pca953x_set_dir(mclink_controllers[k], MCFPGA_RESET_N, 0);
		pca953x_set_val(mclink_controllers[k], MCFPGA_RESET_N, 0);
		udelay(10);
		pca953x_set_val(mclink_controllers[k], MCFPGA_RESET_N,
				MCFPGA_RESET_N);
	}

	if (hw_type_cat) {
		uint mux_ch;
		int retval;
		struct mii_dev *mdiodev = mdio_alloc();

		if (!mdiodev)
			return -ENOMEM;
		strncpy(mdiodev->name, bb_miiphy_buses[0].name, MDIO_NAME_LEN);
		mdiodev->read = bb_miiphy_read;
		mdiodev->write = bb_miiphy_write;

		retval = mdio_register(mdiodev);
		if (retval < 0)
			return retval;
		for (mux_ch = 0; mux_ch < MAX_MUX_CHANNELS; ++mux_ch) {
			if ((mux_ch == 1) && !ch0_rgmii2_present)
				continue;

			setup_88e1514(bb_miiphy_buses[0].name, mux_ch);
		}
	}

	/* give slave-PLLs and Parade DP501 some time to be up and running */
	mdelay(500);

	mclink_fpgacount = CONFIG_SYS_MCLINK_MAX;
	slaves = mclink_probe();
	mclink_fpgacount = 0;

	ioep_fpga_print_info(0);
	osd_probe(0);
#ifdef CONFIG_SYS_OSD_DH
	osd_probe(4);
#endif

	if (slaves <= 0)
		return 0;

	mclink_fpgacount = slaves;

	for (k = 1; k <= slaves; ++k) {
		FPGA_GET_REG(k, fpga_features, &fpga_features);

		ioep_fpga_print_info(k);
		osd_probe(k);
#ifdef CONFIG_SYS_OSD_DH
		osd_probe(k + 4);
#endif
		if (hw_type_cat) {
			int retval;
			struct mii_dev *mdiodev = mdio_alloc();

			if (!mdiodev)
				return -ENOMEM;
			strncpy(mdiodev->name, bb_miiphy_buses[k].name,
				MDIO_NAME_LEN);
			mdiodev->read = bb_miiphy_read;
			mdiodev->write = bb_miiphy_write;

			retval = mdio_register(mdiodev);
			if (retval < 0)
				return retval;
			setup_88e1514(bb_miiphy_buses[k].name, 0);
		}
	}

	for (k = 0; k < ARRAY_SIZE(hrcon_fans); ++k) {
		i2c_set_bus_num(hrcon_fans[k].bus);
		init_fan_controller(hrcon_fans[k].addr);
	}

	return 0;
}
int last_stage_init(void)
{
	int slaves;
	unsigned int k;
	unsigned int mux_ch;
	unsigned char mclink_controllers[] = { 0x3c, 0x3d, 0x3e };
	bool hw_type_cat = pca9698_get_value(0x20, 18);
	bool ch0_sgmii2_present = false;

	/* Turn on Analog Devices ADV7611 */
	pca9698_direction_output(0x20, 8, 0);

	/* Turn on Parade DP501 */
	pca9698_direction_output(0x20, 9, 1);

	ch0_sgmii2_present = !pca9698_get_value(0x20, 37);

	/* wait for FPGA done, then reset FPGA */
	for (k = 0; k < ARRAY_SIZE(mclink_controllers); ++k) {
		unsigned int ctr = 0;

		if (i2c_probe(mclink_controllers[k]))
			continue;

		while (!(pca953x_get_val(mclink_controllers[k])
		       & MCFPGA_DONE)) {
			udelay(100000);
			if (ctr++ > 5) {
				printf("no done for mclink_controller %d\n", k);
				break;
			}
		}

		pca953x_set_dir(mclink_controllers[k], MCFPGA_RESET_N, 0);
		pca953x_set_val(mclink_controllers[k], MCFPGA_RESET_N, 0);
		udelay(10);
		pca953x_set_val(mclink_controllers[k], MCFPGA_RESET_N,
				MCFPGA_RESET_N);
	}

	if (hw_type_cat) {
		miiphy_register(bb_miiphy_buses[0].name, bb_miiphy_read,
				bb_miiphy_write);
		for (mux_ch = 0; mux_ch < MAX_MUX_CHANNELS; ++mux_ch) {
			if ((mux_ch == 1) && !ch0_sgmii2_present)
				continue;

			setup_88e1514(bb_miiphy_buses[0].name, mux_ch);
		}
	}

	/* give slave-PLLs and Parade DP501 some time to be up and running */
	udelay(500000);

	mclink_fpgacount = CONFIG_SYS_MCLINK_MAX;
	slaves = mclink_probe();
	mclink_fpgacount = 0;

	ioep_fpga_print_info(0);

	if (!adv7611_probe(0))
		printf("       Advantiv ADV7611 HDMI Receiver\n");

#ifdef CONFIG_STRIDER_CON
	if (ioep_fpga_has_osd(0))
		osd_probe(0);
#endif

#ifdef CONFIG_STRIDER_CPU
	ch7301_probe(0, false);
#endif

	if (slaves <= 0)
		return 0;

	mclink_fpgacount = slaves;

	for (k = 1; k <= slaves; ++k) {
		ioep_fpga_print_info(k);
#ifdef CONFIG_STRIDER_CON
		if (ioep_fpga_has_osd(k))
			osd_probe(k);
#endif
#ifdef CONFIG_STRIDER_CPU
		FPGA_SET_REG(k, extended_control, 0); /* enable video in*/
		if (!adv7611_probe(k))
			printf("       Advantiv ADV7611 HDMI Receiver\n");
		ch7301_probe(k, false);
#endif
		if (hw_type_cat) {
			miiphy_register(bb_miiphy_buses[k].name,
					bb_miiphy_read, bb_miiphy_write);
			setup_88e1514(bb_miiphy_buses[k].name, 0);
		}
	}

	for (k = 0; k < ARRAY_SIZE(strider_fans); ++k) {
		i2c_set_bus_num(strider_fans[k].bus);
		init_fan_controller(strider_fans[k].addr);
	}

	return 0;
}
Beispiel #7
0
/**
 * Modify the device tree to remove all unused interface types.
 */
int board_fixup_fdt(void)
{
	const char *fdt_key;
	int val;
	int rc;

	val = pca953x_get_val(0, 0x20);
	if (val & 4)
		fdt_key = "2,sata";
	else
		fdt_key = "2,pcie";
	octeon_fdt_patch(working_fdt, fdt_key, NULL);


	if (val & 1)
		fdt_key = "0,xaui";
	else
		fdt_key = "0,qsgmii";

	debug("%s: Patching DLM 0 for %s\n", __func__, fdt_key);
	octeon_fdt_patch(working_fdt, fdt_key, NULL);

	if (val & 8) {
		debug("PCM mode detected, disabling SPI NOR\n");
		octeon_fdt_patch(working_fdt, "0,pcm", "cavium,pcm-trim");
	} else {
		debug("SPI NOR mode selected\n");
		octeon_fdt_patch(working_fdt, "0,not-pcm", "cavium,pcm-trim");
	}

	/* Check if we need to swap the MMC slots or not. */
	if (val & 0x10) {
		int s0_offset, s1_offset, offset;

		debug("%s: Swapping mmc slots 0 and 1\n", __func__);
		/* Swap slot 0 and slot 1 in device tree */
		offset = fdt_path_offset(gd->fdt_blob, "/soc/mmc");
		if (offset < 0) {
			puts("Error accessing /soc/mmc in device tree\n");
			return -1;
		}
		s0_offset = fdt_subnode_offset(gd->fdt_blob, offset,
					       "mmc-slot@0");
		s1_offset = fdt_subnode_offset(gd->fdt_blob, offset,
					       "mmc-slot@1");
		debug("  slot 0 offset: %d, slot 1 offset: %d\n",
		      s0_offset, s1_offset);
		if (s0_offset < 0 || s1_offset < 0) {
			puts("Error accessing MMC in device tree\n");
			return -1;
		}
		rc = fdt_setprop_inplace_u32(gd->fdt_blob, s0_offset, "reg", 1);
		rc |= fdt_setprop_inplace_u32(gd->fdt_blob, s1_offset, "reg", 0);
		if (rc) {
			puts("Error changing reg property in mmc slot\n");
			return -1;
		}

		rc = fdt_set_name(gd->fdt_blob, s0_offset, "mmc-slot@1");
		rc |= fdt_set_name(gd->fdt_blob, s1_offset, "mmc-slot@0");
		if (rc) {
			puts("Error renaming MMC slot names\n");
			return -1;
		}
	}


	return 0;
}
Beispiel #8
0
int checkboard(void)
{
	int clk_to_use = 0;	/* Clock used for DLM0 */
	int val;

	val = pca953x_get_val(0, 0x20);

	/* Print it early so switches are in order */
	if (val & 1) {	/* DLM0_SEL */
		puts("SW4-1 on: RXAUI (10G) port selected\n");
		octeon_configure_qlm(0, 6250, CVMX_QLM_MODE_RXAUI,
				     0, 0, 2, 2);
	} else {
		puts("SW4-1 off: QSGMII ports selected\n");
		octeon_configure_qlm(0, 2500, CVMX_QLM_MODE_QSGMII_QSGMII,
				     0, 0, 1, 1);
	}

	if (val & 2) {	/* DLM1_SEL */
		if (val & 4) {
			puts("SW4-2 on, SW4-3 off: PCIe 1x2 mode selected\n");
			octeon_configure_qlm(1, 5000, CVMX_QLM_MODE_PCIE_1X2,
					     1, 1, 0, 0);
		} else {
			int host_mode = cvmx_pcie_is_host_mode(0);
			printf("SW4-2 on, SW4-3 on: PCIe 1x4 %s mode selected\n",
			       host_mode ? "host" : "target");
			/* For PCIe target mode we need to use clock 1 for DLM0
			 * since in this case clock 0 is coming from the PCIe
			 * host.  Also, there's no need to configure the DLM
			 * if we're in PCIe target (endpoint) mode.
			 */
			if (host_mode)
				octeon_configure_qlm(1, 5000,
						     CVMX_QLM_MODE_PCIE,
						     1, 1, clk_to_use, 0);
			else
				clk_to_use = 1;

		}
	} else {
		puts("SW4-2 off: mini-PCIe slots selected\n");
		octeon_configure_qlm(1, 5000, CVMX_QLM_MODE_PCIE_2X1, 1, 1, 0, 0);
	}

	if (val & 4) {	/* DLM2_SEL */
		puts("SW4-3 on: SATA ports selected\n");
		octeon_configure_qlm(2, 3125, CVMX_QLM_MODE_SATA_2X1,
				     0, 0, 1, 1);
	}
	if (val & 8)
		puts("SW4-4 on: PCM mode selected, SPI NOR disabled\n");
	else
		puts("SW4-4 off: SPI NOR enabled\n");

	printf("SW 1-8 is %s, %s selected as slot 1.\n",
	       val & 0x10 ? "on" : "off",
	       val & 0x10 ? "internal eMMC flash" : "external SD/MMC slot");

	debug("qlm 0 reference clock: %llu\n", cvmx_qlm_measure_clock(0));
	debug("qlm 1 reference clock: %llu\n", cvmx_qlm_measure_clock(1));
	debug("qlm 2 reference clock: %llu\n", cvmx_qlm_measure_clock(2));

	return 0;
}
Beispiel #9
0
int last_stage_init(void)
{
	int slaves;
	unsigned int k;
	unsigned int mux_ch;
	unsigned char mclink_controllers_dvi[] = { 0x3c, 0x3d, 0x3e };
#ifdef CONFIG_STRIDER_CPU
	unsigned char mclink_controllers_dp[] = { 0x24, 0x25, 0x26 };
#endif
	bool hw_type_cat = pca9698_get_value(0x20, 18);
#ifdef CONFIG_STRIDER_CON_DP
	bool is_dh = pca9698_get_value(0x20, 25);
#endif
	bool ch0_sgmii2_present = false;

	/* Turn on Analog Devices ADV7611 */
	pca9698_direction_output(0x20, 8, 0);

	/* Turn on Parade DP501 */
	pca9698_direction_output(0x20, 10, 1);
	pca9698_direction_output(0x20, 11, 1);

	ch0_sgmii2_present = !pca9698_get_value(0x20, 37);

	/* wait for FPGA done, then reset FPGA */
	for (k = 0; k < ARRAY_SIZE(mclink_controllers_dvi); ++k) {
		unsigned int ctr = 0;
		unsigned char *mclink_controllers = mclink_controllers_dvi;

#ifdef CONFIG_STRIDER_CPU
		if (i2c_probe(mclink_controllers[k])) {
			mclink_controllers = mclink_controllers_dp;
			if (i2c_probe(mclink_controllers[k]))
				continue;
		}
#else
		if (i2c_probe(mclink_controllers[k]))
			continue;
#endif
		while (!(pca953x_get_val(mclink_controllers[k])
		       & MCFPGA_DONE)) {
			udelay(100000);
			if (ctr++ > 5) {
				printf("no done for mclink_controller %d\n", k);
				break;
			}
		}

		pca953x_set_dir(mclink_controllers[k], MCFPGA_RESET_N, 0);
		pca953x_set_val(mclink_controllers[k], MCFPGA_RESET_N, 0);
		udelay(10);
		pca953x_set_val(mclink_controllers[k], MCFPGA_RESET_N,
				MCFPGA_RESET_N);
	}

	if (hw_type_cat) {
		int retval;
		struct mii_dev *mdiodev = mdio_alloc();
		if (!mdiodev)
			return -ENOMEM;
		strncpy(mdiodev->name, bb_miiphy_buses[0].name, MDIO_NAME_LEN);
		mdiodev->read = bb_miiphy_read;
		mdiodev->write = bb_miiphy_write;

		retval = mdio_register(mdiodev);
		if (retval < 0)
			return retval;
		for (mux_ch = 0; mux_ch < MAX_MUX_CHANNELS; ++mux_ch) {
			if ((mux_ch == 1) && !ch0_sgmii2_present)
				continue;

			setup_88e1514(bb_miiphy_buses[0].name, mux_ch);
		}
	}

	/* give slave-PLLs and Parade DP501 some time to be up and running */
	udelay(500000);

	mclink_fpgacount = CONFIG_SYS_MCLINK_MAX;
	slaves = mclink_probe();
	mclink_fpgacount = 0;

	ioep_fpga_print_info(0);

	if (!adv7611_probe(0))
		printf("       Advantiv ADV7611 HDMI Receiver\n");

#ifdef CONFIG_STRIDER_CON
	if (ioep_fpga_has_osd(0))
		osd_probe(0);
#endif

#ifdef CONFIG_STRIDER_CON_DP
	if (ioep_fpga_has_osd(0)) {
		osd_probe(0);
		if (is_dh)
			osd_probe(4);
	}
#endif

#ifdef CONFIG_STRIDER_CPU
	ch7301_probe(0, false);
	dp501_probe(0, false);
#endif

	if (slaves <= 0)
		return 0;

	mclink_fpgacount = slaves;

#ifdef CONFIG_STRIDER_CPU
	/* get ADV7611 out of reset, power up DP501, give some time to wakeup */
	for (k = 1; k <= slaves; ++k)
		FPGA_SET_REG(k, extended_control, 0x10); /* enable video */

	udelay(500000);
#endif

	for (k = 1; k <= slaves; ++k) {
		ioep_fpga_print_info(k);
#ifdef CONFIG_STRIDER_CON
		if (ioep_fpga_has_osd(k))
			osd_probe(k);
#endif
#ifdef CONFIG_STRIDER_CON_DP
		if (ioep_fpga_has_osd(k)) {
			osd_probe(k);
			if (is_dh)
				osd_probe(k + 4);
		}
#endif
#ifdef CONFIG_STRIDER_CPU
		if (!adv7611_probe(k))
			printf("       Advantiv ADV7611 HDMI Receiver\n");
		ch7301_probe(k, false);
		dp501_probe(k, false);
#endif
		if (hw_type_cat) {
			int retval;
			struct mii_dev *mdiodev = mdio_alloc();
			if (!mdiodev)
				return -ENOMEM;
			strncpy(mdiodev->name, bb_miiphy_buses[k].name,
				MDIO_NAME_LEN);
			mdiodev->read = bb_miiphy_read;
			mdiodev->write = bb_miiphy_write;

			retval = mdio_register(mdiodev);
			if (retval < 0)
				return retval;
			setup_88e1514(bb_miiphy_buses[k].name, 0);
		}
	}

	for (k = 0; k < ARRAY_SIZE(strider_fans); ++k) {
		i2c_set_bus_num(strider_fans[k].bus);
		init_fan_controller(strider_fans[k].addr);
	}

	return 0;
}
Beispiel #10
0
int do_pca953x(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	static uint8_t chip = CONFIG_SYS_I2C_PCA953X_ADDR;
	int ret = CMD_RET_USAGE, val;
	ulong ul_arg2 = 0;
	ulong ul_arg3 = 0;
	cmd_tbl_t *c;

	c = find_cmd_tbl(argv[1], cmd_pca953x, ARRAY_SIZE(cmd_pca953x));

	/* All commands but "device" require 'maxargs' arguments */
	if (!c || !((argc == (c->maxargs)) ||
		(((int)c->cmd == PCA953X_CMD_DEVICE) &&
		 (argc == (c->maxargs - 1))))) {
		return CMD_RET_USAGE;
	}

	/* arg2 used as chip number or pin number */
	if (argc > 2)
		ul_arg2 = simple_strtoul(argv[2], NULL, 16);

	/* arg3 used as pin or invert value */
	if (argc > 3)
		ul_arg3 = simple_strtoul(argv[3], NULL, 16) & 0x1;

	switch ((int)c->cmd) {
#ifdef CONFIG_CMD_PCA953X_INFO
	case PCA953X_CMD_INFO:
		ret = pca953x_info(chip);
		if (ret)
			ret = CMD_RET_FAILURE;
		break;
#endif

	case PCA953X_CMD_DEVICE:
		if (argc == 3)
			chip = (uint8_t)ul_arg2;
		printf("Current device address: 0x%x\n", chip);
		ret = CMD_RET_SUCCESS;
		break;

	case PCA953X_CMD_INPUT:
		ret = pca953x_set_dir(chip, (1 << ul_arg2),
				PCA953X_DIR_IN << ul_arg2);
		val = (pca953x_get_val(chip) & (1 << ul_arg2)) != 0;

		if (ret)
			ret = CMD_RET_FAILURE;
		else
			printf("chip 0x%02x, pin 0x%lx = %d\n", chip, ul_arg2,
									val);
		break;

	case PCA953X_CMD_OUTPUT:
		ret = pca953x_set_dir(chip, (1 << ul_arg2),
				(PCA953X_DIR_OUT << ul_arg2));
		if (!ret)
			ret = pca953x_set_val(chip, (1 << ul_arg2),
						(ul_arg3 << ul_arg2));
		if (ret)
			ret = CMD_RET_FAILURE;
		break;

	case PCA953X_CMD_INVERT:
		ret = pca953x_set_pol(chip, (1 << ul_arg2),
					(ul_arg3 << ul_arg2));
		if (ret)
			ret = CMD_RET_FAILURE;
		break;
	}

	if (ret == CMD_RET_FAILURE)
		eprintf("Error talking to chip at 0x%x\n", chip);

	return ret;
}