162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (C) 2021-2022, Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include "ice.h"
562306a36Sopenharmony_ci#include "ice_lib.h"
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci/**
862306a36Sopenharmony_ci * ice_gnss_do_write - Write data to internal GNSS receiver
962306a36Sopenharmony_ci * @pf: board private structure
1062306a36Sopenharmony_ci * @buf: command buffer
1162306a36Sopenharmony_ci * @size: command buffer size
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * Write UBX command data to the GNSS receiver
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * Return:
1662306a36Sopenharmony_ci * * number of bytes written - success
1762306a36Sopenharmony_ci * * negative - error code
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_cistatic int
2062306a36Sopenharmony_ciice_gnss_do_write(struct ice_pf *pf, const unsigned char *buf, unsigned int size)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	struct ice_aqc_link_topo_addr link_topo;
2362306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
2462306a36Sopenharmony_ci	unsigned int offset = 0;
2562306a36Sopenharmony_ci	int err = 0;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	memset(&link_topo, 0, sizeof(struct ice_aqc_link_topo_addr));
2862306a36Sopenharmony_ci	link_topo.topo_params.index = ICE_E810T_GNSS_I2C_BUS;
2962306a36Sopenharmony_ci	link_topo.topo_params.node_type_ctx |=
3062306a36Sopenharmony_ci		FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M,
3162306a36Sopenharmony_ci			   ICE_AQC_LINK_TOPO_NODE_CTX_OVERRIDE);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	/* It's not possible to write a single byte to u-blox.
3462306a36Sopenharmony_ci	 * Write all bytes in a loop until there are 6 or less bytes left. If
3562306a36Sopenharmony_ci	 * there are exactly 6 bytes left, the last write would be only a byte.
3662306a36Sopenharmony_ci	 * In this case, do 4+2 bytes writes instead of 5+1. Otherwise, do the
3762306a36Sopenharmony_ci	 * last 2 to 5 bytes write.
3862306a36Sopenharmony_ci	 */
3962306a36Sopenharmony_ci	while (size - offset > ICE_GNSS_UBX_WRITE_BYTES + 1) {
4062306a36Sopenharmony_ci		err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
4162306a36Sopenharmony_ci				       cpu_to_le16(buf[offset]),
4262306a36Sopenharmony_ci				       ICE_MAX_I2C_WRITE_BYTES,
4362306a36Sopenharmony_ci				       &buf[offset + 1], NULL);
4462306a36Sopenharmony_ci		if (err)
4562306a36Sopenharmony_ci			goto err_out;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci		offset += ICE_GNSS_UBX_WRITE_BYTES;
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	/* Single byte would be written. Write 4 bytes instead of 5. */
5162306a36Sopenharmony_ci	if (size - offset == ICE_GNSS_UBX_WRITE_BYTES + 1) {
5262306a36Sopenharmony_ci		err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
5362306a36Sopenharmony_ci				       cpu_to_le16(buf[offset]),
5462306a36Sopenharmony_ci				       ICE_MAX_I2C_WRITE_BYTES - 1,
5562306a36Sopenharmony_ci				       &buf[offset + 1], NULL);
5662306a36Sopenharmony_ci		if (err)
5762306a36Sopenharmony_ci			goto err_out;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci		offset += ICE_GNSS_UBX_WRITE_BYTES - 1;
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	/* Do the last write, 2 to 5 bytes. */
6362306a36Sopenharmony_ci	err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
6462306a36Sopenharmony_ci			       cpu_to_le16(buf[offset]), size - offset - 1,
6562306a36Sopenharmony_ci			       &buf[offset + 1], NULL);
6662306a36Sopenharmony_ci	if (err)
6762306a36Sopenharmony_ci		goto err_out;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	return size;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cierr_out:
7262306a36Sopenharmony_ci	dev_err(ice_pf_to_dev(pf), "GNSS failed to write, offset=%u, size=%u, err=%d\n",
7362306a36Sopenharmony_ci		offset, size, err);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return err;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/**
7962306a36Sopenharmony_ci * ice_gnss_read - Read data from internal GNSS module
8062306a36Sopenharmony_ci * @work: GNSS read work structure
8162306a36Sopenharmony_ci *
8262306a36Sopenharmony_ci * Read the data from internal GNSS receiver, write it to gnss_dev.
8362306a36Sopenharmony_ci */
8462306a36Sopenharmony_cistatic void ice_gnss_read(struct kthread_work *work)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct gnss_serial *gnss = container_of(work, struct gnss_serial,
8762306a36Sopenharmony_ci						read_work.work);
8862306a36Sopenharmony_ci	unsigned long delay = ICE_GNSS_POLL_DATA_DELAY_TIME;
8962306a36Sopenharmony_ci	unsigned int i, bytes_read, data_len, count;
9062306a36Sopenharmony_ci	struct ice_aqc_link_topo_addr link_topo;
9162306a36Sopenharmony_ci	struct ice_pf *pf;
9262306a36Sopenharmony_ci	struct ice_hw *hw;
9362306a36Sopenharmony_ci	__be16 data_len_b;
9462306a36Sopenharmony_ci	char *buf = NULL;
9562306a36Sopenharmony_ci	u8 i2c_params;
9662306a36Sopenharmony_ci	int err = 0;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	pf = gnss->back;
9962306a36Sopenharmony_ci	if (!pf || !test_bit(ICE_FLAG_GNSS, pf->flags))
10062306a36Sopenharmony_ci		return;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	hw = &pf->hw;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	memset(&link_topo, 0, sizeof(struct ice_aqc_link_topo_addr));
10562306a36Sopenharmony_ci	link_topo.topo_params.index = ICE_E810T_GNSS_I2C_BUS;
10662306a36Sopenharmony_ci	link_topo.topo_params.node_type_ctx |=
10762306a36Sopenharmony_ci		FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M,
10862306a36Sopenharmony_ci			   ICE_AQC_LINK_TOPO_NODE_CTX_OVERRIDE);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	i2c_params = ICE_GNSS_UBX_DATA_LEN_WIDTH |
11162306a36Sopenharmony_ci		     ICE_AQC_I2C_USE_REPEATED_START;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	err = ice_aq_read_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
11462306a36Sopenharmony_ci			      cpu_to_le16(ICE_GNSS_UBX_DATA_LEN_H),
11562306a36Sopenharmony_ci			      i2c_params, (u8 *)&data_len_b, NULL);
11662306a36Sopenharmony_ci	if (err)
11762306a36Sopenharmony_ci		goto requeue;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	data_len = be16_to_cpu(data_len_b);
12062306a36Sopenharmony_ci	if (data_len == 0 || data_len == U16_MAX)
12162306a36Sopenharmony_ci		goto requeue;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	/* The u-blox has data_len bytes for us to read */
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	data_len = min_t(typeof(data_len), data_len, PAGE_SIZE);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	buf = (char *)get_zeroed_page(GFP_KERNEL);
12862306a36Sopenharmony_ci	if (!buf) {
12962306a36Sopenharmony_ci		err = -ENOMEM;
13062306a36Sopenharmony_ci		goto requeue;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	/* Read received data */
13462306a36Sopenharmony_ci	for (i = 0; i < data_len; i += bytes_read) {
13562306a36Sopenharmony_ci		unsigned int bytes_left = data_len - i;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci		bytes_read = min_t(typeof(bytes_left), bytes_left,
13862306a36Sopenharmony_ci				   ICE_MAX_I2C_DATA_SIZE);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci		err = ice_aq_read_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
14162306a36Sopenharmony_ci				      cpu_to_le16(ICE_GNSS_UBX_EMPTY_DATA),
14262306a36Sopenharmony_ci				      bytes_read, &buf[i], NULL);
14362306a36Sopenharmony_ci		if (err)
14462306a36Sopenharmony_ci			goto free_buf;
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	count = gnss_insert_raw(pf->gnss_dev, buf, i);
14862306a36Sopenharmony_ci	if (count != i)
14962306a36Sopenharmony_ci		dev_warn(ice_pf_to_dev(pf),
15062306a36Sopenharmony_ci			 "gnss_insert_raw ret=%d size=%d\n",
15162306a36Sopenharmony_ci			 count, i);
15262306a36Sopenharmony_ci	delay = ICE_GNSS_TIMER_DELAY_TIME;
15362306a36Sopenharmony_cifree_buf:
15462306a36Sopenharmony_ci	free_page((unsigned long)buf);
15562306a36Sopenharmony_cirequeue:
15662306a36Sopenharmony_ci	kthread_queue_delayed_work(gnss->kworker, &gnss->read_work, delay);
15762306a36Sopenharmony_ci	if (err)
15862306a36Sopenharmony_ci		dev_dbg(ice_pf_to_dev(pf), "GNSS failed to read err=%d\n", err);
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci/**
16262306a36Sopenharmony_ci * ice_gnss_struct_init - Initialize GNSS receiver
16362306a36Sopenharmony_ci * @pf: Board private structure
16462306a36Sopenharmony_ci *
16562306a36Sopenharmony_ci * Initialize GNSS structures and workers.
16662306a36Sopenharmony_ci *
16762306a36Sopenharmony_ci * Return:
16862306a36Sopenharmony_ci * * pointer to initialized gnss_serial struct - success
16962306a36Sopenharmony_ci * * NULL - error
17062306a36Sopenharmony_ci */
17162306a36Sopenharmony_cistatic struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
17462306a36Sopenharmony_ci	struct kthread_worker *kworker;
17562306a36Sopenharmony_ci	struct gnss_serial *gnss;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	gnss = kzalloc(sizeof(*gnss), GFP_KERNEL);
17862306a36Sopenharmony_ci	if (!gnss)
17962306a36Sopenharmony_ci		return NULL;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	gnss->back = pf;
18262306a36Sopenharmony_ci	pf->gnss_serial = gnss;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	kthread_init_delayed_work(&gnss->read_work, ice_gnss_read);
18562306a36Sopenharmony_ci	kworker = kthread_create_worker(0, "ice-gnss-%s", dev_name(dev));
18662306a36Sopenharmony_ci	if (IS_ERR(kworker)) {
18762306a36Sopenharmony_ci		kfree(gnss);
18862306a36Sopenharmony_ci		return NULL;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	gnss->kworker = kworker;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	return gnss;
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci/**
19762306a36Sopenharmony_ci * ice_gnss_open - Open GNSS device
19862306a36Sopenharmony_ci * @gdev: pointer to the gnss device struct
19962306a36Sopenharmony_ci *
20062306a36Sopenharmony_ci * Open GNSS device and start filling the read buffer for consumer.
20162306a36Sopenharmony_ci *
20262306a36Sopenharmony_ci * Return:
20362306a36Sopenharmony_ci * * 0 - success
20462306a36Sopenharmony_ci * * negative - error code
20562306a36Sopenharmony_ci */
20662306a36Sopenharmony_cistatic int ice_gnss_open(struct gnss_device *gdev)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct ice_pf *pf = gnss_get_drvdata(gdev);
20962306a36Sopenharmony_ci	struct gnss_serial *gnss;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (!pf)
21262306a36Sopenharmony_ci		return -EFAULT;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	if (!test_bit(ICE_FLAG_GNSS, pf->flags))
21562306a36Sopenharmony_ci		return -EFAULT;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	gnss = pf->gnss_serial;
21862306a36Sopenharmony_ci	if (!gnss)
21962306a36Sopenharmony_ci		return -ENODEV;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	kthread_queue_delayed_work(gnss->kworker, &gnss->read_work, 0);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	return 0;
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci/**
22762306a36Sopenharmony_ci * ice_gnss_close - Close GNSS device
22862306a36Sopenharmony_ci * @gdev: pointer to the gnss device struct
22962306a36Sopenharmony_ci *
23062306a36Sopenharmony_ci * Close GNSS device, cancel worker, stop filling the read buffer.
23162306a36Sopenharmony_ci */
23262306a36Sopenharmony_cistatic void ice_gnss_close(struct gnss_device *gdev)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	struct ice_pf *pf = gnss_get_drvdata(gdev);
23562306a36Sopenharmony_ci	struct gnss_serial *gnss;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (!pf)
23862306a36Sopenharmony_ci		return;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	gnss = pf->gnss_serial;
24162306a36Sopenharmony_ci	if (!gnss)
24262306a36Sopenharmony_ci		return;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	kthread_cancel_delayed_work_sync(&gnss->read_work);
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci/**
24862306a36Sopenharmony_ci * ice_gnss_write - Write to GNSS device
24962306a36Sopenharmony_ci * @gdev: pointer to the gnss device struct
25062306a36Sopenharmony_ci * @buf: pointer to the user data
25162306a36Sopenharmony_ci * @count: size of the buffer to be sent to the GNSS device
25262306a36Sopenharmony_ci *
25362306a36Sopenharmony_ci * Return:
25462306a36Sopenharmony_ci * * number of written bytes - success
25562306a36Sopenharmony_ci * * negative - error code
25662306a36Sopenharmony_ci */
25762306a36Sopenharmony_cistatic int
25862306a36Sopenharmony_ciice_gnss_write(struct gnss_device *gdev, const unsigned char *buf,
25962306a36Sopenharmony_ci	       size_t count)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	struct ice_pf *pf = gnss_get_drvdata(gdev);
26262306a36Sopenharmony_ci	struct gnss_serial *gnss;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	/* We cannot write a single byte using our I2C implementation. */
26562306a36Sopenharmony_ci	if (count <= 1 || count > ICE_GNSS_TTY_WRITE_BUF)
26662306a36Sopenharmony_ci		return -EINVAL;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (!pf)
26962306a36Sopenharmony_ci		return -EFAULT;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (!test_bit(ICE_FLAG_GNSS, pf->flags))
27262306a36Sopenharmony_ci		return -EFAULT;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	gnss = pf->gnss_serial;
27562306a36Sopenharmony_ci	if (!gnss)
27662306a36Sopenharmony_ci		return -ENODEV;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return ice_gnss_do_write(pf, buf, count);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic const struct gnss_operations ice_gnss_ops = {
28262306a36Sopenharmony_ci	.open = ice_gnss_open,
28362306a36Sopenharmony_ci	.close = ice_gnss_close,
28462306a36Sopenharmony_ci	.write_raw = ice_gnss_write,
28562306a36Sopenharmony_ci};
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci/**
28862306a36Sopenharmony_ci * ice_gnss_register - Register GNSS receiver
28962306a36Sopenharmony_ci * @pf: Board private structure
29062306a36Sopenharmony_ci *
29162306a36Sopenharmony_ci * Allocate and register GNSS receiver in the Linux GNSS subsystem.
29262306a36Sopenharmony_ci *
29362306a36Sopenharmony_ci * Return:
29462306a36Sopenharmony_ci * * 0 - success
29562306a36Sopenharmony_ci * * negative - error code
29662306a36Sopenharmony_ci */
29762306a36Sopenharmony_cistatic int ice_gnss_register(struct ice_pf *pf)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct gnss_device *gdev;
30062306a36Sopenharmony_ci	int ret;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	gdev = gnss_allocate_device(ice_pf_to_dev(pf));
30362306a36Sopenharmony_ci	if (!gdev) {
30462306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf),
30562306a36Sopenharmony_ci			"gnss_allocate_device returns NULL\n");
30662306a36Sopenharmony_ci		return -ENOMEM;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	gdev->ops = &ice_gnss_ops;
31062306a36Sopenharmony_ci	gdev->type = GNSS_TYPE_UBX;
31162306a36Sopenharmony_ci	gnss_set_drvdata(gdev, pf);
31262306a36Sopenharmony_ci	ret = gnss_register_device(gdev);
31362306a36Sopenharmony_ci	if (ret) {
31462306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "gnss_register_device err=%d\n",
31562306a36Sopenharmony_ci			ret);
31662306a36Sopenharmony_ci		gnss_put_device(gdev);
31762306a36Sopenharmony_ci	} else {
31862306a36Sopenharmony_ci		pf->gnss_dev = gdev;
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	return ret;
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci/**
32562306a36Sopenharmony_ci * ice_gnss_deregister - Deregister GNSS receiver
32662306a36Sopenharmony_ci * @pf: Board private structure
32762306a36Sopenharmony_ci *
32862306a36Sopenharmony_ci * Deregister GNSS receiver from the Linux GNSS subsystem,
32962306a36Sopenharmony_ci * release its resources.
33062306a36Sopenharmony_ci */
33162306a36Sopenharmony_cistatic void ice_gnss_deregister(struct ice_pf *pf)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	if (pf->gnss_dev) {
33462306a36Sopenharmony_ci		gnss_deregister_device(pf->gnss_dev);
33562306a36Sopenharmony_ci		gnss_put_device(pf->gnss_dev);
33662306a36Sopenharmony_ci		pf->gnss_dev = NULL;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci/**
34162306a36Sopenharmony_ci * ice_gnss_init - Initialize GNSS support
34262306a36Sopenharmony_ci * @pf: Board private structure
34362306a36Sopenharmony_ci */
34462306a36Sopenharmony_civoid ice_gnss_init(struct ice_pf *pf)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	int ret;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	pf->gnss_serial = ice_gnss_struct_init(pf);
34962306a36Sopenharmony_ci	if (!pf->gnss_serial)
35062306a36Sopenharmony_ci		return;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	ret = ice_gnss_register(pf);
35362306a36Sopenharmony_ci	if (!ret) {
35462306a36Sopenharmony_ci		set_bit(ICE_FLAG_GNSS, pf->flags);
35562306a36Sopenharmony_ci		dev_info(ice_pf_to_dev(pf), "GNSS init successful\n");
35662306a36Sopenharmony_ci	} else {
35762306a36Sopenharmony_ci		ice_gnss_exit(pf);
35862306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "GNSS init failure\n");
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci/**
36362306a36Sopenharmony_ci * ice_gnss_exit - Disable GNSS TTY support
36462306a36Sopenharmony_ci * @pf: Board private structure
36562306a36Sopenharmony_ci */
36662306a36Sopenharmony_civoid ice_gnss_exit(struct ice_pf *pf)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	ice_gnss_deregister(pf);
36962306a36Sopenharmony_ci	clear_bit(ICE_FLAG_GNSS, pf->flags);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (pf->gnss_serial) {
37262306a36Sopenharmony_ci		struct gnss_serial *gnss = pf->gnss_serial;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci		kthread_cancel_delayed_work_sync(&gnss->read_work);
37562306a36Sopenharmony_ci		kthread_destroy_worker(gnss->kworker);
37662306a36Sopenharmony_ci		gnss->kworker = NULL;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci		kfree(gnss);
37962306a36Sopenharmony_ci		pf->gnss_serial = NULL;
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci/**
38462306a36Sopenharmony_ci * ice_gnss_is_gps_present - Check if GPS HW is present
38562306a36Sopenharmony_ci * @hw: pointer to HW struct
38662306a36Sopenharmony_ci */
38762306a36Sopenharmony_cibool ice_gnss_is_gps_present(struct ice_hw *hw)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	if (!hw->func_caps.ts_func_info.src_tmr_owned)
39062306a36Sopenharmony_ci		return false;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
39362306a36Sopenharmony_ci	if (ice_is_e810t(hw)) {
39462306a36Sopenharmony_ci		int err;
39562306a36Sopenharmony_ci		u8 data;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci		err = ice_read_pca9575_reg_e810t(hw, ICE_PCA9575_P0_IN, &data);
39862306a36Sopenharmony_ci		if (err || !!(data & ICE_E810T_P0_GNSS_PRSNT_N))
39962306a36Sopenharmony_ci			return false;
40062306a36Sopenharmony_ci	} else {
40162306a36Sopenharmony_ci		return false;
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci#else
40462306a36Sopenharmony_ci	if (!ice_is_e810t(hw))
40562306a36Sopenharmony_ci		return false;
40662306a36Sopenharmony_ci#endif /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	return true;
40962306a36Sopenharmony_ci}
410