1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * gyroscope driver for iam20680
4 *
5 * Copyright (c) 2021 Rockchip Electronics Co., Ltd.
6 *
7 * Author: sxj <sxj@rock-chips.com>
8 *
9 */
10 #include <linux/interrupt.h>
11 #include <linux/i2c.h>
12 #include <linux/slab.h>
13 #include <linux/irq.h>
14 #include <linux/miscdevice.h>
15 #include <linux/gpio.h>
16 #include <linux/uaccess.h>
17 #include <linux/atomic.h>
18 #include <linux/delay.h>
19 #include <linux/input.h>
20 #include <linux/workqueue.h>
21 #include <linux/freezer.h>
22 #include <linux/of_gpio.h>
23 #ifdef CONFIG_HAS_EARLYSUSPEND
24 #include <linux/earlysuspend.h>
25 #endif
26 #include <linux/sensor-dev.h>
27 #include <linux/iam20680.h>
28
sensor_active(struct i2c_client * client,int enable,int rate)29 static int sensor_active(struct i2c_client *client, int enable, int rate)
30 {
31 struct sensor_private_data *sensor =
32 (struct sensor_private_data *) i2c_get_clientdata(client);
33 int result = 0;
34 int status = 0;
35 u8 pwrm1 = 0;
36
37 sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg);
38 pwrm1 = sensor_read_reg(client, IAM20680_PWR_MGMT_1);
39
40 if (!enable) {
41 status = BIT_GYRO_STBY;
42 sensor->ops->ctrl_data |= status;
43 if ((sensor->ops->ctrl_data & BIT_ACCEL_STBY) == BIT_ACCEL_STBY)
44 pwrm1 |= IAM20680_PWRM1_SLEEP;
45 } else {
46 status = ~BIT_GYRO_STBY;
47 sensor->ops->ctrl_data &= status;
48 pwrm1 &= ~IAM20680_PWRM1_SLEEP;
49 }
50
51 result = sensor_write_reg(client, sensor->ops->ctrl_reg, sensor->ops->ctrl_data);
52 if (result) {
53 dev_err(&client->dev, "%s:fail to active sensor\n", __func__);
54 return -1;
55 }
56 msleep(20);
57
58 result = sensor_write_reg(client, IAM20680_PWR_MGMT_1, pwrm1);
59 if (result) {
60 dev_err(&client->dev, "%s:fail to set pwrm1\n", __func__);
61 return -1;
62 }
63 msleep(50);
64
65 return result;
66 }
67
sensor_init(struct i2c_client * client)68 static int sensor_init(struct i2c_client *client)
69 {
70 int ret;
71 struct sensor_private_data *sensor =
72 (struct sensor_private_data *) i2c_get_clientdata(client);
73
74 /* init on iam20680_acc.c */
75 ret = sensor->ops->active(client, 0, sensor->pdata->poll_delay_ms);
76 if (ret) {
77 dev_err(&client->dev, "%s:line=%d,error\n", __func__, __LINE__);
78 return ret;
79 }
80
81 return ret;
82 }
83
gyro_report_value(struct i2c_client * client,struct sensor_axis * axis)84 static int gyro_report_value(struct i2c_client *client, struct sensor_axis *axis)
85 {
86 struct sensor_private_data *sensor =
87 (struct sensor_private_data *) i2c_get_clientdata(client);
88
89 if (sensor->status_cur == SENSOR_ON) {
90 /* Report gyro sensor information */
91 input_report_rel(sensor->input_dev, ABS_RX, axis->x);
92 input_report_rel(sensor->input_dev, ABS_RY, axis->y);
93 input_report_rel(sensor->input_dev, ABS_RZ, axis->z);
94 input_sync(sensor->input_dev);
95 }
96
97 return 0;
98 }
99
sensor_report_value(struct i2c_client * client)100 static int sensor_report_value(struct i2c_client *client)
101 {
102 struct sensor_private_data *sensor =
103 (struct sensor_private_data *) i2c_get_clientdata(client);
104 struct sensor_platform_data *pdata = sensor->pdata;
105 int ret = 0;
106 short x, y, z;
107 struct sensor_axis axis;
108 u8 buffer[6] = {0};
109
110 if (sensor->ops->read_len < 6) {
111 dev_err(&client->dev, "%s: length is error, len=%d\n",
112 __func__, sensor->ops->read_len);
113 return -1;
114 }
115
116 memset(buffer, 0, 6);
117
118 do {
119 *buffer = sensor->ops->read_reg;
120 ret = sensor_rx_data(client, buffer, sensor->ops->read_len);
121 if (ret < 0)
122 return ret;
123 } while (0);
124
125 x = ((buffer[0] << 8) & 0xFF00) + (buffer[1] & 0xFF);
126 y = ((buffer[2] << 8) & 0xFF00) + (buffer[3] & 0xFF);
127 z = ((buffer[4] << 8) & 0xFF00) + (buffer[5] & 0xFF);
128
129 axis.x = (pdata->orientation[0]) * x + (pdata->orientation[1]) * y + (pdata->orientation[2]) * z;
130 axis.y = (pdata->orientation[3]) * x + (pdata->orientation[4]) * y + (pdata->orientation[5]) * z;
131 axis.z = (pdata->orientation[6]) * x + (pdata->orientation[7]) * y + (pdata->orientation[8]) * z;
132
133 gyro_report_value(client, &axis);
134
135 mutex_lock(&(sensor->data_mutex));
136 sensor->axis = axis;
137 mutex_unlock(&(sensor->data_mutex));
138
139 return ret;
140 }
141
142 static struct sensor_operate gyro_iam20680_ops = {
143 .name = "iam20680_gyro",
144 .type = SENSOR_TYPE_GYROSCOPE,
145 .id_i2c = GYRO_ID_IAM20680,
146 .read_reg = IAM20680_GYRO_XOUT_H,
147 .read_len = 6,
148 .id_reg = IAM20680_WHOAMI,
149 .id_data = IAM20680_DEVICE_ID,
150 .precision = IAM20680_PRECISION,
151 .ctrl_reg = IAM20680_PWR_MGMT_2,
152 .int_status_reg = IAM20680_INT_STATUS,
153 .range = {-32768, 32768},
154 .trig = IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
155 .active = sensor_active,
156 .init = sensor_init,
157 .report = sensor_report_value,
158 };
159
160 /****************operate according to sensor chip:end************/
gyro_iam20680_probe(struct i2c_client * client,const struct i2c_device_id * devid)161 static int gyro_iam20680_probe(struct i2c_client *client,
162 const struct i2c_device_id *devid)
163 {
164 return sensor_register_device(client, NULL, devid, &gyro_iam20680_ops);
165 }
166
gyro_iam20680_remove(struct i2c_client * client)167 static int gyro_iam20680_remove(struct i2c_client *client)
168 {
169 return sensor_unregister_device(client, NULL, &gyro_iam20680_ops);
170 }
171
172 static const struct i2c_device_id gyro_iam20680_id[] = {
173 {"iam20680_gyro", GYRO_ID_IAM20680},
174 {}
175 };
176
177 static struct i2c_driver gyro_iam20680_driver = {
178 .probe = gyro_iam20680_probe,
179 .remove = gyro_iam20680_remove,
180 .shutdown = sensor_shutdown,
181 .id_table = gyro_iam20680_id,
182 .driver = {
183 .name = "gyro_iam20680",
184 #ifdef CONFIG_PM
185 .pm = &sensor_pm_ops,
186 #endif
187 },
188 };
189
gyro_iam20680_init(void)190 static int __init gyro_iam20680_init(void)
191 {
192 return i2c_add_driver(&gyro_iam20680_driver);
193 }
194
gyro_iam20680_exit(void)195 static void __exit gyro_iam20680_exit(void)
196 {
197 i2c_del_driver(&gyro_iam20680_driver);
198 }
199
200 /* must register after iam20680_acc */
201 device_initcall_sync(gyro_iam20680_init);
202 module_exit(gyro_iam20680_exit);
203
204 MODULE_AUTHOR("sxj <sxj@rock-chips.com>");
205 MODULE_DESCRIPTION("iam20680_gyro 3-Axis Gyroscope driver");
206 MODULE_LICENSE("GPL");
207