Re: [PATCH] i2c: add driver for Rockchip RK3xxx SoC I2C adapter

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Max,

first of all, thanks for working on this :-)

I saw some general things inlined below, but I guess Wolfram is the better 
person to check the i2c-specifics.

Am Sonntag, 27. April 2014, 21:38:49 schrieb Max Schwarz:
> Driver for the native I2C adapter found in Rockchip RK3xxx SoCs.

[...]

> diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
> b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt new file mode 100644
> index 0000000..6778985
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
> @@ -0,0 +1,33 @@
> +* Rockchip RK3xxx I2C controller
> +
> +This driver interfaces with the native I2C controller present in Rockchip
> +RK3xxx SoCs.
> +
> +Required properties :
> +
> + - reg : Offset and length of the register set for the device
> + - compatible : should be "rockchip,rk3x-i2c"
> + - interrupts : interrupt number
> + - clocks : parent clock
> + - grf : the phandle of the syscon node for the general register file (GRF)
> + - bus-idx : index of the bus in the GRF

both the grf as well as the bus-idx are rockchip specific, so they should be 
prefixed (rockchip,grf, etc) and from my personal taste I would hope we could 
invest in an "n" and "e", to make it a full bus-index ;-)


> +
> +Optional properties :
> +
> + - frequency : SCL frequency to use (in Hz). If omitted, 100kHz is used.

the convention seems to be "clock-frequency" for the desired bus speed 
(checked i2c-sirf, i2c-exynos, i2c-at91and i2c-qup).


> +
> +Example:
> +
> +i2c0: i2c@2002d000 {
> +	compatible = "rockchip,rk3x-i2c";
> +	reg = <0x2002d000 0x1000>;
> +	interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	grf = <&grf>;
> +	bus-idx = <0>;
> +
> +	clock-names = "i2c";
> +	clocks = <&cru PCLK_I2C0>;
> +};
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index c94db1c..f973632 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -663,6 +663,16 @@ config I2C_PXA_SLAVE
>  	  is necessary for systems where the PXA may be a target on the
>  	  I2C bus.
> 
> +config I2C_RK3X
> +	tristate "Rockchip RK3xxx I2C adapter"
> +	depends on OF
> +	help
> +	  Say Y here to include support for the I2C adapter in Rockchip RK3xxx
> +	  SoCs.
> +
> +	  This driver can also be built as a module. If so, the module will
> +	  be called i2c-rk3x.
> +
>  config I2C_QUP
>  	tristate "Qualcomm QUP based I2C controller"
>  	depends on ARCH_QCOM
> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> index 18d18ff..39b6851 100644
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -65,6 +65,7 @@ obj-$(CONFIG_I2C_PNX)		+= i2c-pnx.o
>  obj-$(CONFIG_I2C_PUV3)		+= i2c-puv3.o
>  obj-$(CONFIG_I2C_PXA)		+= i2c-pxa.o
>  obj-$(CONFIG_I2C_PXA_PCI)	+= i2c-pxa-pci.o
> +obj-$(CONFIG_I2C_RK3X)		+= i2c-rk3x.o
>  obj-$(CONFIG_I2C_QUP)		+= i2c-qup.o
>  obj-$(CONFIG_I2C_RIIC)		+= i2c-riic.o
>  obj-$(CONFIG_I2C_S3C2410)	+= i2c-s3c2410.o
> diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
> new file mode 100644
> index 0000000..00491b0
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-rk3x.c
> @@ -0,0 +1,728 @@
> +/*
> + * Driver for I2C unit in Rockchip RK3188 SoC

RK3188 -> RK3xxx?

> + *
> + * Max Schwarz <max.schwarz@xxxxxxxxx>
> + * based on the patches by Rockchip Inc.
> + *
> + * 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/kernel.h>
> +#include <linux/module.h>
> +
> +#include <linux/i2c.h>
> +#include <linux/time.h>
> +#include <linux/interrupt.h>
> +#include <linux/delay.h>
> +#include <linux/errno.h>
> +#include <linux/err.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/spinlock.h>
> +#include <linux/clk.h>
> +#include <linux/wait.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/regmap.h>
> +
> +
> +/* Register Map */
> +#define REG_CON        0x00 /* control register */
> +#define REG_CLKDIV     0x04 /* clock divisor register */
> +#define REG_MRXADDR    0x08 /* slave address for REGISTER_TX */
> +#define REG_MRXRADDR   0x0c /* slave register address for REGISTER_TX */
> +#define REG_MTXCNT     0x10 /* number of bytes to be transmitted */
> +#define REG_MRXCNT     0x14 /* number of bytes to be received */
> +#define REG_IEN        0x18 /* interrupt enable */
> +#define REG_IPD        0x1c /* interrupt pending */
> +#define REG_FCNT       0x20 /* finished count */
> +
> +/* Data buffer offsets */
> +#define TXBUFFER_BASE 0x100
> +#define RXBUFFER_BASE 0x200
> +
> +/* REG_CON bits */
> +#define REG_CON_EN        (1 << 0)
> +enum {
> +	REG_CON_MOD_TX = 0,      /* transmit data */
> +	REG_CON_MOD_REGISTER_TX, /* select register and restart */
> +	REG_CON_MOD_RX,          /* receive data */
> +	REG_CON_MOD_REGISTER_RX, /* broken: transmits read addr AND writes
> +				  * register addr */
> +};
> +#define REG_CON_MOD(mod)  ((mod) << 1)
> +#define REG_CON_MOD_MASK  (3 << 1)
> +#define REG_CON_START     (1 << 3)
> +#define REG_CON_STOP      (1 << 4)
> +#define REG_CON_LASTACK   (1 << 5) /* 1: do not send ACK after last receive
> */ +#define REG_CON_ACTACK    (1 << 6) /* 1: stop if NACK is received */ +
> +/* REG_MRXADDR bits */
> +#define REG_MRXADDR_LOW   (1 << 24) /* bits [7:0] of MRX[R]ADDR are valid
> */ +#define REG_MRXADDR_MID   (1 << 25) /* bits [15:8] of MRX[R]ADDR are
> valid */ +#define REG_MRXADDR_HIGH  (1 << 26) /* bits [23:16] of MRX[R]ADDR
> are valid */ +
> +/* REG_IEN/REG_IPD bits */
> +#define REG_INT_BTF       (1 << 0) /* a byte was transmitted */
> +#define REG_INT_BRF       (1 << 1) /* a byte was received */
> +#define REG_INT_MBTF      (1 << 2) /* master data transmit finished */
> +#define REG_INT_MBRF      (1 << 3) /* master data receive finished */
> +#define REG_INT_START     (1 << 4) /* START condition generated */
> +#define REG_INT_STOP      (1 << 5) /* STOP condition generated */
> +#define REG_INT_NAKRCV    (1 << 6) /* NACK received */
> +#define REG_INT_ALL       0x7f
> +
> +/* Registers in the GRF (General Register File) */
> +#define GRF_SOC_CON1      4
> +
> +/* Constants */
> +#define WAIT_TIMEOUT      200 /* ms */
> +
> +enum rk3x_i2c_state {
> +	STATE_IDLE,
> +	STATE_START,
> +	STATE_READ,
> +	STATE_WRITE,
> +	STATE_STOP
> +};
> +
> +struct rk3x_i2c {
> +	struct i2c_adapter adap;
> +	struct device *dev;
> +
> +	/* Hardware resources */
> +	void __iomem *regs;
> +	struct regmap *grf;
> +	unsigned int bus_idx;
> +	struct clk *clk;
> +	int irq;
> +
> +	/* Settings */
> +	unsigned int scl_frequency;
> +
> +	/* Synchronization & notification */
> +	spinlock_t lock;
> +	wait_queue_head_t wait;
> +	bool busy;
> +
> +	/* Current message */
> +	struct i2c_msg *msg;
> +	u8 addr;
> +	unsigned int mode;
> +
> +	/* I2C state machine */
> +	enum rk3x_i2c_state state;
> +	unsigned int processed; /* sent/received bytes */
> +	int error;
> +};
> +
> +static inline void i2c_writel(struct rk3x_i2c *i2c, u32 value,
> +			      unsigned int offset)
> +{
> +	writel(value, i2c->regs + offset);
> +}
> +
> +static inline u32 i2c_readl(struct rk3x_i2c *i2c, unsigned int offset)
> +{
> +	return readl(i2c->regs + offset);
> +}

I'm not sure what the policy here is, but is this indirection really necessary 
when it's only doing a normal readl/writel?


Heiko
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux