亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關于我們
? 蟲蟲下載站

?? iicdriver.c

?? 在網上搜索到的2410的IIC driver. 還沒有用過
?? C
?? 第 1 頁 / 共 2 頁
字號:
 * get the i2c bus for a master transaction
*/

static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
{
	unsigned long iicstat;
	int timeout = 400;

	while (timeout-- > 0) {
		iicstat = readl(i2c->regs + S3C2410_IICSTAT);
		
		if (!(iicstat & S3C2410_IICSTAT_BUSBUSY))
			return 0;

		msleep(1);
	}

	DBG(3, "timeout: read GPEDAT %08x\n", __raw_readl(S3C2410_GPEDAT));
	return -ETIMEDOUT;
}

/* s3c24xx_i2c_doxfer
 *
 * this starts an i2c transfer
*/

static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg msgs[], int num)
{
	unsigned long timeout;
	int ret;

	ret = s3c24xx_i2c_set_master(i2c);
	if (ret != 0) {
		dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
		ret = -EAGAIN;
		goto out;
	}

	spin_lock_irq(&i2c->lock);

	i2c->msg     = msgs;
	i2c->msg_num = num;
	i2c->msg_ptr = 0;
	i2c->msg_idx = 0;
	i2c->state   = STATE_START;

	s3c24xx_i2c_enable_irq(i2c);
	s3c24xx_i2c_message_start(i2c, msgs);
	spin_unlock_irq(&i2c->lock);
	
	timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);

	ret = i2c->msg_idx;

	/* having these next two as dev_err() makes life very 
	 * noisy when doing an i2cdetect */

	if (timeout == 0)
		dev_dbg(i2c->dev, "timeout\n");
	else if (ret != num)
		dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);

	/* ensure the stop has been through the bus */

	msleep(1);

 out:
	return ret;
}

/* s3c24xx_i2c_xfer
 *
 * first port of call from the i2c bus code when an message needs
 * transfering across the i2c bus.
*/

static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
			struct i2c_msg msgs[], int num)
{
	struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;
	int retry;
	int ret;

	for (retry = 0; retry < adap->retries; retry++) {

		ret = s3c24xx_i2c_doxfer(i2c, msgs, num);

		if (ret != -EAGAIN)
			return ret;

		DBG(1, "Retrying transmission (%d)\n", retry);

		udelay(100);
	}

	return -EREMOTEIO;
}

/* i2c bus registration info */

static struct i2c_algorithm s3c24xx_i2c_algorithm = {
	.name			= "S3C2410-I2C-Algorithm",
	.id			= I2C_ALGO_S3C2410,
	.master_xfer		= s3c24xx_i2c_xfer,
};

static struct s3c24xx_i2c s3c24xx_i2c = {
	.lock	= SPIN_LOCK_UNLOCKED,
	.wait	= __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait),
	.adap	= {
		.name			= "s3c2410-i2c",
		.id			= I2C_ALGO_S3C2410,
		.algo			= &s3c24xx_i2c_algorithm,
		.retries		= 2,
	},
};

/* s3c24xx_i2c_calcdivisor
 *
 * return the divisor settings for a given frequency
*/

static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,
				   unsigned int *div1, unsigned int *divs)
{
	unsigned int calc_divs = clkin / wanted;
	unsigned int calc_div1;

	printk(KERN_DEBUG "%lu/%u = %d\n", clkin, wanted, calc_divs);

	if (calc_divs > (16*16))
		calc_div1 = 512;
	else
		calc_div1 = 16;

	calc_divs += calc_div1-1;
	calc_divs /= calc_div1;

	if (calc_divs == 0)
		calc_divs = 1;
	if (calc_divs > 17)
		calc_divs = 17;

	*divs = calc_divs;
	*div1 = calc_div1;

	printk(KERN_DEBUG "divisors %d, %d, => %ld\n",
	    calc_divs, calc_div1, clkin / (calc_divs + calc_div1));

	return clkin / (calc_divs + calc_div1);
}

/* freq_acceptable
 *
 * test wether a frequency is within the acceptable range of error
*/

static inline int freq_acceptable(unsigned int freq, unsigned int wanted)
{
	int diff = freq - wanted;

	return (diff >= -2 && diff <= 2);
}

/* s3c24xx_i2c_getdivisor
 *
 * work out a divisor for the user requested frequency setting,
 * either by the requested frequency, or scanning the acceptable
 * range of frequencies until something is found
*/

static int s3c24xx_i2c_getdivisor(struct s3c24xx_i2c *i2c,
				  unsigned long *iicon,
				  unsigned int *got)
{
	unsigned long clkin = clk_get_rate(i2c->clk);
	struct s3c2410_platform_i2c *pdata;
	unsigned int divs, div1;
	int freq;
	int start, end;

	clkin /= 1000;		/* clkin now in KHz */

	pdata = s3c24xx_i2c_get_platformdata(i2c->adap.dev.parent);

	DBG(1, "pdata %p, freq %lu %lu..%lu\n", pdata, pdata->bus_freq,
	    pdata->min_freq, pdata->max_freq);

	if (pdata->bus_freq != 0) {
		freq = s3c24xx_i2c_calcdivisor(clkin, pdata->bus_freq/1000,
					   &div1, &divs);
		if (freq_acceptable(freq, pdata->bus_freq/1000))
			goto found;
	}

	/* ok, we may have to search for something suitable... */

	start = (pdata->max_freq == 0) ? pdata->bus_freq : pdata->max_freq;
	end = pdata->min_freq;

	start /= 1000;
	end /= 1000;

	for (; start > end; start--) {
		freq = s3c24xx_i2c_calcdivisor(clkin, start, &div1, &divs);
		if (freq_acceptable(freq, start))
			goto found;
	}

	return -EINVAL;

 found:
	*got = freq;
	*iicon |= (divs-1);
	*iicon |= (div1 == 512) ? S3C2410_IICCON_TXDIV_512 : 0;
	return 0;
}

/* s3c24xx_i2c_init
 *
 * initialise the controller, set the IO lines and frequency 
*/
+
static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
{
	unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN;
	unsigned int freq;

	/* inititalise the gpio */

	s3c2410_gpio_cfgpin(S3C2410_GPE15, S3C2410_GPE15_IICSDA);
	s3c2410_gpio_cfgpin(S3C2410_GPE14, S3C2410_GPE14_IICSCL);

	/* we need to work out the divisors for the clock... */

	if (s3c24xx_i2c_getdivisor(i2c, &iicon, &freq) != 0) {
		dev_err(i2c->dev, "cannot meet bus frequency required\n");
		return -EINVAL;
	}

	/* todo - check that the i2c lines aren't being dragged anywhere */

	dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);

	return 0;
}

static void s3c24xx_i2c_free(struct s3c24xx_i2c *i2c)
{
	if (i2c->clk != NULL && !IS_ERR(i2c->clk)) {
		clk_disable(i2c->clk);
		clk_unuse(i2c->clk);
		clk_put(i2c->clk);
		i2c->clk = NULL;
	}

	if (i2c->regs != NULL) {
		iounmap(i2c->regs);
		i2c->regs = NULL;
	}

	if (i2c->ioarea != NULL) {
		release_resource(i2c->ioarea);
		kfree(i2c->ioarea);
		i2c->ioarea = NULL;
	}
}

/* s3c24xx_i2c_probe
*
 * called by the bus driver when a suitable device is found
*/

static int s3c24xx_i2c_probe(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct s3c24xx_i2c *i2c = &s3c24xx_i2c;
	struct resource *res;
	int ret;

	/* find the clock and enable it */

	i2c->dev = dev;
	i2c->clk = clk_get(dev, "i2c");
	if (IS_ERR(i2c->clk)) {
		dev_err(dev, "cannot get clock\n");
		ret = -ENOENT;
		goto out;
	}

	DBG(1, "got clock %p\n", i2c->clk);

	clk_use(i2c->clk);
	clk_enable(i2c->clk);

	/* map the registers */

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (res == NULL) {
		dev_err(dev, "cannot find IO resource\n");
		ret = -ENOENT;
		goto out;
	}

	i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1,
					 pdev->name);

	if (i2c->ioarea == NULL) {
		dev_err(dev, "cannot request IO\n");
		ret = -ENXIO;
		goto out;
	}

	i2c->regs = ioremap(res->start, (res->end-res->start)+1);

	if (i2c->regs == NULL) {
		dev_err(dev, "cannot map IO\n");
		ret = -ENXIO;
		goto out;
	}

	DBG(1, "got registers %p (%p, %p)\n", i2c->regs, i2c->ioarea, res);

	/* setup info block for the i2c core */

	i2c->adap.algo_data = i2c;
	i2c->adap.dev.parent = dev;

	/* initialise the i2c controller */

	ret = s3c24xx_i2c_init(i2c);
	if (ret != 0)
		goto out;

	/* find the IRQ for this unit (note, this relies on the init call to
	 * ensure no current IRQs pending 
	 */

	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (res == NULL) {
		dev_err(dev, "cannot find IRQ\n");
		ret = -ENOENT;
		goto out;
	}

	ret = request_irq(res->start, s3c24xx_i2c_irq, SA_INTERRUPT,
			  pdev->name, i2c);

	if (ret != 0) {
		dev_err(dev, "cannot claim IRQ\n");
		goto out;
	}

	i2c->irq = res;
		
	DBG(0, "got irq %p (%ld)\n", res, res->start);

	ret = i2c_add_adapter(&i2c->adap);
	if (ret < 0) {
		dev_err(dev, "failed to add bus to i2c core\n");
		goto out;
	}

	dev_set_drvdata(dev, i2c);

	dev_info(dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id);

 out:
	if (ret < 0)
		s3c24xx_i2c_free(i2c);

	return ret;
}

/* s3c24xx_i2c_remove
 *
 * called when device is removed from the bus
*/

static int s3c24xx_i2c_remove(struct device *dev)
{
	struct s3c24xx_i2c *i2c = dev_get_drvdata(dev);
	
	if (i2c != NULL) {
		s3c24xx_i2c_free(i2c);
		dev_set_drvdata(dev, NULL);
	}

	return 0;
}

#ifdef CONFIG_PM
static int s3c24xx_i2c_resume(struct device *dev, u32 level)
{
	struct s3c24xx_i2c *i2c = dev_get_drvdata(dev);
	
	if (i2c != NULL && level == RESUME_ENABLE)
		s3c24xx_i2c_init(i2c);

	return 0;
}

#else
#define s3c24xx_i2c_resume NULL
#endif

/* device driver for platform bus bits */

static struct device_driver s3c24xx_i2c_driver = {
	.name		= "s3c2410-i2c",
	.bus		= &platform_bus_type,
	.probe		= s3c24xx_i2c_probe,
	.remove		= s3c24xx_i2c_remove,
	.resume		= s3c24xx_i2c_resume,
};

static int __init i2c_adap_s3c_init(void)
{
	return driver_register(&s3c24xx_i2c_driver);
}

static void i2c_adap_s3c_exit(void)
{
	return driver_unregister(&s3c24xx_i2c_driver);
}

module_init(i2c_adap_s3c_init);
module_exit(i2c_adap_s3c_exit);

MODULE_DESCRIPTION("S3C24XX I2C Bus driver");
MODULE_AUTHOR("Ben Dooks, <ben at simtec.co.uk>");
MODULE_LICENSE("GPL");

?? 快捷鍵說明

復制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
婷婷综合另类小说色区| 午夜视频久久久久久| 欧美日韩国产高清一区二区 | 免费在线成人网| 日韩av电影天堂| 亚洲成av人片在线| 水蜜桃久久夜色精品一区的特点| 五月天婷婷综合| 午夜精品久久久久久久久| 亚洲高清免费在线| 亚洲一区二区在线观看视频| 亚洲一区二区三区四区在线观看| 亚洲欧美区自拍先锋| 一区二区三区精品视频| 亚洲一区免费视频| 亚洲成av人综合在线观看| 免费成人美女在线观看| 国产剧情一区在线| eeuss鲁一区二区三区| 日本精品视频一区二区| 欧美人体做爰大胆视频| 日韩欧美国产精品| 久久九九全国免费| 亚洲精品国产无天堂网2021| 三级不卡在线观看| 韩国av一区二区| 99v久久综合狠狠综合久久| 欧美三级电影一区| 精品国产免费一区二区三区四区| 久久久国产精华| 国产精品国产三级国产aⅴ无密码 国产精品国产三级国产aⅴ原创 | 不卡av电影在线播放| 一本色道亚洲精品aⅴ| 色综合中文字幕| 91污在线观看| 欧美性感一区二区三区| 精品美女一区二区| 亚洲男人电影天堂| 韩国女主播一区| 欧美亚洲高清一区| 久久久精品人体av艺术| 亚洲国产日韩精品| 懂色av一区二区在线播放| 欧美日韩一区精品| 国产精品免费久久| 蜜桃久久久久久久| 一区二区三区四区激情| 亚洲欧美另类在线| 亚洲人成精品久久久久久| 蜜桃视频第一区免费观看| 色哟哟日韩精品| 国产网站一区二区| 日韩高清不卡在线| 91高清视频在线| 国产亚洲一区字幕| 免费高清在线视频一区·| 91麻豆产精品久久久久久 | 亚洲国产精品久久人人爱蜜臀| 国产在线日韩欧美| 欧美精品日韩精品| 亚洲精品视频在线观看网站| 国产91在线|亚洲| 欧美mv日韩mv亚洲| 日本欧美一区二区在线观看| 欧美午夜片在线看| 亚洲品质自拍视频| 成人av午夜电影| 国产乱人伦偷精品视频免下载| 色狠狠av一区二区三区| 日韩美女视频一区二区| 一区二区三区不卡视频 | 久久看人人爽人人| 免费观看91视频大全| 欧美另类高清zo欧美| 亚洲综合久久久| 一本一道波多野结衣一区二区| 欧美激情一区二区三区在线| 精品亚洲成a人| 久久先锋影音av鲁色资源| 另类中文字幕网| 久久日韩精品一区二区五区| 日韩和的一区二区| 欧美一区在线视频| 免费在线看一区| www精品美女久久久tv| 不卡的电视剧免费网站有什么| 亚洲影院在线观看| 国产一区二三区| 中文欧美字幕免费| 91蜜桃在线观看| 一区二区久久久| 欧美日韩国产成人在线免费| 免费成人av在线播放| 精品久久久久久久一区二区蜜臀| 国产在线麻豆精品观看| 国产三级一区二区| 91视频.com| 爽好久久久欧美精品| 日韩美女一区二区三区四区| 国内精品免费**视频| 国产精品乱人伦| 欧美另类videos死尸| 极品少妇xxxx偷拍精品少妇| 欧美韩国日本不卡| 欧美视频精品在线| 精品无人码麻豆乱码1区2区 | 欧美在线色视频| 国产一区二区0| 欧美日韩免费高清一区色橹橹| 日本道色综合久久| 欧美一区二区在线免费播放| 99国产精品久久久久久久久久久| 亚洲图片另类小说| 91精品国产欧美一区二区| 国产a区久久久| 日韩激情视频在线观看| 中文天堂在线一区| 日韩一区二区精品葵司在线| 成人黄色国产精品网站大全在线免费观看 | 1024亚洲合集| 日韩欧美的一区二区| www.亚洲免费av| 美女性感视频久久| 亚洲免费av高清| 久久精品夜色噜噜亚洲aⅴ| 欧美色区777第一页| 国产高清精品在线| 在线免费精品视频| 蜜桃视频第一区免费观看| 日韩三级免费观看| 欧美伊人精品成人久久综合97 | 日本道精品一区二区三区| 久久激情五月婷婷| 亚洲bt欧美bt精品| 亚洲视频一区二区在线| 久久久欧美精品sm网站| 日韩一区二区电影| 欧美日韩中文字幕一区二区| 成人av资源在线观看| 经典三级在线一区| 蜜臀va亚洲va欧美va天堂| 午夜免费久久看| 亚洲国产综合在线| 一区二区在线观看免费| 中文字幕一区三区| 国产精品亲子伦对白| 国产校园另类小说区| 精品久久免费看| 欧美xxx久久| 亚洲精品在线观| 欧美精品一区二区三区蜜桃视频| 欧美一区国产二区| 欧美一区二区三区视频免费播放| 色88888久久久久久影院野外| 国产精品18久久久久久久久| 国内精品视频666| 国产成人午夜精品5599| 成人毛片视频在线观看| 成人ar影院免费观看视频| 白白色亚洲国产精品| 色婷婷久久综合| 欧美主播一区二区三区| 欧美日韩国产综合一区二区| 91精品欧美一区二区三区综合在| 91精品国模一区二区三区| 日韩亚洲欧美一区二区三区| 日韩免费高清视频| 久久久精品黄色| 亚洲人精品一区| 一区二区久久久| 久久精品国产免费看久久精品| 久久99精品久久久久久国产越南| 另类小说视频一区二区| 成人少妇影院yyyy| 一本色道综合亚洲| 日韩一区二区视频| 欧美国产1区2区| 偷窥国产亚洲免费视频| 激情伊人五月天久久综合| 成人av一区二区三区| 欧美区一区二区三区| 亚洲精品一区二区精华| 一区免费观看视频| 天天免费综合色| 国产伦精品一区二区三区免费迷| 99re这里都是精品| 欧美高清激情brazzers| 精品成人在线观看| 夜夜揉揉日日人人青青一国产精品| 日韩不卡一二三区| www.66久久| 精品三级在线观看| 亚洲美女视频在线| 精品伊人久久久久7777人| 99精品视频一区| wwwwww.欧美系列| 香蕉久久一区二区不卡无毒影院| 国产一区二区福利| 欧美一区二区福利在线| 亚洲视频中文字幕|