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