转自:https://blog.csdn.net/lsn946803746/article/details/52515225
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lsn946803746/article/details/52515225
BLSP(BAM Low-Speed Peripheral) , 每一个BLSP含有两个QUP, 每一个QUP可以被配置为I2C, SPI, UART, UIM接口, BLSP是高通对于低速接口的一种管理方式。
i2c@f9923000 { /* BLSP-1 QUP-1 */
cell-index = <1>;
compatible = "qcom,i2c-qup";
#address-cells = <1>;
#size-cells = <0>;
reg-names = "qup_phys_addr";
reg = <0xf9923000 0x1000>;
interrupt-names = "qup_err_intr";
interrupts = <0 95 0>;
qcom,i2c-bus-freq = <100000>;
qcom,i2c-src-freq = <19200000>;
qcom,sda-gpio = <&msmgpio 2 0>;
qcom,scl-gpio = <&msmgpio 3 0>;
qcom,master-id = <86>;
};
i2c_cdc: i2c@f9927000 { /* BLSP1 QUP5 */
cell-index = <5>;
compatible = "qcom,i2c-qup";
#address-cells = <1>;
#size-cells = <0>;
reg-names = "qup_phys_addr";
reg = <0xf9927000 0x1000>;
interrupt-names = "qup_err_intr";
interrupts = <0 99 0>;
qcom,i2c-bus-freq = <100000>;
qcom,i2c-src-freq = <19200000>;
qcom,master-id = <86>;
};
i2c: i2c@f9928000 { /* BLSP1 QUP6 */
cell-index = <6>;
compatible = "qcom,i2c-qup";
#address-cells = <1>;
#size-cells = <0>;
reg-names = "qup_phys_addr";
reg = <0xf9928000 0x1000>;
interrupt-names = "qup_err_intr";
interrupts = <0 100 0>;
qcom,i2c-bus-freq = <100000>;
qcom,i2c-src-freq = <19200000>;
qcom,sda-gpio = <&msmgpio 16 0>;
qcom,scl-gpio = <&msmgpio 17 0>;
qcom,master-id = <86>;
};
i2c@f9924000 { /* BLSP-1 QUP-3 */
cell-index = <2>;
compatible = "qcom,i2c-qup";
#address-cells = <1>;
#size-cells = <0>;
reg-names = "qup_phys_addr";
reg = <0xf9924000 0x1000>;
interrupt-names = "qup_err_intr";
interrupts = <0 96 0>;
qcom,i2c-bus-freq = <100000>;
qcom,i2c-src-freq = <19200000>;
qcom,sda-gpio = <&msmgpio 8 0>;
qcom,scl-gpio = <&msmgpio 9 0>;
qcom,master-id = <86>;
};
i2c@f9925000 { /* BLSP-1 QUP-3 */
cell-index = <0>;
compatible = "qcom,i2c-qup";
#address-cells = <1>;
#size-cells = <0>;
reg-names = "qup_phys_addr";
reg = <0xf9925000 0x1000>;
interrupt-names = "qup_err_intr";
interrupts = <0 97 0>;
qcom,i2c-bus-freq = <100000>;
qcom,i2c-src-freq = <19200000>;
qcom,sda-gpio = <&msmgpio 10 0>;
qcom,scl-gpio = <&msmgpio 11 0>;
qcom,clk-ctl-xfer;
qcom,master-id = <86>;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
以上是I2C的硬件接口描述。
i2c@f9923000{ //I2C设备挂的两种设备 focaltech goodix
focaltech@38{
compatible = "focaltech,5x06";
reg = <0x38>;
interrupt-parent = <&msmgpio>;
interrupts = <1 0x2008>;
vdd-supply = <&pm8110_l19>;
vcc_i2c-supply = <&pm8110_l14>;
focaltech,name = "ft5x06";
focaltech,family-id = <0x54>;
focaltech,reset-gpio = <&msmgpio 0 0x00>;
focaltech,irq-gpio = <&msmgpio 1 0x00>;
focaltech,display-coords = <0 0 480 854>;
focaltech,button-map= <139 172 158>;
focaltech,no-force-update;
focaltech,i2c-pull-up;
focaltech,group-id = <1>;
focaltech,hard-reset-delay-ms = <20>;
focaltech,soft-reset-delay-ms = <150>;
focaltech,num-max-touches = <10>;
focaltech,fw-name = "5436_Ref_Asus89118_V12_D01_20160712_app.i";
focaltech,fw-delay-aa-ms = <50>;
focaltech,fw-delay-55-ms = <30>;
focaltech,fw-upgrade-id1 = <0x79>;
focaltech,fw-upgrade-id2 = <0x03>;
focaltech,fw-delay-readid-ms = <10>;
focaltech,fw-delay-era-flsh-ms = <2000>;
};
goodix@5d {
compatible = "goodix,gt915l"; //用于.of_match_table = goodix_match_table,
reg = <0x5d>; //地址
interrupt-parent = <&msmgpio>; //中断块
interrupts = <1 0x2008>; //中断地址
vdd_ana-supply = <&pm8110_l19>;
vcc_i2c-supply = <&pm8110_l14>;
goodix,rst-gpio = <&msmgpio 0 0x00>; //复位引脚
goodix,irq-gpio = <&msmgpio 1 0x00>; //中断引脚
//goodix,panel-coords = <0 0 540 980>;
//goodix,display-coords = <0 0 540 960>;
//goodix,button-map= <139 172 158>;
//goodix,product-id = "915L";
//goodix,enable-power-off;
goodix,cfg-group0 = [
47 E0 01 56 03 05 34 01 01 05
28 08 50 32 03 05 00 00 FF 7F
00 11 05 17 18 23 14 8C 2E 0E
35 33 0F 0A 00 00 01 BA 33 1D
00 01 00 00 00 00 00 0A 10 00
2B 2E 55 94 C5 02 00 00 00 04
83 31 00 79 37 00 70 3E 00 68
46 00 61 50 00 61 18 38 60 00
F0 4A 3A EE EE 27 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 0F 19 00 00
4B 37 0E 10 12 14 16 18 1A 1C
02 04 06 08 0A 0C 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 2A 29 28 26 24 22 21 20
1F 1E 1D 1C 16 18 00 02 04 06
08 0A 0C 0F 10 12 13 14 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 4C 01];
goodix,cfg-group2 = [
48 D0 02 00 05 05 75 01 01 0F 24
0F 64 3C 03 05 00 00 00 02 00 00
00 16 19 1C 14 8C 0E 0E 24 00 31
0D 00 00 00 83 33 1D 00 41 00 00
3C 0A 14 08 0A 00 2B 1C 3C 94 D5
03 08 00 00 04 93 1E 00 82 23 00
74 29 00 69 2F 00 5F 37 00 5F 20
40 60 00 F0 40 30 55 50 27 00 00
00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 14 19 00 00
50 50 02 04 06 08 0A 0C 0E 10 12
14 16 18 1A 1C 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 1D
1E 1F 20 21 22 24 26 28 29 2A 1C
18 16 14 13 12 10 0F 0C 0A 08 06
04 02 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 3C 01];
};
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
I2C bus 总线的构建。
在kernel/include/linux/init.h中
#define arch_initcall(fn)
#define __define_initcall(level,fn,id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn
1
2
3
4
将i2c-bus的driver init函数放到.initcall3.init 代码段中。
之所以,i2c-bus的driver和i2c 设备的驱动init函数使用的不同的函数放到.initcall代码段,主要原因是后面调用.initcall中的函数执行顺序是按.initcall段的函数顺序进行的(按照initcall的level从0到7依次存放的)。
#define INIT_CALLS_LEVEL(level) \
VMLINUX_SYMBOL(__initcall##level##_start) = .; \
*(.initcall##level##.init) \
*(.initcall##level##s.init)
#define INIT_CALLS \
VMLINUX_SYMBOL(__initcall_start) = .; \
*(.initcallearly.init) \
INIT_CALLS_LEVEL(0) \
INIT_CALLS_LEVEL(1) \
INIT_CALLS_LEVEL(2) \
INIT_CALLS_LEVEL(3) \
INIT_CALLS_LEVEL(4) \
INIT_CALLS_LEVEL(5) \
INIT_CALLS_LEVEL(rootfs) \
INIT_CALLS_LEVEL(6) \
INIT_CALLS_LEVEL(7) \
VMLINUX_SYMBOL(__initcall_end) = .;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
如module_init()的驱动初始化是等级66
(kernel/include/linux/init.h)
#define module_init(x) __initcall(x);
#define __initcall(fn) device_initcall(fn)
#define device_initcall(fn) __define_initcall("6",fn,6)
#define __define_initcall(level,fn,id) /
static initcall_t __initcall_##fn##id __used /
__attribute__((__section__(".initcall" level ".init"))) = fn
initcall_t(typedef int (*initcall_t)(void))
1
2
3
4
5
6
7
8
9
10
11
这就保证了I2C总线的会提前的注册好,在注册挂载的驱动和设备。
在linux /init/main.c 中,
static void __init do_initcalls(void)
{
initcall_t *call;
call = &__initcall_start;
do {
(*call)();
call++;
} while (call < &__initcall_end);
/* Make sure there is no pending stuff from the initcall sequence */
flush_scheduled_tasks();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
通过do_initcalls就可以把__initcall section段的函数调用起來。
kernel/drivers/i2c/busses/i2c-qup.c
/* Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*
* QUP driver for Qualcomm MSM platforms
*
*/
/* #define DEBUG */
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/i2c/i2c-qup.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/timer.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_i2c.h>
#include <linux/of_gpio.h>
#include <mach/board.h>
#include <mach/gpiomux.h>
#include <mach/msm_bus_board.h>
MODULE_LICENSE("GPL v2");
MODULE_VERSION("0.2");
MODULE_ALIAS("platform:i2c_qup");
/* QUP Registers */
enum {
QUP_CONFIG = 0x0,
QUP_STATE = 0x4,
QUP_IO_MODE = 0x8,
QUP_SW_RESET = 0xC,
QUP_OPERATIONAL = 0x18,
QUP_ERROR_FLAGS = 0x1C,
QUP_ERROR_FLAGS_EN = 0x20,
QUP_MX_READ_CNT = 0x208,
QUP_MX_INPUT_CNT = 0x200,
QUP_MX_WR_CNT = 0x100,
QUP_OUT_DEBUG = 0x108,
QUP_OUT_FIFO_CNT = 0x10C,
QUP_OUT_FIFO_BASE = 0x110,
QUP_IN_READ_CUR = 0x20C,
QUP_IN_DEBUG = 0x210,
QUP_IN_FIFO_CNT = 0x214,
QUP_IN_FIFO_BASE = 0x218,
QUP_I2C_CLK_CTL = 0x400,
QUP_I2C_STATUS = 0x404,
};
/* QUP States and reset values */
enum {
QUP_RESET_STATE = 0,
QUP_RUN_STATE = 1U,
QUP_STATE_MASK = 3U,
QUP_PAUSE_STATE = 3U,
QUP_STATE_VALID = 1U << 2,
QUP_I2C_MAST_GEN = 1U << 4,
QUP_OPERATIONAL_RESET = 0xFF0,
QUP_I2C_STATUS_RESET = 0xFFFFFC,
};
/* QUP OPERATIONAL FLAGS */
enum {
QUP_OUT_SVC_FLAG = 1U << 8,
QUP_IN_SVC_FLAG = 1U << 9,
QUP_MX_INPUT_DONE = 1U << 11,
};
/* QUP_CONFIG values and flags */
enum {
I2C_MINI_CORE = 2U << 8,
I2C_N_VAL = 0xF,
I2C_CORE_CLK_ON_EN = BIT(13),
};
/* Packing Unpacking words in FIFOs , and IO modes*/
enum {
QUP_WR_BLK_MODE = 1U << 10,
QUP_RD_BLK_MODE = 1U << 12,
QUP_UNPACK_EN = 1U << 14,
QUP_PACK_EN = 1U << 15,
};
/* QUP tags */
enum {
QUP_OUT_NOP = 0,
QUP_OUT_START = 1U << 8,
QUP_OUT_DATA = 2U << 8,
QUP_OUT_STOP = 3U << 8,
QUP_OUT_REC = 4U << 8,
QUP_IN_DATA = 5U << 8,
QUP_IN_STOP = 6U << 8,
QUP_IN_NACK = 7U << 8,
};
/* Status, Error flags */
enum {
I2C_STATUS_WR_BUFFER_FULL = 1U << 0,
I2C_STATUS_BUS_ACTIVE = 1U << 8,
I2C_STATUS_BUS_MASTER = 1U << 9,
I2C_STATUS_ERROR_MASK = 0x38000FC,
QUP_I2C_NACK_FLAG = 1U << 3,
QUP_IN_NOT_EMPTY = 1U << 5,
QUP_STATUS_ERROR_FLAGS = 0x7C,
};
/* Master status clock states */
enum {
I2C_CLK_RESET_BUSIDLE_STATE = 0,
I2C_CLK_FORCED_LOW_STATE = 5,
};
enum msm_i2c_state {
MSM_I2C_PM_ACTIVE,
MSM_I2C_PM_SUSPENDED,
MSM_I2C_SYS_SUSPENDING,
MSM_I2C_SYS_SUSPENDED,
};
#define QUP_MAX_CLK_STATE_RETRIES 300
#define DEFAULT_CLK_RATE (19200000)
#define I2C_STATUS_CLK_STATE 13
#define QUP_OUT_FIFO_NOT_EMPTY 0x10
#define I2C_GPIOS_DT_CNT (2) /* sda and scl */
static char const * const i2c_rsrcs[] = {"i2c_clk", "i2c_sda"};
static struct gpiomux_setting recovery_config = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_8MA,
.pull = GPIOMUX_PULL_NONE,
};
/**
* qup_i2c_clk_path_vote: data to use bus scaling driver for clock path vote
*
* @client_hdl when zero, client is not registered with the bus scaling driver,
* and bus scaling functionality should not be used. When non zero, it
* is a bus scaling client id and may be used to vote for clock path.
* @reg_err when true, registration error was detected and an error message was
* logged. i2c will attempt to re-register but will log error only once.
* once registration succeed, the flag is set to false.
*/
struct qup_i2c_clk_path_vote {
u32 client_hdl;
struct msm_bus_scale_pdata *pdata;
bool reg_err;
};
struct qup_i2c_dev {
struct device *dev;
void __iomem *base; /* virtual */
void __iomem *gsbi; /* virtual */
int in_irq;
int out_irq;
int err_irq;
int num_irqs;
struct clk *clk;
struct clk *pclk;
struct i2c_adapter adapter;
struct i2c_msg *msg;
int pos;
int cnt;
int err;
int mode;
int clk_ctl;
int one_bit_t;
int out_fifo_sz;
int in_fifo_sz;
int out_blk_sz;
int in_blk_sz;
int wr_sz;
struct msm_i2c_platform_data *pdata;
enum msm_i2c_state pwr_state;
atomic_t xfer_progress;
struct mutex mlock;
void *complete;
int i2c_gpios[ARRAY_SIZE(i2c_rsrcs)];
struct qup_i2c_clk_path_vote clk_path_vote;
};
#ifdef CONFIG_PM
static int i2c_qup_pm_resume_runtime(struct device *device);
#endif
#ifdef DEBUG
static void
qup_print_status(struct qup_i2c_dev *dev)
{
uint32_t val;
val = readl_relaxed(dev->base+QUP_CONFIG);
dev_dbg(dev->dev, "Qup config is :0x%x\n", val);
val = readl_relaxed(dev->base+QUP_STATE);
dev_dbg(dev->dev, "Qup state is :0x%x\n", val);
val = readl_relaxed(dev->base+QUP_IO_MODE);
dev_dbg(dev->dev, "Qup mode is :0x%x\n", val);
}
#else
static inline void qup_print_status(struct qup_i2c_dev *dev)
{
}
#endif
static irqreturn_t
qup_i2c_interrupt(int irq, void *devid)
{
struct qup_i2c_dev *dev = devid;
uint32_t status = 0;
uint32_t status1 = 0;
uint32_t op_flgs = 0;
int err = 0;
if (atomic_read(&dev->xfer_progress) != 1) {
dev_err(dev->dev, "irq:%d when PM suspended\n", irq);
return IRQ_NONE;
}
status = readl_relaxed(dev->base + QUP_I2C_STATUS);
status1 = readl_relaxed(dev->base + QUP_ERROR_FLAGS);
op_flgs = readl_relaxed(dev->base + QUP_OPERATIONAL);
if (!dev->msg || !dev->complete) {
/* Clear Error interrupt if it's a level triggered interrupt*/
if (dev->num_irqs == 1) {
writel_relaxed(QUP_RESET_STATE, dev->base+QUP_STATE);
/* Ensure that state is written before ISR exits */
mb();
}
return IRQ_HANDLED;
}
if (status & I2C_STATUS_ERROR_MASK) {
dev_err(dev->dev, "QUP: I2C status flags :0x%x, irq:%d\n",
status, irq);
err = status;
/* Clear Error interrupt if it's a level triggered interrupt*/
if (dev->num_irqs == 1) {
writel_relaxed(QUP_RESET_STATE, dev->base+QUP_STATE);
/* Ensure that state is written before ISR exits */
mb();
}
goto intr_done;
}
if (status1 & 0x7F) {
dev_err(dev->dev, "QUP: QUP status flags :0x%x\n", status1);
err = -status1;
/* Clear Error interrupt if it's a level triggered interrupt*/
if (dev->num_irqs == 1) {
writel_relaxed((status1 & QUP_STATUS_ERROR_FLAGS),
dev->base + QUP_ERROR_FLAGS);
/* Ensure that error flags are cleared before ISR
* exits
*/
mb();
}
goto intr_done;
}
if ((dev->num_irqs == 3) && (dev->msg->flags == I2C_M_RD)
&& (irq == dev->out_irq))
return IRQ_HANDLED;
if (op_flgs & QUP_OUT_SVC_FLAG) {
writel_relaxed(QUP_OUT_SVC_FLAG, dev->base + QUP_OPERATIONAL);
/* Ensure that service flag is acknowledged before ISR exits */
mb();
}
if (dev->msg->flags == I2C_M_RD) {
if ((op_flgs & QUP_MX_INPUT_DONE) ||
(op_flgs & QUP_IN_SVC_FLAG)) {
writel_relaxed(QUP_IN_SVC_FLAG, dev->base
+ QUP_OPERATIONAL);
/* Ensure that service flag is acknowledged before ISR
* exits
*/
mb();
} else
return IRQ_HANDLED;
}
intr_done:
dev_dbg(dev->dev, "QUP intr= %d, i2c status=0x%x, qup status = 0x%x\n",
irq, status, status1);
qup_print_status(dev);
dev->err = err;
complete(dev->complete);
return IRQ_HANDLED;
}
static int
qup_i2c_poll_state(struct qup_i2c_dev *dev, uint32_t req_state, bool only_valid)
{
uint32_t retries = 0;
dev_dbg(dev->dev, "Polling for state:0x%x, or valid-only:%d\n",
req_state, only_valid);
while (retries != 2000) {
uint32_t status = readl_relaxed(dev->base + QUP_STATE);
/*
* If only valid bit needs to be checked, requested state is
* 'don't care'
*/
if (status & QUP_STATE_VALID) {
if (only_valid)
return 0;
else if ((req_state & QUP_I2C_MAST_GEN) &&
(status & QUP_I2C_MAST_GEN))
return 0;
else if ((status & QUP_STATE_MASK) == req_state)
return 0;
}
if (retries++ == 1000)
udelay(100);
}
return -ETIMEDOUT;
}
static int
qup_update_state(struct qup_i2c_dev *dev, uint32_t state)
{
if (qup_i2c_poll_state(dev, 0, true) != 0)
return -EIO;
writel_relaxed(state, dev->base + QUP_STATE);
if (qup_i2c_poll_state(dev, state, false) != 0)
return -EIO;
return 0;
}
#define MSM_I2C_CLK_PATH_SUSPEND (0)
#define MSM_I2C_CLK_PATH_RESUME (1)
#define MSM_I2C_CLK_PATH_MAX_BW(dev) ((dev->pdata->src_clk_rate * 8) / 1000)
static int i2c_qup_clk_path_init(struct platform_device *pdev,
struct qup_i2c_dev *dev)
{
struct msm_bus_vectors *paths = NULL;
struct msm_bus_paths *usecases = NULL;
if (!dev->pdata->master_id)
return 0;
dev_dbg(&pdev->dev, "initialises bus-scaling clock voting");
paths = devm_kzalloc(&pdev->dev, sizeof(*paths) * 2, GFP_KERNEL);
if (!paths) {
dev_err(&pdev->dev,
"msm_bus_paths.paths memory allocation failed");
return -ENOMEM;
}
usecases = devm_kzalloc(&pdev->dev, sizeof(*usecases) * 2, GFP_KERNEL);
if (!usecases) {
dev_err(&pdev->dev,
"msm_bus_scale_pdata.usecases memory allocation failed");
goto path_init_err;
}
dev->clk_path_vote.pdata = devm_kzalloc(&pdev->dev,
sizeof(*dev->clk_path_vote.pdata),
GFP_KERNEL);
if (!dev->clk_path_vote.pdata) {
dev_err(&pdev->dev,
"msm_bus_scale_pdata memory allocation failed");
goto path_init_err;
}
paths[MSM_I2C_CLK_PATH_SUSPEND] = (struct msm_bus_vectors) {
dev->pdata->master_id, MSM_BUS_SLAVE_EBI_CH0, 0, 0
};
paths[MSM_I2C_CLK_PATH_RESUME] = (struct msm_bus_vectors) {
dev->pdata->master_id, MSM_BUS_SLAVE_EBI_CH0, 0,
MSM_I2C_CLK_PATH_MAX_BW(dev)
};
usecases[MSM_I2C_CLK_PATH_SUSPEND] = (struct msm_bus_paths) {
.num_paths = 1,
.vectors = &paths[MSM_I2C_CLK_PATH_SUSPEND],
};
usecases[MSM_I2C_CLK_PATH_RESUME] = (struct msm_bus_paths) {
.num_paths = 1,
.vectors = &paths[MSM_I2C_CLK_PATH_RESUME],
};
*dev->clk_path_vote.pdata = (struct msm_bus_scale_pdata) {
.active_only = dev->pdata->active_only,
.name = pdev->name,
.num_usecases = 2,
.usecase = usecases,
};
return 0;
path_init_err:
devm_kfree(&pdev->dev, paths);
devm_kfree(&pdev->dev, usecases);
devm_kfree(&pdev->dev, dev->clk_path_vote.pdata);
dev->clk_path_vote.pdata = NULL;
return -ENOMEM;
}
static void i2c_qup_clk_path_teardown(struct qup_i2c_dev *dev)
{
if (dev->clk_path_vote.client_hdl) {
msm_bus_scale_unregister_client(dev->clk_path_vote.client_hdl);
dev->clk_path_vote.client_hdl = 0;
}
}
static void i2c_qup_clk_path_vote(struct qup_i2c_dev *dev)
{
if (dev->clk_path_vote.client_hdl)
msm_bus_scale_client_update_request(
dev->clk_path_vote.client_hdl,
MSM_I2C_CLK_PATH_RESUME);
}
static void i2c_qup_clk_path_unvote(struct qup_i2c_dev *dev)
{
if (dev->clk_path_vote.client_hdl)
msm_bus_scale_client_update_request(
dev->clk_path_vote.client_hdl,
MSM_I2C_CLK_PATH_SUSPEND);
}
/**
* i2c_qup_clk_path_postponed_register: reg with bus-scaling after it is probed
*
* Workaround: i2c driver may be probed before the bus scaling driver. Thus,
* this function should be called not from probe but from a later context.
* This function may be called more then once before register succeed. At
* this case only one error message will be logged. At boot time all clocks
* are on, so earlier i2c transactions should succeed.
*/
static void i2c_qup_clk_path_postponed_register(struct qup_i2c_dev *dev)
{
/*
* bail out if path voting is diabled (master_id == 0) or if it is
* already registered (client_hdl != 0)
*/
if (!dev->pdata->master_id || dev->clk_path_vote.client_hdl)
return;
dev->clk_path_vote.client_hdl = msm_bus_scale_register_client(
dev->clk_path_vote.pdata);
if (dev->clk_path_vote.client_hdl) {
if (dev->clk_path_vote.reg_err) {
/* log a success message if an error msg was logged */
dev->clk_path_vote.reg_err = false;
dev_info(dev->dev,
"msm_bus_scale_register_client(mstr-id:%d "
"actv-only:%d):0x%x",
dev->pdata->master_id, dev->pdata->active_only,
dev->clk_path_vote.client_hdl);
}
if (dev->pdata->active_only)
i2c_qup_clk_path_vote(dev);
} else {
/* guard to log only one error on multiple failure */
if (!dev->clk_path_vote.reg_err) {
dev->clk_path_vote.reg_err = true;
dev_info(dev->dev,
"msm_bus_scale_register_client(mstr-id:%d "
"actv-only:%d):0",
dev->pdata->master_id, dev->pdata->active_only);
}
}
}
static int i2c_qup_gpio_request(struct qup_i2c_dev *dev)
{
int i;
int result = 0;
for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
if (dev->i2c_gpios[i] >= 0) {
result = gpio_request(dev->i2c_gpios[i], i2c_rsrcs[i]);
if (result) {
dev_err(dev->dev,
"gpio_request for pin %d failed with error %d\n",
dev->i2c_gpios[i], result);
goto error;
}
}
}
return 0;
error:
for (; --i >= 0;) {
if (dev->i2c_gpios[i] >= 0)
gpio_free(dev->i2c_gpios[i]);
}
return result;
}
static void i2c_qup_gpio_free(struct qup_i2c_dev *dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
if (dev->i2c_gpios[i] >= 0)
gpio_free(dev->i2c_gpios[i]);
}
}
static void i2c_qup_pm_suspend_clk(struct qup_i2c_dev *dev)
{
uint32_t status;
/* reset core and enable conditional dynamic clock gating */
qup_update_state(dev, QUP_RESET_STATE);
status = readl_relaxed(dev->base + QUP_CONFIG);
status |= I2C_CORE_CLK_ON_EN;
writel_relaxed(status, dev->base + QUP_CONFIG);
/* ensure that write has really gone through */
mb();
clk_disable_unprepare(dev->clk);
if (!dev->pdata->keep_ahb_clk_on)
clk_disable_unprepare(dev->pclk);
}
static void i2c_qup_pm_resume_clk(struct qup_i2c_dev *dev)
{
clk_prepare_enable(dev->clk);
if (!dev->pdata->keep_ahb_clk_on)
clk_prepare_enable(dev->pclk);
}
static void i2c_qup_pm_suspend(struct qup_i2c_dev *dev)
{
if (dev->pwr_state == MSM_I2C_PM_SUSPENDED) {
dev_err(dev->dev, "attempt to suspend when suspended\n");
return;
}
if (!dev->pdata->clk_ctl_xfer)
i2c_qup_pm_suspend_clk(dev);
if (!dev->pdata->active_only)
i2c_qup_clk_path_unvote(dev);
i2c_qup_gpio_free(dev);
dev->pwr_state = MSM_I2C_PM_SUSPENDED;
}
static void i2c_qup_pm_resume(struct qup_i2c_dev *dev)
{
if (dev->pwr_state == MSM_I2C_PM_ACTIVE)
return;
i2c_qup_gpio_request(dev);
i2c_qup_clk_path_postponed_register(dev);
if (!dev->pdata->active_only)
i2c_qup_clk_path_vote(dev);
if (!dev->pdata->clk_ctl_xfer)
i2c_qup_pm_resume_clk(dev);
dev->pwr_state = MSM_I2C_PM_ACTIVE;
}
static int
qup_i2c_poll_writeready(struct qup_i2c_dev *dev, int rem)
{
uint32_t retries = 0;
while (retries != 2000) {
uint32_t status = readl_relaxed(dev->base + QUP_I2C_STATUS);
if (!(status & I2C_STATUS_WR_BUFFER_FULL)) {
if (((dev->msg->flags & I2C_M_RD) || (rem == 0)) &&
!(status & I2C_STATUS_BUS_ACTIVE))
return 0;
else if ((dev->msg->flags == 0) && (rem > 0))
return 0;
else /* 1-bit delay before we check for bus busy */
udelay(dev->one_bit_t);
}
if (retries++ == 1000) {
/*
* Wait for FIFO number of bytes to be absolutely sure
* that I2C write state machine is not idle. Each byte
* takes 9 clock cycles. (8 bits + 1 ack)
*/
usleep_range((dev->one_bit_t * (dev->out_fifo_sz * 9)),
(dev->one_bit_t * (dev->out_fifo_sz * 9)));
}
}
qup_print_status(dev);
return -ETIMEDOUT;
}
static int qup_i2c_poll_clock_ready(struct qup_i2c_dev *dev)
{
uint32_t retries = 0;
uint32_t op_flgs = -1, clk_state = -1;
/*
* Wait for the clock state to transition to either IDLE or FORCED
* LOW. This will usually happen within one cycle of the i2c clock.
*/
while (retries++ < QUP_MAX_CLK_STATE_RETRIES) {
uint32_t status = readl_relaxed(dev->base + QUP_I2C_STATUS);
clk_state = (status >> I2C_STATUS_CLK_STATE) & 0x7;
/* Read the operational register */
op_flgs = readl_relaxed(dev->base +
QUP_OPERATIONAL) & QUP_OUT_FIFO_NOT_EMPTY;
/*
* In very corner case when slave do clock stretching and
* output fifo will have 1 block of data space empty at
* the same time. So i2c qup will get output service
* interrupt and as it doesn't have more data to be written.
* This can lead to issue where output fifo is not empty.
*/
if (op_flgs == 0 &&
(clk_state == I2C_CLK_RESET_BUSIDLE_STATE ||
clk_state == I2C_CLK_FORCED_LOW_STATE)){
dev_dbg(dev->dev, "clk_state 0x%x op_flgs [%x]\n",
clk_state, op_flgs);
return 0;
}
/* 1-bit delay before we check again */
udelay(dev->one_bit_t);
}
dev_err(dev->dev, "Error waiting for clk ready clk_state: 0x%x op_flgs: 0x%x\n",
clk_state, op_flgs);
return -ETIMEDOUT;
}
#ifdef DEBUG
static void qup_verify_fifo(struct qup_i2c_dev *dev, uint32_t val,
uint32_t addr, int rdwr)
{
if (rdwr)
dev_dbg(dev->dev, "RD:Wrote 0x%x to out_ff:0x%x\n", val, addr);
else
dev_dbg(dev->dev, "WR:Wrote 0x%x to out_ff:0x%x\n", val, addr);
}
#else
static inline void qup_verify_fifo(struct qup_i2c_dev *dev, uint32_t val,
uint32_t addr, int rdwr)
{
}
#endif
static void
qup_issue_read(struct qup_i2c_dev *dev, struct i2c_msg *msg, int *idx,
uint32_t carry_over)
{
uint16_t addr = (msg->addr << 1) | 1;
/* QUP limit 256 bytes per read. By HW design, 0 in the 8-bit field
* is treated as 256 byte read.
*/
uint16_t rd_len = ((dev->cnt == 256) ? 0 : dev->cnt);
if (*idx % 4) {
writel_relaxed(carry_over | ((QUP_OUT_START | addr) << 16),
dev->base + QUP_OUT_FIFO_BASE);/* + (*idx-2)); */
qup_verify_fifo(dev, carry_over |
((QUP_OUT_START | addr) << 16), (uint32_t)dev->base
+ QUP_OUT_FIFO_BASE + (*idx - 2), 1);
writel_relaxed((QUP_OUT_REC | rd_len),
dev->base + QUP_OUT_FIFO_BASE);/* + (*idx+2)); */
qup_verify_fifo(dev, (QUP_OUT_REC | rd_len),
(uint32_t)dev->base + QUP_OUT_FIFO_BASE + (*idx + 2), 1);
} else {
writel_relaxed(((QUP_OUT_REC | rd_len) << 16)
| QUP_OUT_START | addr,
dev->base + QUP_OUT_FIFO_BASE);/* + (*idx)); */
qup_verify_fifo(dev, QUP_OUT_REC << 16 | rd_len << 16 |
QUP_OUT_START | addr,
(uint32_t)dev->base + QUP_OUT_FIFO_BASE + (*idx), 1);
}
*idx += 4;
}
static void
qup_issue_write(struct qup_i2c_dev *dev, struct i2c_msg *msg, int rem,
int *idx, uint32_t *carry_over)
{
int entries = dev->cnt;
int empty_sl = dev->wr_sz - ((*idx) >> 1);
int i = 0;
uint32_t val = 0;
uint32_t last_entry = 0;
uint16_t addr = msg->addr << 1;
if (dev->pos == 0) {
if (*idx % 4) {
writel_relaxed(*carry_over | ((QUP_OUT_START |
addr) << 16),
dev->base + QUP_OUT_FIFO_BASE);
qup_verify_fifo(dev, *carry_over | QUP_OUT_START << 16 |
addr << 16, (uint32_t)dev->base +
QUP_OUT_FIFO_BASE + (*idx) - 2, 0);
} else
val = QUP_OUT_START | addr;
*idx += 2;
i++;
entries++;
} else {
/* Avoid setp time issue by adding 1 NOP when number of bytes
* are more than FIFO/BLOCK size. setup time issue can't appear
* otherwise since next byte to be written will always be ready
*/
val = (QUP_OUT_NOP | 1);
*idx += 2;
i++;
entries++;
}
if (entries > empty_sl)
entries = empty_sl;
for (; i < (entries - 1); i++) {
if (*idx % 4) {
writel_relaxed(val | ((QUP_OUT_DATA |
msg->buf[dev->pos]) << 16),
dev->base + QUP_OUT_FIFO_BASE);
qup_verify_fifo(dev, val | QUP_OUT_DATA << 16 |
msg->buf[dev->pos] << 16, (uint32_t)dev->base +
QUP_OUT_FIFO_BASE + (*idx) - 2, 0);
} else
val = QUP_OUT_DATA | msg->buf[dev->pos];
(*idx) += 2;
dev->pos++;
}
if (dev->pos < (msg->len - 1))
last_entry = QUP_OUT_DATA;
else if (rem > 1) /* not last array entry */
last_entry = QUP_OUT_DATA;
else
last_entry = QUP_OUT_STOP;
if ((*idx % 4) == 0) {
/*
* If read-start and read-command end up in different fifos, it
* may result in extra-byte being read due to extra-read cycle.
* Avoid that by inserting NOP as the last entry of fifo only
* if write command(s) leave 1 space in fifo.
*/
if (rem > 1) {
struct i2c_msg *next = msg + 1;
if (next->addr == msg->addr && (next->flags & I2C_M_RD)
&& *idx == ((dev->wr_sz*2) - 4)) {
writel_relaxed(((last_entry |
msg->buf[dev->pos]) |
((1 | QUP_OUT_NOP) << 16)), dev->base +
QUP_OUT_FIFO_BASE);/* + (*idx) - 2); */
qup_verify_fifo(dev,
((last_entry | msg->buf[dev->pos]) |
((1 | QUP_OUT_NOP) << 16)),
(uint32_t)dev->base +
QUP_OUT_FIFO_BASE + (*idx), 0);
*idx += 2;
} else if ((dev->pos == msg->len - 1)
&& *idx < (dev->wr_sz*2) &&
(next->addr != msg->addr)) {
/* Last byte of an intermittent write */
writel_relaxed((QUP_OUT_STOP |
msg->buf[dev->pos]),
dev->base + QUP_OUT_FIFO_BASE);
qup_verify_fifo(dev,
QUP_OUT_STOP | msg->buf[dev->pos],
(uint32_t)dev->base +
QUP_OUT_FIFO_BASE + (*idx), 0);
*idx += 2;
} else
*carry_over = (last_entry | msg->buf[dev->pos]);
} else {
writel_relaxed((last_entry | msg->buf[dev->pos]),
dev->base + QUP_OUT_FIFO_BASE);/* + (*idx) - 2); */
qup_verify_fifo(dev, last_entry | msg->buf[dev->pos],
(uint32_t)dev->base + QUP_OUT_FIFO_BASE +
(*idx), 0);
}
} else {
writel_relaxed(val | ((last_entry | msg->buf[dev->pos]) << 16),
dev->base + QUP_OUT_FIFO_BASE);/* + (*idx) - 2); */
qup_verify_fifo(dev, val | (last_entry << 16) |
(msg->buf[dev->pos] << 16), (uint32_t)dev->base +
QUP_OUT_FIFO_BASE + (*idx) - 2, 0);
}
*idx += 2;
dev->pos++;
dev->cnt = msg->len - dev->pos;
}
static void
qup_set_read_mode(struct qup_i2c_dev *dev, int rd_len)
{
uint32_t wr_mode = (dev->wr_sz < dev->out_fifo_sz) ?
QUP_WR_BLK_MODE : 0;
if (rd_len > 256) {
dev_dbg(dev->dev, "HW limit: Breaking reads in chunk of 256\n");
rd_len = 256;
}
if (rd_len <= dev->in_fifo_sz) {
writel_relaxed(wr_mode | QUP_PACK_EN | QUP_UNPACK_EN,
dev->base + QUP_IO_MODE);
writel_relaxed(rd_len, dev->base + QUP_MX_READ_CNT);
} else {
writel_relaxed(wr_mode | QUP_RD_BLK_MODE |
QUP_PACK_EN | QUP_UNPACK_EN, dev->base + QUP_IO_MODE);
writel_relaxed(rd_len, dev->base + QUP_MX_INPUT_CNT);
}
}
static int
qup_set_wr_mode(struct qup_i2c_dev *dev, int rem)
{
int total_len = 0;
int ret = 0;
int len = dev->msg->len;
struct i2c_msg *next = NULL;
if (rem > 1)
next = dev->msg + 1;
while (rem > 1 && next->flags == 0 && (next->addr == dev->msg->addr)) {
len += next->len + 1;
next = next + 1;
rem--;
}
if (len >= (dev->out_fifo_sz - 1)) {
total_len = len + 1 + (len/(dev->out_blk_sz-1));
writel_relaxed(QUP_WR_BLK_MODE | QUP_PACK_EN | QUP_UNPACK_EN,
dev->base + QUP_IO_MODE);
dev->wr_sz = dev->out_blk_sz;
} else
writel_relaxed(QUP_PACK_EN | QUP_UNPACK_EN,
dev->base + QUP_IO_MODE);
if (rem > 1) {
if (next->addr == dev->msg->addr &&
next->flags == I2C_M_RD) {
qup_set_read_mode(dev, next->len);
/* make sure read start & read command are in 1 blk */
if ((total_len % dev->out_blk_sz) ==
(dev->out_blk_sz - 1))
total_len += 3;
else
total_len += 2;
}
}
/* WRITE COUNT register valid/used only in block mode */
if (dev->wr_sz == dev->out_blk_sz)
writel_relaxed(total_len, dev->base + QUP_MX_WR_CNT);
return ret;
}
static void qup_i2c_recover_bus_busy(struct qup_i2c_dev *dev)
{
int i;
int gpio_clk;
int gpio_dat;
bool gpio_clk_status = false;
uint32_t status = readl_relaxed(dev->base + QUP_I2C_STATUS);
struct gpiomux_setting old_gpio_setting[ARRAY_SIZE(i2c_rsrcs)];
if (dev->pdata->msm_i2c_config_gpio)
return;
if (!(status & (I2C_STATUS_BUS_ACTIVE)) ||
(status & (I2C_STATUS_BUS_MASTER)))
return;
gpio_clk = dev->i2c_gpios[0];
gpio_dat = dev->i2c_gpios[1];
if ((gpio_clk == -1) && (gpio_dat == -1)) {
dev_err(dev->dev, "Recovery failed due to undefined GPIO's\n");
return;
}
disable_irq(dev->err_irq);
for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
if (msm_gpiomux_write(dev->i2c_gpios[i], GPIOMUX_ACTIVE,
&recovery_config, &old_gpio_setting[i])) {
dev_err(dev->dev, "GPIO pins have no active setting\n");
goto recovery_end;
}
}
dev_warn(dev->dev, "i2c_scl: %d, i2c_sda: %d\n",
gpio_get_value(gpio_clk), gpio_get_value(gpio_dat));
for (i = 0; i < 9; i++) {
if (gpio_get_value(gpio_dat) && gpio_clk_status)
break;
gpio_direction_output(gpio_clk, 0);
udelay(5);
gpio_direction_output(gpio_dat, 0);
udelay(5);
gpio_direction_input(gpio_clk);
udelay(5);
if (!gpio_get_value(gpio_clk))
udelay(20);
if (!gpio_get_value(gpio_clk))
usleep_range(10000, 10000);
gpio_clk_status = gpio_get_value(gpio_clk);
gpio_direction_input(gpio_dat);
udelay(5);
}
/* Configure ALT funciton to QUP I2C*/
for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
msm_gpiomux_write(dev->i2c_gpios[i], GPIOMUX_ACTIVE,
&old_gpio_setting[i], NULL);
}
udelay(10);
status = readl_relaxed(dev->base + QUP_I2C_STATUS);
if (!(status & I2C_STATUS_BUS_ACTIVE)) {
dev_info(dev->dev, "Bus busy cleared after %d clock cycles, "
"status %x\n",
i, status);
goto recovery_end;
}
dev_warn(dev->dev, "Bus still busy, status %x\n", status);
recovery_end:
enable_irq(dev->err_irq);
}
static int
qup_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
DECLARE_COMPLETION_ONSTACK(complete);
struct qup_i2c_dev *dev = i2c_get_adapdata(adap);
int ret;
int rem = num;
long timeout;
int err;
/*
* If all slaves of this controller behave as expected, they will
* implement suspend and won't call any transaction if they are
* suspended. Since controller is its parent, controller's suspend
* will be called only AFTER alls slaves are suspended.
* However reality is differe and some slave don't implement suspend
* If a slave tries to initiate transfer when we are suspended,
* pm_runtime_enabled is set to false by system-pm.
* Make sure we return error when transaction is initiated while
* we are in suspended state
*/
mutex_lock(&dev->mlock);
if (dev->pwr_state >= MSM_I2C_SYS_SUSPENDING) {
dev_err(dev->dev,
"xfer not allowed when ctrl is suspended addr:0x%x\n",
msgs->addr);
mutex_unlock(&dev->mlock);
return -EIO;
}
if (!pm_runtime_enabled(dev->dev)) {
dev_dbg(dev->dev, "Runtime PM FEATURE is disabled\n");
i2c_qup_pm_resume(dev);
} else {
pm_runtime_get_sync(dev->dev);
}
if (dev->pdata->clk_ctl_xfer)
i2c_qup_pm_resume_clk(dev);
atomic_set(&dev->xfer_progress, 1);
/* Initialize QUP registers during first transfer */
if (dev->clk_ctl == 0) {
int fs_div;
int hs_div;
uint32_t fifo_reg;
if (dev->gsbi) {
writel_relaxed(0x2 << 4, dev->gsbi);
/* GSBI memory is not in the same 1K region as other
* QUP registers. mb() here ensures that the GSBI
* register is updated in correct order and that the
* write has gone through before programming QUP core
* registers
*/
mb();
}
fs_div = ((dev->pdata->src_clk_rate
/ dev->pdata->clk_freq) / 2) - 3;
hs_div = 3;
dev->clk_ctl = ((hs_div & 0x7) << 8) | (fs_div & 0xff);
fifo_reg = readl_relaxed(dev->base + QUP_IO_MODE);
if (fifo_reg & 0x3)
dev->out_blk_sz = (fifo_reg & 0x3) * 16;
else
dev->out_blk_sz = 16;
if (fifo_reg & 0x60)
dev->in_blk_sz = ((fifo_reg & 0x60) >> 5) * 16;
else
dev->in_blk_sz = 16;
/*
* The block/fifo size w.r.t. 'actual data' is 1/2 due to 'tag'
* associated with each byte written/received
*/
dev->out_blk_sz /= 2;
dev->in_blk_sz /= 2;
dev->out_fifo_sz = dev->out_blk_sz *
(2 << ((fifo_reg & 0x1C) >> 2));
dev->in_fifo_sz = dev->in_blk_sz *
(2 << ((fifo_reg & 0x380) >> 7));
dev_dbg(dev->dev, "QUP IN:bl:%d, ff:%d, OUT:bl:%d, ff:%d\n",
dev->in_blk_sz, dev->in_fifo_sz,
dev->out_blk_sz, dev->out_fifo_sz);
}
writel_relaxed(1, dev->base + QUP_SW_RESET);
ret = qup_i2c_poll_state(dev, QUP_RESET_STATE, false);
if (ret) {
dev_err(dev->dev, "QUP Busy:Trying to recover\n");
goto out_err;
}
if (dev->num_irqs == 3) {
enable_irq(dev->in_irq);
enable_irq(dev->out_irq);
}
enable_irq(dev->err_irq);
/* Initialize QUP registers */
writel_relaxed(0, dev->base + QUP_CONFIG);
writel_relaxed(QUP_OPERATIONAL_RESET, dev->base + QUP_OPERATIONAL);
writel_relaxed(QUP_STATUS_ERROR_FLAGS, dev->base + QUP_ERROR_FLAGS_EN);
writel_relaxed(I2C_MINI_CORE | I2C_N_VAL, dev->base + QUP_CONFIG);
/* Initialize I2C mini core registers */
writel_relaxed(0, dev->base + QUP_I2C_CLK_CTL);
writel_relaxed(QUP_I2C_STATUS_RESET, dev->base + QUP_I2C_STATUS);
while (rem) {
bool filled = false;
dev->cnt = msgs->len - dev->pos;
dev->msg = msgs;
dev->wr_sz = dev->out_fifo_sz;
dev->err = 0;
dev->complete = &complete;
if (qup_i2c_poll_state(dev, QUP_I2C_MAST_GEN, false) != 0) {
ret = -EIO;
goto out_err;
}
qup_print_status(dev);
/* HW limits Read upto 256 bytes in 1 read without stop */
if (dev->msg->flags & I2C_M_RD) {
qup_set_read_mode(dev, dev->cnt);
if (dev->cnt > 256)
dev->cnt = 256;
} else {
ret = qup_set_wr_mode(dev, rem);
if (ret != 0)
goto out_err;
/* Don't fill block till we get interrupt */
if (dev->wr_sz == dev->out_blk_sz)
filled = true;
}
err = qup_update_state(dev, QUP_RUN_STATE);
if (err < 0) {
ret = err;
goto out_err;
}
qup_print_status(dev);
writel_relaxed(dev->clk_ctl, dev->base + QUP_I2C_CLK_CTL);
/* CLK_CTL register is not in the same 1K region as other QUP
* registers. Ensure that clock control is written before
* programming other QUP registers
*/
mb();
do {
int idx = 0;
uint32_t carry_over = 0;
/* Transition to PAUSE state only possible from RUN */
err = qup_update_state(dev, QUP_PAUSE_STATE);
if (err < 0) {
ret = err;
goto out_err;
}
qup_print_status(dev);
/* This operation is Write, check the next operation
* and decide mode
*/
while (filled == false) {
if ((msgs->flags & I2C_M_RD))
qup_issue_read(dev, msgs, &idx,
carry_over);
else if (!(msgs->flags & I2C_M_RD))
qup_issue_write(dev, msgs, rem, &idx,
&carry_over);
if (idx >= (dev->wr_sz << 1))
filled = true;
/* Start new message */
if (filled == false) {
if (msgs->flags & I2C_M_RD)
filled = true;
else if (rem > 1) {
/* Only combine operations with
* same address
*/
struct i2c_msg *next = msgs + 1;
if (next->addr != msgs->addr)
filled = true;
else {
rem--;
msgs++;
dev->msg = msgs;
dev->pos = 0;
dev->cnt = msgs->len;
if (msgs->len > 256)
dev->cnt = 256;
}
} else
filled = true;
}
}
err = qup_update_state(dev, QUP_RUN_STATE);
if (err < 0) {
ret = err;
goto out_err;
}
dev_dbg(dev->dev, "idx:%d, rem:%d, num:%d, mode:%d\n",
idx, rem, num, dev->mode);
qup_print_status(dev);
timeout = wait_for_completion_timeout(&complete,
msecs_to_jiffies(dev->out_fifo_sz));
if (!timeout) {
uint32_t istatus = readl_relaxed(dev->base +
QUP_I2C_STATUS);
uint32_t qstatus = readl_relaxed(dev->base +
QUP_ERROR_FLAGS);
uint32_t op_flgs = readl_relaxed(dev->base +
QUP_OPERATIONAL);
/*
* Dont wait for 1 sec if i2c sees the bus
* active and controller is not master.
* A slave has pulled line low. Try to recover
*/
if (!(istatus & I2C_STATUS_BUS_ACTIVE) ||
(istatus & I2C_STATUS_BUS_MASTER)) {
timeout =
wait_for_completion_timeout(&complete,
HZ);
if (timeout)
goto timeout_err;
}
qup_i2c_recover_bus_busy(dev);
dev_err(dev->dev,
"Transaction timed out, SL-AD = 0x%x\n",
dev->msg->addr);
dev_err(dev->dev, "I2C Status: %x\n", istatus);
dev_err(dev->dev, "QUP Status: %x\n", qstatus);
dev_err(dev->dev, "OP Flags: %x\n", op_flgs);
writel_relaxed(1, dev->base + QUP_SW_RESET);
/* Make sure that the write has gone through
* before returning from the function
*/
mb();
ret = -ETIMEDOUT;
goto out_err;
}
timeout_err:
if (dev->err) {
if (dev->err > 0 &&
dev->err & QUP_I2C_NACK_FLAG) {
dev_err(dev->dev,
"I2C slave addr:0x%x not connected\n",
dev->msg->addr);
dev->err = ENOTCONN;
} else if (dev->err < 0) {
dev_err(dev->dev,
"QUP data xfer error %d\n", dev->err);
ret = dev->err;
goto out_err;
} else if (dev->err > 0) {
/*
* ISR returns +ve error if error code
* is I2C related, e.g. unexpected start
* So you may call recover-bus-busy when
* this error happens
*/
qup_i2c_recover_bus_busy(dev);
}
ret = -dev->err;
goto out_err;
}
if (dev->msg->flags & I2C_M_RD) {
int i;
uint32_t dval = 0;
for (i = 0; dev->pos < dev->msg->len; i++,
dev->pos++) {
uint32_t rd_status =
readl_relaxed(dev->base
+ QUP_OPERATIONAL);
if (i % 2 == 0) {
if ((rd_status &
QUP_IN_NOT_EMPTY) == 0)
break;
dval = readl_relaxed(dev->base +
QUP_IN_FIFO_BASE);
dev->msg->buf[dev->pos] =
dval & 0xFF;
} else
dev->msg->buf[dev->pos] =
((dval & 0xFF0000) >>
16);
}
dev->cnt -= i;
} else
filled = false; /* refill output FIFO */
dev_dbg(dev->dev, "pos:%d, len:%d, cnt:%d\n",
dev->pos, msgs->len, dev->cnt);
} while (dev->cnt > 0);
if (dev->cnt == 0) {
if (msgs->len == dev->pos) {
rem--;
msgs++;
dev->pos = 0;
}
if (rem) {
err = qup_i2c_poll_clock_ready(dev);
if (err < 0) {
ret = err;
goto out_err;
}
err = qup_update_state(dev, QUP_RESET_STATE);
if (err < 0) {
ret = err;
goto out_err;
}
}
}
/* Wait for I2C bus to be idle */
ret = qup_i2c_poll_writeready(dev, rem);
if (ret) {
dev_err(dev->dev,
"Error waiting for write ready\n");
goto out_err;
}
}
ret = num;
out_err:
disable_irq(dev->err_irq);
if (dev->num_irqs == 3) {
disable_irq(dev->in_irq);
disable_irq(dev->out_irq);
}
dev->complete = NULL;
dev->msg = NULL;
dev->pos = 0;
dev->err = 0;
dev->cnt = 0;
if (dev->pdata->clk_ctl_xfer)
i2c_qup_pm_suspend_clk(dev);
atomic_set(&dev->xfer_progress, 0);
mutex_unlock(&dev->mlock);
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
return ret;
}
enum msm_i2c_dt_entry_status {
DT_REQUIRED,
DT_SUGGESTED,
DT_OPTIONAL,
};
enum msm_i2c_dt_entry_type {
DT_U32,
DT_GPIO,
DT_BOOL,
};
struct msm_i2c_dt_to_pdata_map {
const char *dt_name;
void *ptr_data;
enum msm_i2c_dt_entry_status status;
enum msm_i2c_dt_entry_type type;
int default_val;
};
int __devinit msm_i2c_rsrcs_dt_to_pdata_map(struct platform_device *pdev,
struct msm_i2c_platform_data *pdata, int *gpios)
{
int ret, err = 0;
struct device_node *node = pdev->dev.of_node;
struct msm_i2c_dt_to_pdata_map *itr;
struct msm_i2c_dt_to_pdata_map map[] = {
{"qcom,i2c-bus-freq", &pdata->clk_freq, DT_REQUIRED, DT_U32, 0},
{"cell-index", &pdev->id, DT_REQUIRED, DT_U32, -1},
{"qcom,i2c-src-freq", &pdata->src_clk_rate, DT_SUGGESTED, DT_U32, 0},
{"qcom,master-id", &pdata->master_id, DT_SUGGESTED, DT_U32, 0},
{"qcom,scl-gpio", gpios, DT_OPTIONAL, DT_GPIO, -1},
{"qcom,sda-gpio", gpios + 1, DT_OPTIONAL, DT_GPIO, -1},
{"qcom,clk-ctl-xfer", &pdata->clk_ctl_xfer, DT_OPTIONAL, DT_BOOL, -1},
{"qcom,active-only", &pdata->active_only, DT_OPTIONAL, DT_BOOL, 0},
{NULL, NULL, 0, 0, 0},
};
for (itr = map; itr->dt_name ; ++itr) {
switch (itr->type) {
case DT_GPIO:
ret = of_get_named_gpio(node, itr->dt_name, 0);
if (ret >= 0) {
*((int *) itr->ptr_data) = ret;
ret = 0;
}
break;
case DT_U32:
ret = of_property_read_u32(node, itr->dt_name,
(u32 *) itr->ptr_data);
break;
case DT_BOOL:
*((bool *) itr->ptr_data) =
of_property_read_bool(node, itr->dt_name);
ret = 0;
break;
default:
dev_err(&pdev->dev, "%d is an unknown DT entry type\n",
itr->type);
ret = -EBADE;
}
dev_dbg(&pdev->dev, "DT entry ret:%d name:%s val:%d\n",
ret, itr->dt_name, *((int *)itr->ptr_data));
if (ret) {
*((int *)itr->ptr_data) = itr->default_val;
if (itr->status < DT_OPTIONAL) {
dev_err(&pdev->dev, "Missing '%s' DT entry\n",
itr->dt_name);
/* cont on err to dump all missing entries */
if (itr->status == DT_REQUIRED && !err)
err = ret;
}
}
}
return err;
}
static u32
qup_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
}
static const struct i2c_algorithm qup_i2c_algo = {
.master_xfer = qup_i2c_xfer,
.functionality = qup_i2c_func,
};
static int __devinit
qup_i2c_probe(struct platform_device *pdev)
{
struct qup_i2c_dev *dev;
struct resource *qup_mem, *gsbi_mem, *qup_io, *gsbi_io, *res;
struct resource *in_irq, *out_irq, *err_irq;
struct clk *clk, *pclk;
int ret = 0;
int i;
int dt_gpios[I2C_GPIOS_DT_CNT];
bool use_device_tree = pdev->dev.of_node;
struct msm_i2c_platform_data *pdata;
gsbi_mem = NULL;
dev_dbg(&pdev->dev, "qup_i2c_probe\n");
if (use_device_tree) {
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
ret = msm_i2c_rsrcs_dt_to_pdata_map(pdev, pdata, dt_gpios);
if (ret)
goto get_res_failed;
} else
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "platform data not initialized\n");
return -ENOSYS;
}
qup_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"qup_phys_addr");
if (!qup_mem) {
dev_err(&pdev->dev,
"platform_get_resource_byname(qup_phys_addr) failed\n");
ret = -ENODEV;
goto get_res_failed;
}
/*
* We only have 1 interrupt for new hardware targets and in_irq,
* out_irq will be NULL for those platforms
*/
in_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
"qup_in_intr");
out_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
"qup_out_intr");
err_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
"qup_err_intr");
if (!err_irq) {
dev_err(&pdev->dev, "no error irq resource?\n");
ret = -ENODEV;
goto get_res_failed;
}
qup_io = request_mem_region(qup_mem->start, resource_size(qup_mem),
pdev->name);
if (!qup_io) {
dev_err(&pdev->dev, "QUP region already claimed\n");
ret = -EBUSY;
goto get_res_failed;
}
if (!pdata->use_gsbi_shared_mode) {
gsbi_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"gsbi_qup_i2c_addr");
if (!gsbi_mem) {
dev_dbg(&pdev->dev, "Assume BLSP\n");
/*
* BLSP core does not need protocol programming so this
* resource is not expected
*/
goto blsp_core_init;
}
gsbi_io = request_mem_region(gsbi_mem->start,
resource_size(gsbi_mem),
pdev->name);
if (!gsbi_io) {
dev_err(&pdev->dev, "GSBI region already claimed\n");
ret = -EBUSY;
goto err_res_failed;
}
}
blsp_core_init:
clk = clk_get(&pdev->dev, "core_clk");
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "Could not get core_clk\n");
ret = PTR_ERR(clk);
goto err_clk_get_failed;
}
pclk = clk_get(&pdev->dev, "iface_clk");
if (IS_ERR(pclk)) {
dev_err(&pdev->dev, "Could not get iface_clk\n");
ret = PTR_ERR(pclk);
clk_put(clk);
goto err_clk_get_failed;
}
/* We support frequencies upto FAST Mode(400KHz) */
if (pdata->clk_freq <= 0 ||
pdata->clk_freq > 400000) {
dev_err(&pdev->dev, "clock frequency not supported\n");
ret = -EIO;
goto err_config_failed;
}
dev = kzalloc(sizeof(struct qup_i2c_dev), GFP_KERNEL);
if (!dev) {
ret = -ENOMEM;
goto err_alloc_dev_failed;
}
dev->dev = &pdev->dev;
if (in_irq)
dev->in_irq = in_irq->start;
if (out_irq)
dev->out_irq = out_irq->start;
dev->err_irq = err_irq->start;
if (in_irq && out_irq)
dev->num_irqs = 3;
else
dev->num_irqs = 1;
dev->clk = clk;
dev->pclk = pclk;
dev->base = ioremap(qup_mem->start, resource_size(qup_mem));
if (!dev->base) {
ret = -ENOMEM;
goto err_ioremap_failed;
}
/* Configure GSBI block to use I2C functionality */
if (gsbi_mem) {
dev->gsbi = ioremap(gsbi_mem->start, resource_size(gsbi_mem));
if (!dev->gsbi) {
ret = -ENOMEM;
goto err_gsbi_failed;
}
}
for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
if (use_device_tree && i < I2C_GPIOS_DT_CNT) {
dev->i2c_gpios[i] = dt_gpios[i];
} else {
res = platform_get_resource_byname(pdev, IORESOURCE_IO,
i2c_rsrcs[i]);
dev->i2c_gpios[i] = res ? res->start : -1;
}
}
platform_set_drvdata(pdev, dev);
dev->one_bit_t = (USEC_PER_SEC/pdata->clk_freq) + 1;
dev->pdata = pdata;
dev->clk_ctl = 0;
dev->pos = 0;
ret = i2c_qup_clk_path_init(pdev, dev);
if (ret) {
dev_err(&pdev->dev,
"Failed to init clock path-voting data structs. err:%d", ret);
/* disable i2c_qup_clk_path_xxx() functionality */
dev->pdata->master_id = 0;
}
if (dev->pdata->src_clk_rate <= 0) {
dev_info(&pdev->dev,
"No src_clk_rate specified in platfrom data\n");
dev_info(&pdev->dev, "Using default clock rate %dHz\n",
DEFAULT_CLK_RATE);
dev->pdata->src_clk_rate = DEFAULT_CLK_RATE;
}
ret = clk_set_rate(dev->clk, dev->pdata->src_clk_rate);
if (ret)
dev_info(&pdev->dev, "clk_set_rate(core_clk, %dHz):%d\n",
dev->pdata->src_clk_rate, ret);
clk_prepare_enable(dev->clk);
clk_prepare_enable(dev->pclk);
/*
* If bootloaders leave a pending interrupt on certain GSBI's,
* then we reset the core before registering for interrupts.
*/
writel_relaxed(1, dev->base + QUP_SW_RESET);
if (qup_i2c_poll_state(dev, 0, true) != 0)
goto err_reset_failed;
clk_disable_unprepare(dev->clk);
clk_disable_unprepare(dev->pclk);
/*
* We use num_irqs to also indicate if we got 3 interrupts or just 1.
* If we have just 1, we use err_irq as the general purpose irq
* and handle the changes in ISR accordingly
* Per Hardware guidelines, if we have 3 interrupts, they are always
* edge triggering, and if we have 1, it's always level-triggering
*/
if (dev->num_irqs == 3) {
ret = request_irq(dev->in_irq, qup_i2c_interrupt,
IRQF_TRIGGER_RISING, "qup_in_intr", dev);
if (ret) {
dev_err(&pdev->dev, "request_in_irq failed\n");
goto err_request_irq_failed;
}
/*
* We assume out_irq exists if in_irq does since platform
* configuration either has 3 interrupts assigned to QUP or 1
*/
ret = request_irq(dev->out_irq, qup_i2c_interrupt,
IRQF_TRIGGER_RISING, "qup_out_intr", dev);
if (ret) {
dev_err(&pdev->dev, "request_out_irq failed\n");
free_irq(dev->in_irq, dev);
goto err_request_irq_failed;
}
ret = request_irq(dev->err_irq, qup_i2c_interrupt,
IRQF_TRIGGER_RISING, "qup_err_intr", dev);
if (ret) {
dev_err(&pdev->dev, "request_err_irq failed\n");
free_irq(dev->out_irq, dev);
free_irq(dev->in_irq, dev);
goto err_request_irq_failed;
}
} else {
ret = request_irq(dev->err_irq, qup_i2c_interrupt,
IRQF_TRIGGER_HIGH, "qup_err_intr", dev);
if (ret) {
dev_err(&pdev->dev, "request_err_irq failed\n");
goto err_request_irq_failed;
}
}
disable_irq(dev->err_irq);
if (dev->num_irqs == 3) {
disable_irq(dev->in_irq);
disable_irq(dev->out_irq);
}
i2c_set_adapdata(&dev->adapter, dev);
dev->adapter.algo = &qup_i2c_algo;
strlcpy(dev->adapter.name,
"QUP I2C adapter",
sizeof(dev->adapter.name));
dev->adapter.nr = pdev->id;
dev->adapter.dev.parent = &pdev->dev;
if (pdata->msm_i2c_config_gpio)
pdata->msm_i2c_config_gpio(dev->adapter.nr, 1);
mutex_init(&dev->mlock);
dev->pwr_state = MSM_I2C_PM_SUSPENDED;
atomic_set(&dev->xfer_progress, 0);
/* If the same AHB clock is used on Modem side
* switch it on here itself and don't switch it
* on and off during suspend and resume.
*/
if (dev->pdata->keep_ahb_clk_on)
clk_prepare_enable(dev->pclk);
ret = i2c_add_numbered_adapter(&dev->adapter);
if (ret) {
dev_err(&pdev->dev, "i2c_add_adapter failed\n");
if (dev->num_irqs == 3) {
free_irq(dev->out_irq, dev);
free_irq(dev->in_irq, dev);
}
free_irq(dev->err_irq, dev);
} else {
if (dev->dev->of_node) {
dev->adapter.dev.of_node = pdev->dev.of_node;
of_i2c_register_devices(&dev->adapter);
}
pm_runtime_set_autosuspend_delay(&pdev->dev, MSEC_PER_SEC);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev);
return 0;
}
err_request_irq_failed:
if (dev->gsbi)
iounmap(dev->gsbi);
err_reset_failed:
clk_disable_unprepare(dev->clk);
clk_disable_unprepare(dev->pclk);
i2c_qup_clk_path_teardown(dev);
err_gsbi_failed:
iounmap(dev->base);
err_ioremap_failed:
kfree(dev);
err_alloc_dev_failed:
err_config_failed:
clk_put(clk);
clk_put(pclk);
err_clk_get_failed:
if (gsbi_mem)
release_mem_region(gsbi_mem->start, resource_size(gsbi_mem));
err_res_failed:
release_mem_region(qup_mem->start, resource_size(qup_mem));
get_res_failed:
if (pdev->dev.of_node)
kfree(pdata);
return ret;
}
static void qup_i2c_mem_release(struct platform_device *pdev, const char *name)
{
struct resource *res =
platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
if (res)
release_mem_region(res->start, resource_size(res));
else
dev_dbg(&pdev->dev,
"platform_get_resource_byname(%s) failed\n", name);
}
static int __devexit
qup_i2c_remove(struct platform_device *pdev)
{
struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
/* Grab mutex to ensure ongoing transaction is over */
mutex_lock(&dev->mlock);
dev->pwr_state = MSM_I2C_SYS_SUSPENDING;
mutex_unlock(&dev->mlock);
i2c_qup_pm_suspend(dev);
dev->pwr_state = MSM_I2C_SYS_SUSPENDED;
mutex_destroy(&dev->mlock);
platform_set_drvdata(pdev, NULL);
if (dev->num_irqs == 3) {
free_irq(dev->out_irq, dev);
free_irq(dev->in_irq, dev);
}
free_irq(dev->err_irq, dev);
i2c_del_adapter(&dev->adapter);
if (!dev->pdata->keep_ahb_clk_on) {
clk_put(dev->pclk);
}
clk_put(dev->clk);
if (dev->pdata->active_only)
i2c_qup_clk_path_unvote(dev);
i2c_qup_clk_path_teardown(dev);
if (dev->gsbi)
iounmap(dev->gsbi);
iounmap(dev->base);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
if (!(dev->pdata->use_gsbi_shared_mode))
qup_i2c_mem_release(pdev, "gsbi_qup_i2c_addr");
qup_i2c_mem_release(pdev, "qup_phys_addr");
if (dev->dev->of_node)
kfree(dev->pdata);
kfree(dev);
return 0;
}
#ifdef CONFIG_PM
static int i2c_qup_pm_suspend_runtime(struct device *device)
{
struct platform_device *pdev = to_platform_device(device);
struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
dev_dbg(device, "pm_runtime: suspending...\n");
i2c_qup_pm_suspend(dev);
return 0;
}
static int i2c_qup_pm_resume_runtime(struct device *device)
{
struct platform_device *pdev = to_platform_device(device);
struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
dev_dbg(device, "pm_runtime: resuming...\n");
i2c_qup_pm_resume(dev);
return 0;
}
static int i2c_qup_pm_suspend_sys(struct device *device)
{
struct platform_device *pdev = to_platform_device(device);
struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
/* Acquire mutex to ensure current transaction is over */
mutex_lock(&dev->mlock);
dev->pwr_state = MSM_I2C_SYS_SUSPENDING;
mutex_unlock(&dev->mlock);
if (!pm_runtime_enabled(device) || !pm_runtime_suspended(device)) {
dev_dbg(device, "system suspend\n");
i2c_qup_pm_suspend(dev);
/*
* set the device's runtime PM status to 'suspended'
*/
pm_runtime_disable(device);
pm_runtime_set_suspended(device);
pm_runtime_enable(device);
}
dev->pwr_state = MSM_I2C_SYS_SUSPENDED;
return 0;
}
static int i2c_qup_pm_resume_sys(struct device *device)
{
struct platform_device *pdev = to_platform_device(device);
struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
/*
* Rely on runtime-PM to call resume in case it is enabled
* Even if it's not enabled, rely on 1st client transaction to do
* clock ON and gpio configuration
*/
dev_dbg(device, "system resume\n");
dev->pwr_state = MSM_I2C_PM_SUSPENDED;
return 0;
}
#endif /* CONFIG_PM */
static const struct dev_pm_ops i2c_qup_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(
i2c_qup_pm_suspend_sys,
i2c_qup_pm_resume_sys
)
SET_RUNTIME_PM_OPS(
i2c_qup_pm_suspend_runtime,
i2c_qup_pm_resume_runtime,
NULL
)
};
static struct of_device_id i2c_qup_dt_match[] = {
{
.compatible = "qcom,i2c-qup",
},
{}
};
static struct platform_driver qup_i2c_driver = {
.probe = qup_i2c_probe,
.remove = __devexit_p(qup_i2c_remove),
.driver = {
.name = "qup_i2c",
.owner = THIS_MODULE,
.pm = &i2c_qup_dev_pm_ops,
.of_match_table = i2c_qup_dt_match,
},
};
/* QUP may be needed to bring up other drivers */
int __init qup_i2c_init_driver(void)
{
static bool initialized;
if (initialized)
return 0;
else
initialized = true;
return platform_driver_register(&qup_i2c_driver);
}
EXPORT_SYMBOL(qup_i2c_init_driver);
arch_initcall(qup_i2c_init_driver);
static void __exit qup_i2c_exit_driver(void)
{
platform_driver_unregister(&qup_i2c_driver);
}
module_exit(qup_i2c_exit_driver);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
使用中注意设备树中配成相应的
static struct of_device_id i2c_qup_dt_match[] = {
{
.compatible = "qcom,i2c-qup",
},
{}
};
1
2
3
4
5
6
第一:
arch_initcall(qup_i2c_init_driver);
第二:
platform_driver_register(&qup_i2c_driver);
static struct platform_driver qup_i2c_driver = {
.probe = qup_i2c_probe,
.remove = __devexit_p(qup_i2c_remove),
.driver = {
.name = "qup_i2c",
.owner = THIS_MODULE,
.pm = &i2c_qup_dev_pm_ops,
.of_match_table = i2c_qup_dt_match,
},
};
1
2
3
4
5
6
7
8
9
10
在probe中,先提取platform_device 的设备信息填充i2c平台数据(struct msm_i2c_platform_data) *pdata;
struct device_node *node = pdev->dev.of_node;
compatible = “qcom,i2c-qup”; 用于与驱动match的
reg-names = “qup_phys_addr”;
reg = <0xf9923000 0x1000>;
qup_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
“qup_phys_addr”);
这个用于一块的IORESOURCE_MEM (resource)的数据结构(struct resource *qup_mem)
interrupt-names = “qup_err_intr”;
interrupts = <0 95 0>;
err_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
“qup_err_intr”);
用于读取IORESOURCE_IRQ资源,
ret = of_get_named_gpio(node, itr->dt_name, 0);
static inline int of_get_named_gpio(struct device_node *np,const char *propname, int index)
{
return of_get_named_gpio_flags(np, propname, index, NULL);*返回的是GPIO的有效值,使用Linux通用GPIO的API,或者是一个错误
*值在错误条件。如果“标记”不为空,则函数也填充
对于GPIO标志*。
}
ret = of_property_read_u32(node, itr->dt_name,(u32 *) itr->ptr_data);
static inline int of_property_read_u32(const struct device_node *np,const char *propname, u32 *out_value)
{
return of_property_read_u32_array(np, propname, out_value, 1);*在设备节点中搜索一个属性,并从中读取32位值到out_value(S)
*。成功执行将返回0
}
((bool ) itr->ptr_data) =of_property_read_bool(node, itr->dt_name);等
还有将
qup_io = request_mem_region(qup_mem->start,resource_size(qup_mem),pdev->name);
1
request_mem_region 是申请 I/O 内存用的 . 申请了之后 , 还需要使用 ioremap 或者 ioremap_nocache 函数来映射 .对于 request_region, 三个参数 start,n,name 表示你想使用从 start 开始的 size 为 n 的 I/O port 资源 ,name 自然就是你的名字。
这样i2c的一个接口设备驱动就完成了,基础就有了。
重要的平台驱动注册。platform_driver_register
platform_driver_register()的注册过程:
1 platform_driver_register(&qup_i2c_driver)
2 driver_register(&drv->driver)
3 bus_add_driver(drv)
4 driver_attach(drv)
5 bus_for_each_dev(drv->bus, NULL, drv,__driver_attach)
6 __driver_attach(struct device * dev, void * data)
7 driver_probe_device(drv, dev)
8 really_probe(dev, drv)
在really_probe()中:为设备指派管理该设备的驱动:dev->driver = drv, 调用probe()函数初始化设备:drv->probe(dev)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
这是完成平台驱动的注册和设备的probe。
sys/bus/platfrom的模型
//platform设备声明
struct device platform_bus = {
.bus_id = "platform",
};
EXPORT_SYMBOL_GPL(platform_bus);
//platform总线设备声明
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.suspend = platform_suspend,
.suspend_late = platform_suspend_late,
.resume_early = platform_resume_early,
.resume = platform_resume,
};
EXPORT_SYMBOL_GPL(platform_bus_type);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
这里定义了两个数据结构分别是
/sys/devices/platfrom/
/sys/bus/platfrom/
int __init platform_bus_init(void)
{
int error;
error = device_register(&platform_bus);//注册了"platform"的设备
if (error)
return error;
error = bus_register(&platform_bus_type);//注册了叫"platform"的总线
if (error)
device_unregister(&platform_bus);
return error;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
有了总线就可以挂设备了。
//常用的platform_device_register,内部调用了platform_device_add,将设备挂在了platform总线上
/**
* platform_device_register - add a platform-level device
* @pdev: platform device we're adding
*/
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
return platform_device_add(pdev);
}
EXPORT_SYMBOL_GPL(platform_device_register);
//这里在platform总线上挂设备
int platform_device_add(struct platform_device *pdev)
{
int i, ret = 0;
if (!pdev)
return -EINVAL;
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;//父设备设置为platform_bus
pdev->dev.bus = &platform_bus_type;//设置挂在platform总线上
if (pdev->id != -1)
snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
pdev->id);
else
strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
for (i = 0; i < pdev->num_resources; i++) {
struct resource *p, *r = &pdev->resource[i];
if (r->name == NULL)
r->name = pdev->dev.bus_id;
p = r->parent;
if (!p) {
if (r->flags & IORESOURCE_MEM)
p = &iomem_resource;
else if (r->flags & IORESOURCE_IO)
p = &ioport_resource;
}
if (p && insert_resource(p, r)) {
printk(KERN_ERR
"%s: failed to claim resource %d\n",
pdev->dev.bus_id, i);
ret = -EBUSY;
goto failed;
}
}
pr_debug("Registering platform device '%s'. Parent at %s\n",
pdev->dev.bus_id, pdev->dev.parent->bus_id);
ret = device_add(&pdev->dev);
if (ret == 0)
return ret;
failed:
while (--i >= 0)
if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO))
release_resource(&pdev->resource[i]);
return ret;
}
EXPORT_SYMBOL_GPL(platform_device_add);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
blsp_core_init(blsp的初始化)
if (!pdata->use_gsbi_shared_mode)
判断是否使用gsbi
gsbi是物理上实际存在的部件,它可以模拟成i2c、gpio、spi、uart、sdio等,此i2c即是gsbi模拟的。这里顺便提下i2c adapter和i2c总线,两者都是物理上必须存在的,哪怕是其他部件模拟的,例如GSBI模拟I2C,那么GSBI这个部件是实际存在的。GSBI的走线会与所有i2c设备互连,GSBI的接口即是i2c adapter,与其他i2c设备互连的走线即是i2c总线。如果GSBI模拟成uart,那么与uart的rx/tx pin连接的走线即是uart串口线。这是高通平台的设计,换作其他平台,也一定会有一个i2c adapter或者说可以模拟成i2c adapter的物理部件存在。猜测i2c adapter位于片上系统中,类似I/O接口的东西,没有固件,驱动它的代码即是各平台相关的i2c adapter driver。GSBI的地址以及模拟成的qup i2c/uart的地址都是编址好的,在arch/arm/mach-msm/devices-msm8x60.c最开头可以看到这些物理地址。我们知道ARM是统一编址的,在代码中要用ioremap把它映射到虚拟内存,这样就可以访问了。
gsbi_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"gsbi_qup_i2c_addr");
if (!gsbi_mem) {
dev_dbg(&pdev->dev, "Assume BLSP\n");
/*
* BLSP core does not need protocol programming so this
* resource is not expected
*/
goto blsp_core_init;
}
1
2
3
4
5
6
7
8
9
10
也就是不是Gsbi时goto blsp_core_init;
获取clk;
获取pclk;
实例化一个dev(struct qup_i2c_dev)
dev->dev = &pdev->dev;
dev->err_irq = err_irq->start;
dev->clk = clk;
dev->pclk = pclk;
dev->base = ioremap(qup_mem->start, resource_size(qup_mem));//映射到虚拟地址
dev->i2c_gpios[i] = dt_gpios[i];//获取sda scl;
platform_set_drvdata(pdev, dev);
pdev是我们在probe函数中定义的局部变量,如果我想在其他地方使用它怎么办呢? 这就需要把它保存起来。内核提供了这个方法,使用函数platform_set_drvdata()可以将pdev保存成平台总线设备的私有数据。以后再要使用它时只需调用platform_get_drvdata()就可以了。
pdata = pdev->dev.platform_data;dev->pdata = pdata;
ret = i2c_qup_clk_path_init(pdev, dev);
ret = request_irq(dev->err_irq, qup_i2c_interrupt,IRQF_TRIGGER_HIGH, “qup_err_intr”, dev);
disable_irq(dev->err_irq);
i2c_set_adapdata(&dev->adapter, dev);
dev->adapter.algo = &qup_i2c_algo;//等等
ret = i2c_add_numbered_adapter(&dev->adapter); //i2c-core.c添加适配器是core层做的事。主要i2c_register_adapter(adap);
关于i2c_register_adapter(adap)详解一下;
适配器的存在就是一个设备的存在,按照希望的过程是在/sys/bus/下构建一个i2c的驱动模型框架。设备模型是希望一个功能可以通过某个设备和某个设备驱动probe成功,让驱动完成与应用层的交互。devices这个数据结构就是一个抽象(可以说是个类的概念)
它就有着device_register(struct device *),它与sysfs的体现就是构建了devices的管理路径.
INIT_LIST_HEAD(&adap->userspace_clients);// 初始化一个clients的双向链表;
dev_set_name(&adap->dev, “i2c-%d”, adap->nr);//设置一个具体的适配器设备文件名。
adap->dev.bus = &i2c_bus_type;
struct bus_type i2c_bus_type = {
.name = "i2c",// /sys/bus/i2c 设备模型的框
.match = i2c_device_match,//这个设备match函数
.probe = i2c_device_probe,//这个设备的probe函数
.remove = i2c_device_remove,//驱动与设备的移除
.shutdown = i2c_device_shutdown,//设备关闭
.pm = &i2c_device_pm_ops,//电源管理
};
1
2
3
4
5
6
7
8
adap->dev.type = &i2c_adapter_type;//这个设备(i2c适配器)的sysfs的接口应用
static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
static DEVICE_ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device);
static struct attribute *i2c_adapter_attrs[] = {
&dev_attr_name.attr,
&dev_attr_new_device.attr,
&dev_attr_delete_device.attr,
NULL
};
static struct attribute_group i2c_adapter_attr_group = {
.attrs = i2c_adapter_attrs,
};
static const struct attribute_group *i2c_adapter_attr_groups[] = {
&i2c_adapter_attr_group,
NULL
};
struct device_type i2c_adapter_type = {
.groups = i2c_adapter_attr_groups,
.release = i2c_adapter_dev_release,
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
res = device_register(&adap->dev); //设备的注册
(难点)
/* 相应的代码位于i2c-core.c:create pre-declared device nodes */
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);.......
struct i2c_devinfo {
struct list_head list;
int busnum;
struct i2c_board_info board_info;
};
struct i2c_board_info {
char type[I2C_NAME_SIZE];
unsigned short flags;
unsigned short addr;
void *platform_data;
struct dev_archdata *archdata;
struct device_node *of_node;
int irq;
};
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
struct i2c_devinfo *devinfo;
down_read(&__i2c_board_lock);
list_for_each_entry(devinfo, &__i2c_board_list, list) {
if (devinfo->busnum == adapter->nr
&& !i2c_new_device(adapter,
&devinfo->board_info))
dev_err(&adapter->dev,
"Can't create device at 0x%02x\n",
devinfo->board_info.addr);
}
up_read(&__i2c_board_lock);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
在i2c_scan_static_board_info()函数中遍历I2C设备链表__i2c_board_list,设备的总线号和adapter(nr)的总线号相等,
回顾下在设备树中获取总线号的方法,当然也是配置的方法:
{“cell-index”, &pdev->id, DT_REQUIRED, DT_U32, -1},
adapter->nr = pdev->id;
dev_set_name(&adap->dev, “i2c-%d”, adap->nr);
至于I2C设备链表的创建和填充是在
int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent)
{
struct device_node *child;
int rc = 0;
root = root ? of_node_get(root) : of_find_node_by_path("/");
if (!root)
return -EINVAL;
for_each_child_of_node(root, child) { //遍历设备树
rc = of_platform_bus_create(child, matches, lookup, parent, true);
if (rc)
break;
}
of_node_put(root);
return rc;
}
*创建一个platform_device为device_node
*递归为所有子节点创建设备。
static int of_platform_bus_create(struct device_node *bus,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent, bool strict)
{
const struct of_dev_auxdata *auxdata;
struct device_node *child;
struct platform_device *dev;
const char *bus_id = NULL;
void *platform_data = NULL;
int rc = 0;
/* Make sure it has a compatible property */
if (strict && (!of_get_property(bus, "compatible", NULL))) {
pr_debug("%s() - skipping %s, no compatible prop\n",
__func__, bus->full_name);
return 0;
}
auxdata = of_dev_lookup(lookup, bus);
if (auxdata) {
bus_id = auxdata->name;
platform_data = auxdata->platform_data;
}
if (of_device_is_compatible(bus, "arm,primecell")) {
of_amba_device_create(bus, bus_id, platform_data, parent);
return 0;
}
dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
if (!dev || !of_match_node(matches, bus))
return 0;
for_each_child_of_node(bus, child) {
pr_debug(" create child: %s\n", child->full_name);
rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
if (rc) {
of_node_put(child);
break;
}
}
return rc;
}
在适配器probe时如果是设备树的方式注册。
if (dev->dev->of_node) {
dev->adapter.dev.of_node = pdev->dev.of_node;
of_i2c_register_devices(&dev->adapter);
}
void of_i2c_register_devices(struct i2c_adapter *adap)
{
void *result;
struct device_node *node;
/* Only register child devices if the adapter has a node pointer set */
if (!adap->dev.of_node)
return;
dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
for_each_child_of_node(adap->dev.of_node, node) {
struct i2c_board_info info = {};
struct dev_archdata dev_ad = {};
const __be32 *addr;
int len;
dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name);
if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
node->full_name);
continue;
}
addr = of_get_property(node, "reg", &len);
if (!addr || (len < sizeof(int))) {
dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
node->full_name);
continue;
}
info.addr = be32_to_cpup(addr);
if (info.addr > (1 << 10) - 1) {
dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
info.addr, node->full_name);
continue;
}
info.irq = irq_of_parse_and_map(node, 0);
info.of_node = of_node_get(node);
info.archdata = &dev_ad;
request_module("%s%s", I2C_MODULE_PREFIX, info.type);
result = i2c_new_device(adap, &info);
if (result == NULL) {
dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
node->full_name);
of_node_put(node);
irq_dispose_mapping(info.irq);
continue;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
如果使用board_info 的方式则是遍历devices链表,当设备的busnum等于这个i2c的总线号就确认这个设备是挂在这i2c的总线上的。
最后都是使用函数i2c_new_device()创建该设备。
struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
struct i2c_client *client;
int status;
client = kzalloc(sizeof *client, GFP_KERNEL);
if (!client)
return NULL;
client->adapter = adap;
client->dev.platform_data = info->platform_data;
if (info->archdata)
client->dev.archdata = *info->archdata;
client->flags = info->flags;
client->addr = info->addr;
client->irq = info->irq;
strlcpy(client->name, info->type, sizeof(client->name));
/* Check for address validity */
status = i2c_check_client_addr_validity(client);
if (status) {
dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n",
client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);
goto out_err_silent;
}
/* Check for address business */
status = i2c_check_addr_busy(adap, client->addr);
if (status)
goto out_err;
client->dev.parent = &client->adapter->dev;
client->dev.bus = &i2c_bus_type;
client->dev.type = &i2c_client_type;
client->dev.of_node = info->of_node;
/* For 10-bit clients, add an arbitrary offset to avoid collisions */
dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
client->addr | ((client->flags & I2C_CLIENT_TEN)
? 0xa000 : 0));
status = device_register(&client->dev);
if (status)
goto out_err;
dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",
client->name, dev_name(&client->dev));
return client;
out_err:
dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
"(%d)\n", client->name, client->addr, status);
out_err_silent:
kfree(client);
return NULL;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
通过struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);
传入的适配器和i2c_board_info构建成返回一个i2c_client,(如果返回NULL 一般就是地址的有误或冲突)
client->dev.parent = &client->adapter->dev;//将一个设备的父容器dev设置为其适配器的设备容器
client->dev.bus = &i2c_bus_type;//设备总线描述(在bus/i2c/{下的设备}devices/)
client->dev.type = &i2c_client_type;//设备类型描述(att『属性』,uevent,release等)
client->dev.of_node = info->of_node;//设备树的节点,类似pdate,
dev_set_name(&client->dev, “%d-%04x”, i2c_adapter_id(adap),
client->addr | ((client->flags & I2C_CLIENT_TEN)? 0xa000 : 0));//设备的命名 如:
/sys/bus/i2c/devices/1-0038/
通过设备容器的嵌套:1-0038 -> ../../../devices/f9923000.i2c/i2c-1/1-0038
也就是实际上sys/bus/i2c/devices/* 是/sys/devices/的链接文件。
status = device_register(&client->dev);//完成上面的设置。
这就完成了一个client。而这个client构建的时候也是具有了适配器,算法,等。
注意:
*bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
新的适配器加入内核时调用函数 bus_for_each_drv时调用的函数。
完成当一个新的适配器加入内核时,会在总线类型为i2c_bus_type的驱动中找与之匹配的,
并将驱动支持的设备插入新加入的这个适配器。
函数bus_for_each_dev() 和 bus_for_each_drv()分别用于遍历bus上devices和drivers链表中的所有元素。*
这部分在已经废弃了,不在建议使用
/ *通知BUS的机制,一个新的公共bus已经出现,它即将
*删除。你应该避免使用这个,不久的将来它将被删除
* /
int (attach_adapter)(struct i2c_adapter ) __deprecated;
int (detach_adapter)(struct i2c_adapter ) __deprecated;
struct i2c_client {
unsigned short flags; /* div., see below */
unsigned short addr; /* chip address - NOTE: 7bit */
/* addresses are stored in the */
/* _LOWER_ 7 bits */
char name[I2C_NAME_SIZE];
struct i2c_adapter *adapter; /* the adapter we sit on */
struct i2c_driver *driver; /* and our access routines */
struct device dev; /* the device structure */
int irq; /* irq issued by device */
struct list_head detected;
};
struct i2c_driver {
unsigned int class;
/* Notifies the driver that a new bus has appeared or is about to be
* removed. You should avoid using this, it will be removed in a
* near future.
*/
int (*attach_adapter)(struct i2c_adapter *) __deprecated;
int (*detach_adapter)(struct i2c_adapter *) __deprecated;
/* Standard driver model interfaces */
int (*probe)(struct i2c_client *, const struct i2c_device_id *);
int (*remove)(struct i2c_client *);
/* driver model interfaces that don't relate to enumeration */
void (*shutdown)(struct i2c_client *);
int (*suspend)(struct i2c_client *, pm_message_t mesg);
int (*resume)(struct i2c_client *);
/* Alert callback, for example for the SMBus alert protocol.
* The format and meaning of the data value depends on the protocol.
* For the SMBus alert protocol, there is a single bit of data passed
* as the alert response's low bit ("event flag").
*/
void (*alert)(struct i2c_client *, unsigned int data);
/* a ioctl like command that can be used to perform specific functions
* with the device.
*/
int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
struct device_driver driver;
const struct i2c_device_id *id_table;
/* Device detection callback for automatic device creation */
int (*detect)(struct i2c_client *, struct i2c_board_info *);
const unsigned short *address_list;
struct list_head clients;
};
struct i2c_adapter {
struct module *owner;
unsigned int class; /* classes to allow probing for */
const struct i2c_algorithm *algo; /* the algorithm to access the bus */
void *algo_data;
/* data fields that are valid for all devices */
struct rt_mutex bus_lock;
int timeout; /* in jiffies */
int retries;
struct device dev; /* the adapter device */
int nr;
char name[48];
struct completion dev_released;
struct mutex userspace_clients_lock;
struct list_head userspace_clients;
};
struct i2c_device_id {
char name[I2C_NAME_SIZE]; //它由于对比具体的client的 name于 设备的驱动probe
kernel_ulong_t driver_data /* Data private to the driver */
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
一、关于client与设备驱动的匹配
到内核,这些设备client的name在该驱动的id_table中。
老的内核还是通过函数driver->detect便是填充结构体i2c_board_info,用i2c_board_info去初始化
client,驱动id_table中的name就是i2c_board_info->type带入client的。
该驱动与设备就是根据这个name相匹配的,匹配后调用函数probe执行一些初始化或是设备探测。
当然该驱动也是可以不携带地址信息的,而是注册后与内核中已存在的client匹配执行probe()。
“legacy”driver是不携带地址信息的,它的主要任务是调用函数driver->detach_adapter为新加入
的适配器,或是与之匹配的适配器创建一个可依附的设备节点,或者是做其他初始化工作。
新的内核就通过设备树的方式,将一个适配器和它附属的设备顺序的完成clinet的创建。
驱动实际只需要要匹配设备name就可以probe,和使用设备依赖的适配器的算法和设备数据。
编写一个设备驱动就简单的很多。
如:
module_init(goodix_ts_init); //调用等级为7.
static struct i2c_driver goodix_ts_driver = {
.probe = goodix_ts_probe,
.remove = goodix_ts_remove,
.id_table = goodix_ts_id, //I2C设备支持的驱动程序列表 /sys/bus/i2c/drivers/XXXX
.driver = {
.name = GTP_I2C_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = goodix_match_table,
#endif
#if !defined(CONFIG_FB) && defined(CONFIG_PM)
.pm = >p_pm_ops,
#endif
},
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
定义一个i2c_driver的数据结构;
static const struct of_device_id goodix_match_table[] = {
{.compatible = "goodix,gt915l",},
{ },
};
1
2
3
4
of_device_id为了实现于client的probe。(client->name)///sys/bus/i2c/devices/1-005d/name
驱动可以驱动多个设备,但是设备被一个驱动服务。
ret = i2c_add_driver(&goodix_ts_driver);//调用一个add函数,它具体完成i2c设备的内核注册。
#define i2c_add_driver(driver) \
i2c_register_driver(THIS_MODULE, driver)//他是core层代码。
1
2
driver->driver.owner = owner; //THIS_MODULE
driver->driver.bus = &i2c_bus_type; //sys/bus/i2c/driver/XXXX
res = driver_register(&driver->driver); //类似device_register();
INIT_LIST_HEAD(&driver->clients); //初始化client的链表头。
i2c_for_each_dev(driver, __process_new_driver); //find已经存在的适配器 //新的内核已经废弃。
static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
client :传递的适配器。
id :传递驱动(name ,data)。
probe成功后只需要保存这个client的数据结构,就可以操作具体的设备了。
————————————————
版权声明:本文为CSDN博主「lsn946803746」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lsn946803746/article/details/52515225