cregit-Linux how code gets into the kernel

Release 4.7 drivers/i2c/busses/i2c-puv3.c

/*
 * I2C driver for PKUnity-v3 SoC
 * Code specific to PKUnity SoC and UniCore ISA
 *
 *      Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
 *      Copyright (C) 2001-2010 Guan Xuetao
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <mach/hardware.h>

/*
 * Poll the i2c status register until the specified bit is set.
 * Returns 0 if timed out (100 msec).
 */

static short poll_status(unsigned long bit) { int loop_cntr = 1000; if (bit & I2C_STATUS_TFNF) { do { udelay(10); } while (!(readl(I2C_STATUS) & bit) && (--loop_cntr > 0)); } else { /* RXRDY handler */ do { if (readl(I2C_TAR) == I2C_TAR_EEPROM) msleep(20); else udelay(10); } while (!(readl(I2C_RXFLR) & 0xf) && (--loop_cntr > 0)); } return (loop_cntr > 0); }

Contributors

PersonTokensPropCommitsCommitProp
guan xuetaoguan xuetao105100.00%1100.00%
Total105100.00%1100.00%


static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length) { int i2c_reg = *buf; /* Read data */ while (length--) { if (!poll_status(I2C_STATUS_TFNF)) { dev_dbg(&adap->dev, "Tx FIFO Not Full timeout\n"); return -ETIMEDOUT; } /* send addr */ writel(i2c_reg | I2C_DATACMD_WRITE, I2C_DATACMD); /* get ready to next write */ i2c_reg++; /* send read CMD */ writel(I2C_DATACMD_READ, I2C_DATACMD); /* wait until the Rx FIFO have available */ if (!poll_status(I2C_STATUS_RFNE)) { dev_dbg(&adap->dev, "RXRDY timeout\n"); return -ETIMEDOUT; } /* read the data to buf */ *buf = (readl(I2C_DATACMD) & I2C_DATACMD_DAT_MASK); buf++; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
guan xuetaoguan xuetao123100.00%1100.00%
Total123100.00%1100.00%


static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length) { int i2c_reg = *buf; /* Do nothing but storing the reg_num to a static variable */ if (i2c_reg == -1) { printk(KERN_WARNING "Error i2c reg\n"); return -ETIMEDOUT; } if (length == 1) return 0; buf++; length--; while (length--) { /* send addr */ writel(i2c_reg | I2C_DATACMD_WRITE, I2C_DATACMD); /* send write CMD */ writel(*buf | I2C_DATACMD_WRITE, I2C_DATACMD); /* wait until the Rx FIFO have available */ msleep(20); /* read the data to buf */ i2c_reg++; buf++; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
guan xuetaoguan xuetao104100.00%1100.00%
Total104100.00%1100.00%

/* * Generic i2c master transfer entrypoint. * */
static int puv3_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num) { int i, ret; unsigned char swap; /* Disable i2c */ writel(I2C_ENABLE_DISABLE, I2C_ENABLE); /* Set the work mode and speed*/ writel(I2C_CON_MASTER | I2C_CON_SPEED_STD | I2C_CON_SLAVEDISABLE, I2C_CON); writel(pmsg->addr, I2C_TAR); /* Enable i2c */ writel(I2C_ENABLE_ENABLE, I2C_ENABLE); dev_dbg(&adap->dev, "puv3_i2c_xfer: processing %d messages:\n", num); for (i = 0; i < num; i++) { dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i, pmsg->flags & I2C_M_RD ? "read" : "writ", pmsg->len, pmsg->len > 1 ? "s" : "", pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr); if (pmsg->len && pmsg->buf) { /* sanity check */ if (pmsg->flags & I2C_M_RD) ret = xfer_read(adap, pmsg->buf, pmsg->len); else ret = xfer_write(adap, pmsg->buf, pmsg->len); if (ret) return ret; } dev_dbg(&adap->dev, "transfer complete\n"); pmsg++; /* next message */ } /* XXX: fixup be16_to_cpu in bq27x00_battery.c */ if (pmsg->addr == I2C_TAR_PWIC) { swap = pmsg->buf[0]; pmsg->buf[0] = pmsg->buf[1]; pmsg->buf[1] = swap; } return i; }

Contributors

PersonTokensPropCommitsCommitProp
guan xuetaoguan xuetao261100.00%1100.00%
Total261100.00%1100.00%

/* * Return list of supported functionality. */
static u32 puv3_i2c_func(struct i2c_adapter *adapter) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; }

Contributors

PersonTokensPropCommitsCommitProp
guan xuetaoguan xuetao16100.00%1100.00%
Total16100.00%1100.00%

static struct i2c_algorithm puv3_i2c_algorithm = { .master_xfer = puv3_i2c_xfer, .functionality = puv3_i2c_func, }; /* * Main initialization routine. */
static int puv3_i2c_probe(struct platform_device *pdev) { struct i2c_adapter *adapter; struct resource *mem; int rc; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) return -ENODEV; if (!request_mem_region(mem->start, resource_size(mem), "puv3_i2c")) return -EBUSY; adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); if (adapter == NULL) { dev_err(&pdev->dev, "can't allocate interface!\n"); rc = -ENOMEM; goto fail_nomem; } snprintf(adapter->name, sizeof(adapter->name), "PUV3-I2C at 0x%08x", mem->start); adapter->algo = &puv3_i2c_algorithm; adapter->class = I2C_CLASS_HWMON; adapter->dev.parent = &pdev->dev; platform_set_drvdata(pdev, adapter); adapter->nr = pdev->id; rc = i2c_add_numbered_adapter(adapter); if (rc) { dev_err(&pdev->dev, "Adapter '%s' registration failed\n", adapter->name); goto fail_add_adapter; } dev_info(&pdev->dev, "PKUnity v3 i2c bus adapter.\n"); return 0; fail_add_adapter: kfree(adapter); fail_nomem: release_mem_region(mem->start, resource_size(mem)); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
guan xuetaoguan xuetao22999.57%150.00%
masanari iidamasanari iida10.43%150.00%
Total230100.00%2100.00%


static int puv3_i2c_remove(struct platform_device *pdev) { struct i2c_adapter *adapter = platform_get_drvdata(pdev); struct resource *mem; i2c_del_adapter(adapter); put_device(&pdev->dev); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(mem->start, resource_size(mem)); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
guan xuetaoguan xuetao6498.46%150.00%
lars-peter clausenlars-peter clausen11.54%150.00%
Total65100.00%2100.00%

#ifdef CONFIG_PM_SLEEP
static int puv3_i2c_suspend(struct device *dev) { int poll_count; /* Disable the IIC */ writel(I2C_ENABLE_DISABLE, I2C_ENABLE); for (poll_count = 0; poll_count < 50; poll_count++) { if (readl(I2C_ENSTATUS) & I2C_ENSTATUS_ENABLE) udelay(25); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
guan xuetaoguan xuetao5398.15%150.00%
rafael j. wysockirafael j. wysocki11.85%150.00%
Total54100.00%2100.00%

static SIMPLE_DEV_PM_OPS(puv3_i2c_pm, puv3_i2c_suspend, NULL); #define PUV3_I2C_PM (&puv3_i2c_pm) #else #define PUV3_I2C_PM NULL #endif static struct platform_driver puv3_i2c_driver = { .probe = puv3_i2c_probe, .remove = puv3_i2c_remove, .driver = { .name = "PKUnity-v3-I2C", .pm = PUV3_I2C_PM, } }; module_platform_driver(puv3_i2c_driver); MODULE_DESCRIPTION("PKUnity v3 I2C driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:puv3_i2c");

Overall Contributors

PersonTokensPropCommitsCommitProp
guan xuetaoguan xuetao106998.07%233.33%
rafael j. wysockirafael j. wysocki181.65%116.67%
masanari iidamasanari iida10.09%116.67%
lars-peter clausenlars-peter clausen10.09%116.67%
jingoo hanjingoo han10.09%116.67%
Total1090100.00%6100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}