基于设备树的TQ2440触摸屏驱动移植

2023-11-01 27浏览
百检网是一家专业的第三方检测平台,汇聚众多拥有权威资质的第三方检测机构为你提供一站式的检测服务,做检测就上百检网。百检网让检测从此检测,一份报告全国通用,专业值得信赖。

平台

开发板:tq2440

内核:Linux-4.9

u-boot:u-boot-2015.04

概述

之前移植了LCD驱动,下面继续移植触摸屏驱动,然后将tslib也移植上去。

正文

一、移植触摸屏驱动

为了简单起见我们对TQ2440自带的触摸屏驱动进行改写,改成设备树的形式。

1、设备树

触摸屏使用了两个中断,如下:

这两个中断是子中断,隶属于主中断INT_ADC:

关于寄存器,参考芯片手册的第16章,知道了上面的信息,我们就可以得到如下的设备树节点(可以参考博文基于设备树的TQ2440的中断(1)):

tq2440ts@5800000 {

compatible = "tq2440,ts";

reg =

reg-names = "adc_ts_physical";

interrupts =

interrupt-names = "int_ts", "int_adc_s";

clocks =

clock-names = "adc";

};

2、驱动

对应的触摸屏驱动是drivers/input/touchscreen/tq2440_ts.c

这部分我已经上传到github上面了,可以使用下面的命令下载:

git clone git@github.com:pengdonglin137/linux-4.9.git -b tq2440_dt

代码如下:

1 /*************************************

2

3 NAME:tq2440_ts.c

4 COPYRIGHT:www.embedsky.net

5

6 *************************************/

7 #include

8 #include

9 #include

10 #include

11 #include

12 #include

13 #include

14 #include

15 #include

16 #include

17 #include

18 #include

19 #include

20 #include

21 #include

22

23 #include

24 #include

25

26 /* For ts.dev.id.version */

27 #define S3C2410TSVERSION 0x0101

28

29 #define WAIT4INT(x) (((x)<<8) |

30 S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN |

31 S3C2410_ADCTSC_XY_PST(3))

32

33 #define AUTOPST (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN |

34 S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0))

35

36 static char *tq2440ts_name = "TQ2440 TouchScreen";

37

38 static struct input_dev *idev;

39 static long xp;

40 static long yp;

41 static int count;

42

43 static void __iomem *base_addr;

44

45 static void touch_timer_fire(unsigned long data)

46 {

47 u32 data0;

48 u32 data1;

49 int updown;

50

51 data0 = readl(base_addr+S3C2410_ADCDAT0);

52 data1 = readl(base_addr+S3C2410_ADCDAT1);

53

54 updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));

55

56 if (updown) {

57 if (count != 0) {

58 long tmp;

59

60 tmp = xp;

61 xp = yp;

62 yp = tmp;

63

64 xp >>= 2;

65 yp >>= 2;

66

67 input_report_abs(idev, ABS_X, xp);

68 input_report_abs(idev, ABS_Y, yp);

69

70 input_report_key(idev, BTN_TOUCH, 1);

71 input_report_abs(idev, ABS_PRESSURE, 1);

72 input_sync(idev);

73 }

74

75 xp = 0;

76 yp = 0;

77 count = 0;

78

79 writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);

80 writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);

81 } else {

82 count = 0;

83

84 input_report_key(idev, BTN_TOUCH, 0);

85 input_report_abs(idev, ABS_PRESSURE, 0);

86 input_sync(idev);

87

88 writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);

89 }

90 }

91

92 static struct timer_list touch_timer =

93 TIMER_INITIALIZER(touch_timer_fire, 0, 0);

94

95 static irqreturn_t stylus_updown(int irq, void *dev_id)

96 {

97 u32 data0;

98 u32 data1;

99 int updown;

100

101 data0 = readl(base_addr+S3C2410_ADCDAT0);

102 data1 = readl(base_addr+S3C2410_ADCDAT1);

103

104 updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));

105

106 if (updown)

107 touch_timer_fire(0);

108

109 return IRQ_HANDLED;

110 }

111

112 static irqreturn_t stylus_action(int irq, void *dev_id)

113 {

114 u32 data0;

115 u32 data1;

116

117 data0 = readl(base_addr+S3C2410_ADCDAT0);

118 data1 = readl(base_addr+S3C2410_ADCDAT1);

119

120 xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;

121 yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;

122 count++;

123

124 if (count < (1<<2)) {

125 writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);

126 writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);

127 } else {

128 mod_timer(&touch_timer, jiffies+1);

129 writel(WAIT4INT(1), base_addr+S3C2410_ADCTSC);

130 }

131

132 return IRQ_HANDLED;

133 }

134

135 static int tq2440ts_probe(struct platform_device *pdev)

136 {

137 struct device *dev = &pdev->dev;

138 struct device_node *node = dev->of_node;

139 struct clk *adc_clock;

140 struct resource *tsmem, *irq;

141 struct input_dev *input_dev;

142 int ret;

143

144 if (!node) {

145 dev_dbg(dev, "of_node is NULLn");

146 return -EINVAL;

147 }

148

149 adc_clock = devm_clk_get(dev, "adc");

150 dev_dbg(dev, "adc_clock: %pn", adc_clock);

151 if (IS_ERR(adc_clock)) {

152 dev_err(dev, "cannot get clockn");

153 return -ENOENT;

154 }

155 clk_prepare(adc_clock);

156 clk_enable(adc_clock);

157

158 dev_dbg(dev, "get memn");

159 tsmem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "adc_ts_physical");

160 if (!tsmem) {

161 dev_dbg(dev, "get mem resource failed.n");

162 ret = -EINVAL;

163 goto err;

164 }

165

166 base_addr = devm_ioremap_resource(dev, tsmem);

167 if (IS_ERR(base_addr)) {

168 dev_dbg(dev, "ioremap failed.n");

169 ret = PTR_ERR(base_addr);

170 goto err;

171 }

172

173 writel(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF),base_addr+S3C2410_ADCCON);

174 writel(0xffff, base_addr+S3C2410_ADCDLY);

175 writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);

176

177 input_dev = devm_input_allocate_device(dev);

178 if (!input_dev) {

179 dev_dbg(dev, "ioremap failed.n");

180 ret = -ENOMEM;

181 goto err;

182 }

183

184 idev = input_dev;

185 idev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);

186

187

188 __set_bit(EV_SYN, idev->evbit);

189 __set_bit(EV_KEY, idev->evbit);

190 __set_bit(EV_ABS, idev->evbit);

191 __set_bit(BTN_TOUCH, idev->keybit);

192

193 input_set_abs_params(idev, ABS_X, 0, 0x3FF, 0, 0);

194 input_set_abs_params(idev, ABS_Y, 0, 0x3FF, 0, 0);

195 input_set_abs_params(idev, ABS_PRESSURE, 0, 1, 0, 0);

196

197 idev->name = tq2440ts_name;

198 idev->id.bustype = BUS_RS232;

199 idev->id.vendor = 0xDEAD;

200 idev->id.product = 0xBEEF;

201 idev->id.version = S3C2410TSVERSION;

202

203 irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "int_ts");

204 if (!irq) {

205 dev_err(dev, "get irq resource int_ts failed.n");

206 ret = -EINVAL;

207 goto err;

208 }

209 ret = devm_request_irq(dev, irq->start, stylus_updown, IRQF_ONESHOT, "int_ts", NULL);

210 if (ret < 0){

211 dev_err(dev, "request irq tsirq %d failed.n", irq->start);

百检网秉承“客户至上,服务为先,精诚合作,以人为本”的经营理念,始终站在用户的角度解决问题,为客户提供“一站购物式”的新奇检测体验,打开网站,像挑选商品一样简单,方便。打破行业信息壁垒,建构消费和检测机构之间高效的沟通平台