static int cpm_i2c_setup()

in busses/i2c-cpm.c [423:601]


static int cpm_i2c_setup(struct cpm_i2c *cpm)
{
	struct platform_device *ofdev = cpm->ofdev;
	const u32 *data;
	int len, ret, i;
	void __iomem *i2c_base;
	cbd_t __iomem *tbdf;
	cbd_t __iomem *rbdf;
	unsigned char brg;

	dev_dbg(&cpm->ofdev->dev, "cpm_i2c_setup()\n");

	init_waitqueue_head(&cpm->i2c_wait);

	cpm->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
	if (!cpm->irq)
		return -EINVAL;

	/* Install interrupt handler. */
	ret = request_irq(cpm->irq, cpm_i2c_interrupt, 0, "cpm_i2c",
			  &cpm->adap);
	if (ret)
		return ret;

	/* I2C parameter RAM */
	i2c_base = of_iomap(ofdev->dev.of_node, 1);
	if (i2c_base == NULL) {
		ret = -EINVAL;
		goto out_irq;
	}

	if (of_device_is_compatible(ofdev->dev.of_node, "fsl,cpm1-i2c")) {

		/* Check for and use a microcode relocation patch. */
		cpm->i2c_ram = i2c_base;
		cpm->i2c_addr = in_be16(&cpm->i2c_ram->rpbase);

		/*
		 * Maybe should use cpm_muram_alloc instead of hardcoding
		 * this in micropatch.c
		 */
		if (cpm->i2c_addr) {
			cpm->i2c_ram = cpm_muram_addr(cpm->i2c_addr);
			iounmap(i2c_base);
		}

		cpm->version = 1;

	} else if (of_device_is_compatible(ofdev->dev.of_node, "fsl,cpm2-i2c")) {
		cpm->i2c_addr = cpm_muram_alloc(sizeof(struct i2c_ram), 64);
		cpm->i2c_ram = cpm_muram_addr(cpm->i2c_addr);
		out_be16(i2c_base, cpm->i2c_addr);
		iounmap(i2c_base);

		cpm->version = 2;

	} else {
		iounmap(i2c_base);
		ret = -EINVAL;
		goto out_irq;
	}

	/* I2C control/status registers */
	cpm->i2c_reg = of_iomap(ofdev->dev.of_node, 0);
	if (cpm->i2c_reg == NULL) {
		ret = -EINVAL;
		goto out_ram;
	}

	data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len);
	if (!data || len != 4) {
		ret = -EINVAL;
		goto out_reg;
	}
	cpm->cp_command = *data;

	data = of_get_property(ofdev->dev.of_node, "linux,i2c-class", &len);
	if (data && len == 4)
		cpm->adap.class = *data;

	data = of_get_property(ofdev->dev.of_node, "clock-frequency", &len);
	if (data && len == 4)
		cpm->freq = *data;
	else
		cpm->freq = 60000; /* use 60kHz i2c clock by default */

	/*
	 * Allocate space for CPM_MAXBD transmit and receive buffer
	 * descriptors in the DP ram.
	 */
	cpm->dp_addr = cpm_muram_alloc(sizeof(cbd_t) * 2 * CPM_MAXBD, 8);
	if (!cpm->dp_addr) {
		ret = -ENOMEM;
		goto out_reg;
	}

	cpm->tbase = cpm_muram_addr(cpm->dp_addr);
	cpm->rbase = cpm_muram_addr(cpm->dp_addr + sizeof(cbd_t) * CPM_MAXBD);

	/* Allocate TX and RX buffers */

	tbdf = cpm->tbase;
	rbdf = cpm->rbase;

	for (i = 0; i < CPM_MAXBD; i++) {
		cpm->rxbuf[i] = dma_alloc_coherent(&cpm->ofdev->dev,
						   CPM_MAX_READ + 1,
						   &cpm->rxdma[i], GFP_KERNEL);
		if (!cpm->rxbuf[i]) {
			ret = -ENOMEM;
			goto out_muram;
		}
		out_be32(&rbdf[i].cbd_bufaddr, ((cpm->rxdma[i] + 1) & ~1));

		cpm->txbuf[i] = dma_alloc_coherent(&cpm->ofdev->dev,
						   CPM_MAX_READ + 1,
						   &cpm->txdma[i], GFP_KERNEL);
		if (!cpm->txbuf[i]) {
			ret = -ENOMEM;
			goto out_muram;
		}
		out_be32(&tbdf[i].cbd_bufaddr, cpm->txdma[i]);
	}

	/* Initialize Tx/Rx parameters. */

	cpm_reset_i2c_params(cpm);

	dev_dbg(&cpm->ofdev->dev, "i2c_ram 0x%p, i2c_addr 0x%04x, freq %d\n",
		cpm->i2c_ram, cpm->i2c_addr, cpm->freq);
	dev_dbg(&cpm->ofdev->dev, "tbase 0x%04x, rbase 0x%04x\n",
		(u8 __iomem *)cpm->tbase - DPRAM_BASE,
		(u8 __iomem *)cpm->rbase - DPRAM_BASE);

	cpm_command(cpm->cp_command, CPM_CR_INIT_TRX);

	/*
	 * Select an invalid address. Just make sure we don't use loopback mode
	 */
	out_8(&cpm->i2c_reg->i2add, 0x7f << 1);

	/*
	 * PDIV is set to 00 in i2mod, so brgclk/32 is used as input to the
	 * i2c baud rate generator. This is divided by 2 x (DIV + 3) to get
	 * the actual i2c bus frequency.
	 */
	brg = get_brgfreq() / (32 * 2 * cpm->freq) - 3;
	out_8(&cpm->i2c_reg->i2brg, brg);

	out_8(&cpm->i2c_reg->i2mod, 0x00);
	out_8(&cpm->i2c_reg->i2com, I2COM_MASTER);	/* Master mode */

	/* Disable interrupts. */
	out_8(&cpm->i2c_reg->i2cmr, 0);
	out_8(&cpm->i2c_reg->i2cer, 0xff);

	return 0;

out_muram:
	for (i = 0; i < CPM_MAXBD; i++) {
		if (cpm->rxbuf[i])
			dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
				cpm->rxbuf[i], cpm->rxdma[i]);
		if (cpm->txbuf[i])
			dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
				cpm->txbuf[i], cpm->txdma[i]);
	}
	cpm_muram_free(cpm->dp_addr);
out_reg:
	iounmap(cpm->i2c_reg);
out_ram:
	if ((cpm->version == 1) && (!cpm->i2c_addr))
		iounmap(cpm->i2c_ram);
	if (cpm->version == 2)
		cpm_muram_free(cpm->i2c_addr);
out_irq:
	free_irq(cpm->irq, &cpm->adap);
	return ret;
}