xref: /OK3568_Linux_fs/kernel/drivers/iio/chemical/pms7003.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Plantower PMS7003 particulate matter sensor driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <asm/unaligned.h>
9*4882a593Smuzhiyun #include <linux/completion.h>
10*4882a593Smuzhiyun #include <linux/device.h>
11*4882a593Smuzhiyun #include <linux/errno.h>
12*4882a593Smuzhiyun #include <linux/iio/buffer.h>
13*4882a593Smuzhiyun #include <linux/iio/iio.h>
14*4882a593Smuzhiyun #include <linux/iio/trigger_consumer.h>
15*4882a593Smuzhiyun #include <linux/iio/triggered_buffer.h>
16*4882a593Smuzhiyun #include <linux/jiffies.h>
17*4882a593Smuzhiyun #include <linux/kernel.h>
18*4882a593Smuzhiyun #include <linux/mod_devicetable.h>
19*4882a593Smuzhiyun #include <linux/module.h>
20*4882a593Smuzhiyun #include <linux/mutex.h>
21*4882a593Smuzhiyun #include <linux/serdev.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #define PMS7003_DRIVER_NAME "pms7003"
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #define PMS7003_MAGIC 0x424d
26*4882a593Smuzhiyun /* last 2 data bytes hold frame checksum */
27*4882a593Smuzhiyun #define PMS7003_MAX_DATA_LENGTH 28
28*4882a593Smuzhiyun #define PMS7003_CHECKSUM_LENGTH 2
29*4882a593Smuzhiyun #define PMS7003_PM10_OFFSET 10
30*4882a593Smuzhiyun #define PMS7003_PM2P5_OFFSET 8
31*4882a593Smuzhiyun #define PMS7003_PM1_OFFSET 6
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define PMS7003_TIMEOUT msecs_to_jiffies(6000)
34*4882a593Smuzhiyun #define PMS7003_CMD_LENGTH 7
35*4882a593Smuzhiyun #define PMS7003_PM_MAX 1000
36*4882a593Smuzhiyun #define PMS7003_PM_MIN 0
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun enum {
39*4882a593Smuzhiyun 	PM1,
40*4882a593Smuzhiyun 	PM2P5,
41*4882a593Smuzhiyun 	PM10,
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun enum pms7003_cmd {
45*4882a593Smuzhiyun 	CMD_WAKEUP,
46*4882a593Smuzhiyun 	CMD_ENTER_PASSIVE_MODE,
47*4882a593Smuzhiyun 	CMD_READ_PASSIVE,
48*4882a593Smuzhiyun 	CMD_SLEEP,
49*4882a593Smuzhiyun };
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun /*
52*4882a593Smuzhiyun  * commands have following format:
53*4882a593Smuzhiyun  *
54*4882a593Smuzhiyun  * +------+------+-----+------+-----+-----------+-----------+
55*4882a593Smuzhiyun  * | 0x42 | 0x4d | cmd | 0x00 | arg | cksum msb | cksum lsb |
56*4882a593Smuzhiyun  * +------+------+-----+------+-----+-----------+-----------+
57*4882a593Smuzhiyun  */
58*4882a593Smuzhiyun static const u8 pms7003_cmd_tbl[][PMS7003_CMD_LENGTH] = {
59*4882a593Smuzhiyun 	[CMD_WAKEUP] = { 0x42, 0x4d, 0xe4, 0x00, 0x01, 0x01, 0x74 },
60*4882a593Smuzhiyun 	[CMD_ENTER_PASSIVE_MODE] = { 0x42, 0x4d, 0xe1, 0x00, 0x00, 0x01, 0x70 },
61*4882a593Smuzhiyun 	[CMD_READ_PASSIVE] = { 0x42, 0x4d, 0xe2, 0x00, 0x00, 0x01, 0x71 },
62*4882a593Smuzhiyun 	[CMD_SLEEP] = { 0x42, 0x4d, 0xe4, 0x00, 0x00, 0x01, 0x73 },
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun struct pms7003_frame {
66*4882a593Smuzhiyun 	u8 data[PMS7003_MAX_DATA_LENGTH];
67*4882a593Smuzhiyun 	u16 expected_length;
68*4882a593Smuzhiyun 	u16 length;
69*4882a593Smuzhiyun };
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun struct pms7003_state {
72*4882a593Smuzhiyun 	struct serdev_device *serdev;
73*4882a593Smuzhiyun 	struct pms7003_frame frame;
74*4882a593Smuzhiyun 	struct completion frame_ready;
75*4882a593Smuzhiyun 	struct mutex lock; /* must be held whenever state gets touched */
76*4882a593Smuzhiyun 	/* Used to construct scan to push to the IIO buffer */
77*4882a593Smuzhiyun 	struct {
78*4882a593Smuzhiyun 		u16 data[3]; /* PM1, PM2P5, PM10 */
79*4882a593Smuzhiyun 		s64 ts;
80*4882a593Smuzhiyun 	} scan;
81*4882a593Smuzhiyun };
82*4882a593Smuzhiyun 
pms7003_do_cmd(struct pms7003_state * state,enum pms7003_cmd cmd)83*4882a593Smuzhiyun static int pms7003_do_cmd(struct pms7003_state *state, enum pms7003_cmd cmd)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun 	int ret;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	ret = serdev_device_write(state->serdev, pms7003_cmd_tbl[cmd],
88*4882a593Smuzhiyun 				  PMS7003_CMD_LENGTH, PMS7003_TIMEOUT);
89*4882a593Smuzhiyun 	if (ret < PMS7003_CMD_LENGTH)
90*4882a593Smuzhiyun 		return ret < 0 ? ret : -EIO;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	ret = wait_for_completion_interruptible_timeout(&state->frame_ready,
93*4882a593Smuzhiyun 							PMS7003_TIMEOUT);
94*4882a593Smuzhiyun 	if (!ret)
95*4882a593Smuzhiyun 		ret = -ETIMEDOUT;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	return ret < 0 ? ret : 0;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
pms7003_get_pm(const u8 * data)100*4882a593Smuzhiyun static u16 pms7003_get_pm(const u8 *data)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	return clamp_val(get_unaligned_be16(data),
103*4882a593Smuzhiyun 			 PMS7003_PM_MIN, PMS7003_PM_MAX);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
pms7003_trigger_handler(int irq,void * p)106*4882a593Smuzhiyun static irqreturn_t pms7003_trigger_handler(int irq, void *p)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	struct iio_poll_func *pf = p;
109*4882a593Smuzhiyun 	struct iio_dev *indio_dev = pf->indio_dev;
110*4882a593Smuzhiyun 	struct pms7003_state *state = iio_priv(indio_dev);
111*4882a593Smuzhiyun 	struct pms7003_frame *frame = &state->frame;
112*4882a593Smuzhiyun 	int ret;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	mutex_lock(&state->lock);
115*4882a593Smuzhiyun 	ret = pms7003_do_cmd(state, CMD_READ_PASSIVE);
116*4882a593Smuzhiyun 	if (ret) {
117*4882a593Smuzhiyun 		mutex_unlock(&state->lock);
118*4882a593Smuzhiyun 		goto err;
119*4882a593Smuzhiyun 	}
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	state->scan.data[PM1] =
122*4882a593Smuzhiyun 		pms7003_get_pm(frame->data + PMS7003_PM1_OFFSET);
123*4882a593Smuzhiyun 	state->scan.data[PM2P5] =
124*4882a593Smuzhiyun 		pms7003_get_pm(frame->data + PMS7003_PM2P5_OFFSET);
125*4882a593Smuzhiyun 	state->scan.data[PM10] =
126*4882a593Smuzhiyun 		pms7003_get_pm(frame->data + PMS7003_PM10_OFFSET);
127*4882a593Smuzhiyun 	mutex_unlock(&state->lock);
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	iio_push_to_buffers_with_timestamp(indio_dev, &state->scan,
130*4882a593Smuzhiyun 					   iio_get_time_ns(indio_dev));
131*4882a593Smuzhiyun err:
132*4882a593Smuzhiyun 	iio_trigger_notify_done(indio_dev->trig);
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	return IRQ_HANDLED;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
pms7003_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)137*4882a593Smuzhiyun static int pms7003_read_raw(struct iio_dev *indio_dev,
138*4882a593Smuzhiyun 			    struct iio_chan_spec const *chan,
139*4882a593Smuzhiyun 			    int *val, int *val2, long mask)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	struct pms7003_state *state = iio_priv(indio_dev);
142*4882a593Smuzhiyun 	struct pms7003_frame *frame = &state->frame;
143*4882a593Smuzhiyun 	int ret;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	switch (mask) {
146*4882a593Smuzhiyun 	case IIO_CHAN_INFO_PROCESSED:
147*4882a593Smuzhiyun 		switch (chan->type) {
148*4882a593Smuzhiyun 		case IIO_MASSCONCENTRATION:
149*4882a593Smuzhiyun 			mutex_lock(&state->lock);
150*4882a593Smuzhiyun 			ret = pms7003_do_cmd(state, CMD_READ_PASSIVE);
151*4882a593Smuzhiyun 			if (ret) {
152*4882a593Smuzhiyun 				mutex_unlock(&state->lock);
153*4882a593Smuzhiyun 				return ret;
154*4882a593Smuzhiyun 			}
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 			*val = pms7003_get_pm(frame->data + chan->address);
157*4882a593Smuzhiyun 			mutex_unlock(&state->lock);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 			return IIO_VAL_INT;
160*4882a593Smuzhiyun 		default:
161*4882a593Smuzhiyun 			return -EINVAL;
162*4882a593Smuzhiyun 		}
163*4882a593Smuzhiyun 	}
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	return -EINVAL;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun static const struct iio_info pms7003_info = {
169*4882a593Smuzhiyun 	.read_raw = pms7003_read_raw,
170*4882a593Smuzhiyun };
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun #define PMS7003_CHAN(_index, _mod, _addr) { \
173*4882a593Smuzhiyun 	.type = IIO_MASSCONCENTRATION, \
174*4882a593Smuzhiyun 	.modified = 1, \
175*4882a593Smuzhiyun 	.channel2 = IIO_MOD_ ## _mod, \
176*4882a593Smuzhiyun 	.address = _addr, \
177*4882a593Smuzhiyun 	.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
178*4882a593Smuzhiyun 	.scan_index = _index, \
179*4882a593Smuzhiyun 	.scan_type = { \
180*4882a593Smuzhiyun 		.sign = 'u', \
181*4882a593Smuzhiyun 		.realbits = 10, \
182*4882a593Smuzhiyun 		.storagebits = 16, \
183*4882a593Smuzhiyun 		.endianness = IIO_CPU, \
184*4882a593Smuzhiyun 	}, \
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun static const struct iio_chan_spec pms7003_channels[] = {
188*4882a593Smuzhiyun 	PMS7003_CHAN(0, PM1, PMS7003_PM1_OFFSET),
189*4882a593Smuzhiyun 	PMS7003_CHAN(1, PM2P5, PMS7003_PM2P5_OFFSET),
190*4882a593Smuzhiyun 	PMS7003_CHAN(2, PM10, PMS7003_PM10_OFFSET),
191*4882a593Smuzhiyun 	IIO_CHAN_SOFT_TIMESTAMP(3),
192*4882a593Smuzhiyun };
193*4882a593Smuzhiyun 
pms7003_calc_checksum(struct pms7003_frame * frame)194*4882a593Smuzhiyun static u16 pms7003_calc_checksum(struct pms7003_frame *frame)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun 	u16 checksum = (PMS7003_MAGIC >> 8) + (u8)(PMS7003_MAGIC & 0xff) +
197*4882a593Smuzhiyun 		       (frame->length >> 8) + (u8)frame->length;
198*4882a593Smuzhiyun 	int i;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	for (i = 0; i < frame->length - PMS7003_CHECKSUM_LENGTH; i++)
201*4882a593Smuzhiyun 		checksum += frame->data[i];
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	return checksum;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun 
pms7003_frame_is_okay(struct pms7003_frame * frame)206*4882a593Smuzhiyun static bool pms7003_frame_is_okay(struct pms7003_frame *frame)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	int offset = frame->length - PMS7003_CHECKSUM_LENGTH;
209*4882a593Smuzhiyun 	u16 checksum = get_unaligned_be16(frame->data + offset);
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	return checksum == pms7003_calc_checksum(frame);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
pms7003_receive_buf(struct serdev_device * serdev,const unsigned char * buf,size_t size)214*4882a593Smuzhiyun static int pms7003_receive_buf(struct serdev_device *serdev,
215*4882a593Smuzhiyun 			       const unsigned char *buf, size_t size)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun 	struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev);
218*4882a593Smuzhiyun 	struct pms7003_state *state = iio_priv(indio_dev);
219*4882a593Smuzhiyun 	struct pms7003_frame *frame = &state->frame;
220*4882a593Smuzhiyun 	int num;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	if (!frame->expected_length) {
223*4882a593Smuzhiyun 		u16 magic;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 		/* wait for SOF and data length */
226*4882a593Smuzhiyun 		if (size < 4)
227*4882a593Smuzhiyun 			return 0;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 		magic = get_unaligned_be16(buf);
230*4882a593Smuzhiyun 		if (magic != PMS7003_MAGIC)
231*4882a593Smuzhiyun 			return 2;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 		num = get_unaligned_be16(buf + 2);
234*4882a593Smuzhiyun 		if (num <= PMS7003_MAX_DATA_LENGTH) {
235*4882a593Smuzhiyun 			frame->expected_length = num;
236*4882a593Smuzhiyun 			frame->length = 0;
237*4882a593Smuzhiyun 		}
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 		return 4;
240*4882a593Smuzhiyun 	}
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	num = min(size, (size_t)(frame->expected_length - frame->length));
243*4882a593Smuzhiyun 	memcpy(frame->data + frame->length, buf, num);
244*4882a593Smuzhiyun 	frame->length += num;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	if (frame->length == frame->expected_length) {
247*4882a593Smuzhiyun 		if (pms7003_frame_is_okay(frame))
248*4882a593Smuzhiyun 			complete(&state->frame_ready);
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 		frame->expected_length = 0;
251*4882a593Smuzhiyun 	}
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	return num;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun static const struct serdev_device_ops pms7003_serdev_ops = {
257*4882a593Smuzhiyun 	.receive_buf = pms7003_receive_buf,
258*4882a593Smuzhiyun 	.write_wakeup = serdev_device_write_wakeup,
259*4882a593Smuzhiyun };
260*4882a593Smuzhiyun 
pms7003_stop(void * data)261*4882a593Smuzhiyun static void pms7003_stop(void *data)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun 	struct pms7003_state *state = data;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	pms7003_do_cmd(state, CMD_SLEEP);
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun static const unsigned long pms7003_scan_masks[] = { 0x07, 0x00 };
269*4882a593Smuzhiyun 
pms7003_probe(struct serdev_device * serdev)270*4882a593Smuzhiyun static int pms7003_probe(struct serdev_device *serdev)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun 	struct pms7003_state *state;
273*4882a593Smuzhiyun 	struct iio_dev *indio_dev;
274*4882a593Smuzhiyun 	int ret;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	indio_dev = devm_iio_device_alloc(&serdev->dev, sizeof(*state));
277*4882a593Smuzhiyun 	if (!indio_dev)
278*4882a593Smuzhiyun 		return -ENOMEM;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	state = iio_priv(indio_dev);
281*4882a593Smuzhiyun 	serdev_device_set_drvdata(serdev, indio_dev);
282*4882a593Smuzhiyun 	state->serdev = serdev;
283*4882a593Smuzhiyun 	indio_dev->info = &pms7003_info;
284*4882a593Smuzhiyun 	indio_dev->name = PMS7003_DRIVER_NAME;
285*4882a593Smuzhiyun 	indio_dev->channels = pms7003_channels,
286*4882a593Smuzhiyun 	indio_dev->num_channels = ARRAY_SIZE(pms7003_channels);
287*4882a593Smuzhiyun 	indio_dev->modes = INDIO_DIRECT_MODE;
288*4882a593Smuzhiyun 	indio_dev->available_scan_masks = pms7003_scan_masks;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	mutex_init(&state->lock);
291*4882a593Smuzhiyun 	init_completion(&state->frame_ready);
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	serdev_device_set_client_ops(serdev, &pms7003_serdev_ops);
294*4882a593Smuzhiyun 	ret = devm_serdev_device_open(&serdev->dev, serdev);
295*4882a593Smuzhiyun 	if (ret)
296*4882a593Smuzhiyun 		return ret;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	serdev_device_set_baudrate(serdev, 9600);
299*4882a593Smuzhiyun 	serdev_device_set_flow_control(serdev, false);
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
302*4882a593Smuzhiyun 	if (ret)
303*4882a593Smuzhiyun 		return ret;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	ret = pms7003_do_cmd(state, CMD_WAKEUP);
306*4882a593Smuzhiyun 	if (ret) {
307*4882a593Smuzhiyun 		dev_err(&serdev->dev, "failed to wakeup sensor\n");
308*4882a593Smuzhiyun 		return ret;
309*4882a593Smuzhiyun 	}
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	ret = pms7003_do_cmd(state, CMD_ENTER_PASSIVE_MODE);
312*4882a593Smuzhiyun 	if (ret) {
313*4882a593Smuzhiyun 		dev_err(&serdev->dev, "failed to enter passive mode\n");
314*4882a593Smuzhiyun 		return ret;
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	ret = devm_add_action_or_reset(&serdev->dev, pms7003_stop, state);
318*4882a593Smuzhiyun 	if (ret)
319*4882a593Smuzhiyun 		return ret;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	ret = devm_iio_triggered_buffer_setup(&serdev->dev, indio_dev, NULL,
322*4882a593Smuzhiyun 					      pms7003_trigger_handler, NULL);
323*4882a593Smuzhiyun 	if (ret)
324*4882a593Smuzhiyun 		return ret;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	return devm_iio_device_register(&serdev->dev, indio_dev);
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun static const struct of_device_id pms7003_of_match[] = {
330*4882a593Smuzhiyun 	{ .compatible = "plantower,pms1003" },
331*4882a593Smuzhiyun 	{ .compatible = "plantower,pms3003" },
332*4882a593Smuzhiyun 	{ .compatible = "plantower,pms5003" },
333*4882a593Smuzhiyun 	{ .compatible = "plantower,pms6003" },
334*4882a593Smuzhiyun 	{ .compatible = "plantower,pms7003" },
335*4882a593Smuzhiyun 	{ .compatible = "plantower,pmsa003" },
336*4882a593Smuzhiyun 	{ }
337*4882a593Smuzhiyun };
338*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, pms7003_of_match);
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun static struct serdev_device_driver pms7003_driver = {
341*4882a593Smuzhiyun 	.driver = {
342*4882a593Smuzhiyun 		.name = PMS7003_DRIVER_NAME,
343*4882a593Smuzhiyun 		.of_match_table = pms7003_of_match,
344*4882a593Smuzhiyun 	},
345*4882a593Smuzhiyun 	.probe = pms7003_probe,
346*4882a593Smuzhiyun };
347*4882a593Smuzhiyun module_serdev_device_driver(pms7003_driver);
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
350*4882a593Smuzhiyun MODULE_DESCRIPTION("Plantower PMS7003 particulate matter sensor driver");
351*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
352