コード例 #1
0
ファイル: i2c-sh_mobile.c プロジェクト: AlexShiLucky/linux
/*
 * r8a7740 chip has lasting errata on I2C I/O pad reset.
 * this is work-around for it.
 */
static int sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd)
{
	iic_set_clr(pd, ICCR, ICCR_ICE, 0);
	iic_rd(pd, ICCR); /* dummy read */

	iic_set_clr(pd, ICSTART, ICSTART_ICSTART, 0);
	iic_rd(pd, ICSTART); /* dummy read */

	udelay(10);

	iic_wr(pd, ICCR, ICCR_SCP);
	iic_wr(pd, ICSTART, 0);

	udelay(10);

	iic_wr(pd, ICCR, ICCR_TRS);
	udelay(10);
	iic_wr(pd, ICCR, 0);
	udelay(10);
	iic_wr(pd, ICCR, ICCR_TRS);
	udelay(10);

	return sh_mobile_i2c_init(pd);
}
コード例 #2
0
ファイル: i2c-sh_mobile.c プロジェクト: AlexShiLucky/linux
static int sh_mobile_i2c_probe(struct platform_device *dev)
{
	struct sh_mobile_i2c_data *pd;
	struct i2c_adapter *adap;
	struct resource *res;
	const struct sh_mobile_dt_config *config;
	int ret;
	u32 bus_speed;

	pd = devm_kzalloc(&dev->dev, sizeof(struct sh_mobile_i2c_data), GFP_KERNEL);
	if (!pd)
		return -ENOMEM;

	pd->clk = devm_clk_get(&dev->dev, NULL);
	if (IS_ERR(pd->clk)) {
		dev_err(&dev->dev, "cannot get clock\n");
		return PTR_ERR(pd->clk);
	}

	ret = sh_mobile_i2c_hook_irqs(dev, pd);
	if (ret)
		return ret;

	pd->dev = &dev->dev;
	platform_set_drvdata(dev, pd);

	res = platform_get_resource(dev, IORESOURCE_MEM, 0);

	pd->res = res;
	pd->reg = devm_ioremap_resource(&dev->dev, res);
	if (IS_ERR(pd->reg))
		return PTR_ERR(pd->reg);

	ret = of_property_read_u32(dev->dev.of_node, "clock-frequency", &bus_speed);
	pd->bus_speed = (ret || !bus_speed) ? STANDARD_MODE : bus_speed;
	pd->clks_per_count = 1;

	/* Newer variants come with two new bits in ICIC */
	if (resource_size(res) > 0x17)
		pd->flags |= IIC_FLAG_HAS_ICIC67;

	pm_runtime_enable(&dev->dev);
	pm_runtime_get_sync(&dev->dev);

	config = of_device_get_match_data(&dev->dev);
	if (config) {
		pd->clks_per_count = config->clks_per_count;
		ret = config->setup(pd);
	} else {
		ret = sh_mobile_i2c_init(pd);
	}

	pm_runtime_put_sync(&dev->dev);
	if (ret)
		return ret;

	/* Init DMA */
	sg_init_table(&pd->sg, 1);
	pd->dma_direction = DMA_NONE;
	pd->dma_rx = pd->dma_tx = ERR_PTR(-EPROBE_DEFER);

	/* setup the private data */
	adap = &pd->adap;
	i2c_set_adapdata(adap, pd);

	adap->owner = THIS_MODULE;
	adap->algo = &sh_mobile_i2c_algorithm;
	adap->quirks = &sh_mobile_i2c_quirks;
	adap->dev.parent = &dev->dev;
	adap->retries = 5;
	adap->nr = dev->id;
	adap->dev.of_node = dev->dev.of_node;

	strlcpy(adap->name, dev->name, sizeof(adap->name));

	spin_lock_init(&pd->lock);
	init_waitqueue_head(&pd->wait);

	ret = i2c_add_numbered_adapter(adap);
	if (ret < 0) {
		sh_mobile_i2c_release_dma(pd);
		return ret;
	}

	dev_info(&dev->dev, "I2C adapter %d, bus speed %lu Hz\n", adap->nr, pd->bus_speed);

	return 0;
}
コード例 #3
0
ファイル: i2c-sh_mobile.c プロジェクト: Amitabha2001/linux
static int sh_mobile_i2c_probe(struct platform_device *dev)
{
	struct i2c_sh_mobile_platform_data *pdata = dev_get_platdata(&dev->dev);
	struct sh_mobile_i2c_data *pd;
	struct i2c_adapter *adap;
	struct resource *res;
	int ret;
	u32 bus_speed;

	pd = devm_kzalloc(&dev->dev, sizeof(struct sh_mobile_i2c_data), GFP_KERNEL);
	if (!pd)
		return -ENOMEM;

	pd->clk = devm_clk_get(&dev->dev, NULL);
	if (IS_ERR(pd->clk)) {
		dev_err(&dev->dev, "cannot get clock\n");
		return PTR_ERR(pd->clk);
	}

	ret = sh_mobile_i2c_hook_irqs(dev);
	if (ret)
		return ret;

	pd->dev = &dev->dev;
	platform_set_drvdata(dev, pd);

	res = platform_get_resource(dev, IORESOURCE_MEM, 0);

	pd->reg = devm_ioremap_resource(&dev->dev, res);
	if (IS_ERR(pd->reg))
		return PTR_ERR(pd->reg);

	/* Use platform data bus speed or STANDARD_MODE */
	ret = of_property_read_u32(dev->dev.of_node, "clock-frequency", &bus_speed);
	pd->bus_speed = ret ? STANDARD_MODE : bus_speed;

	pd->clks_per_count = 1;

	if (dev->dev.of_node) {
		const struct of_device_id *match;

		match = of_match_device(sh_mobile_i2c_dt_ids, &dev->dev);
		if (match) {
			const struct sh_mobile_dt_config *config;

			config = match->data;
			pd->clks_per_count = config->clks_per_count;
		}
	} else {
		if (pdata && pdata->bus_speed)
			pd->bus_speed = pdata->bus_speed;
		if (pdata && pdata->clks_per_count)
			pd->clks_per_count = pdata->clks_per_count;
	}

	/* The IIC blocks on SH-Mobile ARM processors
	 * come with two new bits in ICIC.
	 */
	if (resource_size(res) > 0x17)
		pd->flags |= IIC_FLAG_HAS_ICIC67;

	ret = sh_mobile_i2c_init(pd);
	if (ret)
		return ret;

	/* Enable Runtime PM for this device.
	 *
	 * Also tell the Runtime PM core to ignore children
	 * for this device since it is valid for us to suspend
	 * this I2C master driver even though the slave devices
	 * on the I2C bus may not be suspended.
	 *
	 * The state of the I2C hardware bus is unaffected by
	 * the Runtime PM state.
	 */
	pm_suspend_ignore_children(&dev->dev, true);
	pm_runtime_enable(&dev->dev);

	/* setup the private data */
	adap = &pd->adap;
	i2c_set_adapdata(adap, pd);

	adap->owner = THIS_MODULE;
	adap->algo = &sh_mobile_i2c_algorithm;
	adap->dev.parent = &dev->dev;
	adap->retries = 5;
	adap->nr = dev->id;
	adap->dev.of_node = dev->dev.of_node;

	strlcpy(adap->name, dev->name, sizeof(adap->name));

	spin_lock_init(&pd->lock);
	init_waitqueue_head(&pd->wait);

	ret = i2c_add_numbered_adapter(adap);
	if (ret < 0) {
		dev_err(&dev->dev, "cannot add numbered adapter\n");
		return ret;
	}

	dev_info(&dev->dev,
		 "I2C adapter %d with bus speed %lu Hz (L/H=0x%x/0x%x)\n",
		 adap->nr, pd->bus_speed, pd->iccl, pd->icch);

	return 0;
}