brintos

brintos / linux-shallow public Read only

0
0
Text · 9.5 KiB · c8ea1af Raw
413 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (C) 2021-2022, Intel Corporation. */3 4#include "ice.h"5#include "ice_lib.h"6 7/**8 * ice_gnss_do_write - Write data to internal GNSS receiver9 * @pf: board private structure10 * @buf: command buffer11 * @size: command buffer size12 *13 * Write UBX command data to the GNSS receiver14 *15 * Return:16 * * number of bytes written - success17 * * negative - error code18 */19static int20ice_gnss_do_write(struct ice_pf *pf, const unsigned char *buf, unsigned int size)21{22	struct ice_aqc_link_topo_addr link_topo;23	struct ice_hw *hw = &pf->hw;24	unsigned int offset = 0;25	int err = 0;26 27	memset(&link_topo, 0, sizeof(struct ice_aqc_link_topo_addr));28	link_topo.topo_params.index = ICE_E810T_GNSS_I2C_BUS;29	link_topo.topo_params.node_type_ctx |=30		FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M,31			   ICE_AQC_LINK_TOPO_NODE_CTX_OVERRIDE);32 33	/* It's not possible to write a single byte to u-blox.34	 * Write all bytes in a loop until there are 6 or less bytes left. If35	 * there are exactly 6 bytes left, the last write would be only a byte.36	 * In this case, do 4+2 bytes writes instead of 5+1. Otherwise, do the37	 * last 2 to 5 bytes write.38	 */39	while (size - offset > ICE_GNSS_UBX_WRITE_BYTES + 1) {40		err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,41				       cpu_to_le16(buf[offset]),42				       ICE_MAX_I2C_WRITE_BYTES,43				       &buf[offset + 1], NULL);44		if (err)45			goto err_out;46 47		offset += ICE_GNSS_UBX_WRITE_BYTES;48	}49 50	/* Single byte would be written. Write 4 bytes instead of 5. */51	if (size - offset == ICE_GNSS_UBX_WRITE_BYTES + 1) {52		err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,53				       cpu_to_le16(buf[offset]),54				       ICE_MAX_I2C_WRITE_BYTES - 1,55				       &buf[offset + 1], NULL);56		if (err)57			goto err_out;58 59		offset += ICE_GNSS_UBX_WRITE_BYTES - 1;60	}61 62	/* Do the last write, 2 to 5 bytes. */63	err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,64			       cpu_to_le16(buf[offset]), size - offset - 1,65			       &buf[offset + 1], NULL);66	if (err)67		goto err_out;68 69	return size;70 71err_out:72	dev_err(ice_pf_to_dev(pf), "GNSS failed to write, offset=%u, size=%u, err=%d\n",73		offset, size, err);74 75	return err;76}77 78/**79 * ice_gnss_read - Read data from internal GNSS module80 * @work: GNSS read work structure81 *82 * Read the data from internal GNSS receiver, write it to gnss_dev.83 */84static void ice_gnss_read(struct kthread_work *work)85{86	struct gnss_serial *gnss = container_of(work, struct gnss_serial,87						read_work.work);88	unsigned long delay = ICE_GNSS_POLL_DATA_DELAY_TIME;89	unsigned int i, bytes_read, data_len, count;90	struct ice_aqc_link_topo_addr link_topo;91	struct ice_pf *pf;92	struct ice_hw *hw;93	__be16 data_len_b;94	char *buf = NULL;95	u8 i2c_params;96	int err = 0;97 98	pf = gnss->back;99	if (!pf || !test_bit(ICE_FLAG_GNSS, pf->flags))100		return;101 102	hw = &pf->hw;103 104	memset(&link_topo, 0, sizeof(struct ice_aqc_link_topo_addr));105	link_topo.topo_params.index = ICE_E810T_GNSS_I2C_BUS;106	link_topo.topo_params.node_type_ctx |=107		FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M,108			   ICE_AQC_LINK_TOPO_NODE_CTX_OVERRIDE);109 110	i2c_params = ICE_GNSS_UBX_DATA_LEN_WIDTH |111		     ICE_AQC_I2C_USE_REPEATED_START;112 113	err = ice_aq_read_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,114			      cpu_to_le16(ICE_GNSS_UBX_DATA_LEN_H),115			      i2c_params, (u8 *)&data_len_b, NULL);116	if (err)117		goto requeue;118 119	data_len = be16_to_cpu(data_len_b);120	if (data_len == 0 || data_len == U16_MAX)121		goto requeue;122 123	/* The u-blox has data_len bytes for us to read */124 125	data_len = min_t(typeof(data_len), data_len, PAGE_SIZE);126 127	buf = (char *)get_zeroed_page(GFP_KERNEL);128	if (!buf) {129		err = -ENOMEM;130		goto requeue;131	}132 133	/* Read received data */134	for (i = 0; i < data_len; i += bytes_read) {135		unsigned int bytes_left = data_len - i;136 137		bytes_read = min_t(typeof(bytes_left), bytes_left,138				   ICE_MAX_I2C_DATA_SIZE);139 140		err = ice_aq_read_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,141				      cpu_to_le16(ICE_GNSS_UBX_EMPTY_DATA),142				      bytes_read, &buf[i], NULL);143		if (err)144			goto free_buf;145	}146 147	count = gnss_insert_raw(pf->gnss_dev, buf, i);148	if (count != i)149		dev_warn(ice_pf_to_dev(pf),150			 "gnss_insert_raw ret=%d size=%d\n",151			 count, i);152	delay = ICE_GNSS_TIMER_DELAY_TIME;153free_buf:154	free_page((unsigned long)buf);155requeue:156	kthread_queue_delayed_work(gnss->kworker, &gnss->read_work, delay);157	if (err)158		dev_dbg(ice_pf_to_dev(pf), "GNSS failed to read err=%d\n", err);159}160 161/**162 * ice_gnss_struct_init - Initialize GNSS receiver163 * @pf: Board private structure164 *165 * Initialize GNSS structures and workers.166 *167 * Return:168 * * pointer to initialized gnss_serial struct - success169 * * NULL - error170 */171static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf)172{173	struct device *dev = ice_pf_to_dev(pf);174	struct kthread_worker *kworker;175	struct gnss_serial *gnss;176 177	gnss = kzalloc(sizeof(*gnss), GFP_KERNEL);178	if (!gnss)179		return NULL;180 181	gnss->back = pf;182	pf->gnss_serial = gnss;183 184	kthread_init_delayed_work(&gnss->read_work, ice_gnss_read);185	kworker = kthread_create_worker(0, "ice-gnss-%s", dev_name(dev));186	if (IS_ERR(kworker)) {187		kfree(gnss);188		return NULL;189	}190 191	gnss->kworker = kworker;192 193	return gnss;194}195 196/**197 * ice_gnss_open - Open GNSS device198 * @gdev: pointer to the gnss device struct199 *200 * Open GNSS device and start filling the read buffer for consumer.201 *202 * Return:203 * * 0 - success204 * * negative - error code205 */206static int ice_gnss_open(struct gnss_device *gdev)207{208	struct ice_pf *pf = gnss_get_drvdata(gdev);209	struct gnss_serial *gnss;210 211	if (!pf)212		return -EFAULT;213 214	if (!test_bit(ICE_FLAG_GNSS, pf->flags))215		return -EFAULT;216 217	gnss = pf->gnss_serial;218	if (!gnss)219		return -ENODEV;220 221	kthread_queue_delayed_work(gnss->kworker, &gnss->read_work, 0);222 223	return 0;224}225 226/**227 * ice_gnss_close - Close GNSS device228 * @gdev: pointer to the gnss device struct229 *230 * Close GNSS device, cancel worker, stop filling the read buffer.231 */232static void ice_gnss_close(struct gnss_device *gdev)233{234	struct ice_pf *pf = gnss_get_drvdata(gdev);235	struct gnss_serial *gnss;236 237	if (!pf)238		return;239 240	gnss = pf->gnss_serial;241	if (!gnss)242		return;243 244	kthread_cancel_delayed_work_sync(&gnss->read_work);245}246 247/**248 * ice_gnss_write - Write to GNSS device249 * @gdev: pointer to the gnss device struct250 * @buf: pointer to the user data251 * @count: size of the buffer to be sent to the GNSS device252 *253 * Return:254 * * number of written bytes - success255 * * negative - error code256 */257static int258ice_gnss_write(struct gnss_device *gdev, const unsigned char *buf,259	       size_t count)260{261	struct ice_pf *pf = gnss_get_drvdata(gdev);262	struct gnss_serial *gnss;263 264	/* We cannot write a single byte using our I2C implementation. */265	if (count <= 1 || count > ICE_GNSS_TTY_WRITE_BUF)266		return -EINVAL;267 268	if (!pf)269		return -EFAULT;270 271	if (!test_bit(ICE_FLAG_GNSS, pf->flags))272		return -EFAULT;273 274	gnss = pf->gnss_serial;275	if (!gnss)276		return -ENODEV;277 278	return ice_gnss_do_write(pf, buf, count);279}280 281static const struct gnss_operations ice_gnss_ops = {282	.open = ice_gnss_open,283	.close = ice_gnss_close,284	.write_raw = ice_gnss_write,285};286 287/**288 * ice_gnss_register - Register GNSS receiver289 * @pf: Board private structure290 *291 * Allocate and register GNSS receiver in the Linux GNSS subsystem.292 *293 * Return:294 * * 0 - success295 * * negative - error code296 */297static int ice_gnss_register(struct ice_pf *pf)298{299	struct gnss_device *gdev;300	int ret;301 302	gdev = gnss_allocate_device(ice_pf_to_dev(pf));303	if (!gdev) {304		dev_err(ice_pf_to_dev(pf),305			"gnss_allocate_device returns NULL\n");306		return -ENOMEM;307	}308 309	gdev->ops = &ice_gnss_ops;310	gdev->type = GNSS_TYPE_UBX;311	gnss_set_drvdata(gdev, pf);312	ret = gnss_register_device(gdev);313	if (ret) {314		dev_err(ice_pf_to_dev(pf), "gnss_register_device err=%d\n",315			ret);316		gnss_put_device(gdev);317	} else {318		pf->gnss_dev = gdev;319	}320 321	return ret;322}323 324/**325 * ice_gnss_deregister - Deregister GNSS receiver326 * @pf: Board private structure327 *328 * Deregister GNSS receiver from the Linux GNSS subsystem,329 * release its resources.330 */331static void ice_gnss_deregister(struct ice_pf *pf)332{333	if (pf->gnss_dev) {334		gnss_deregister_device(pf->gnss_dev);335		gnss_put_device(pf->gnss_dev);336		pf->gnss_dev = NULL;337	}338}339 340/**341 * ice_gnss_init - Initialize GNSS support342 * @pf: Board private structure343 */344void ice_gnss_init(struct ice_pf *pf)345{346	int ret;347 348	pf->gnss_serial = ice_gnss_struct_init(pf);349	if (!pf->gnss_serial)350		return;351 352	ret = ice_gnss_register(pf);353	if (!ret) {354		set_bit(ICE_FLAG_GNSS, pf->flags);355		dev_info(ice_pf_to_dev(pf), "GNSS init successful\n");356	} else {357		ice_gnss_exit(pf);358		dev_err(ice_pf_to_dev(pf), "GNSS init failure\n");359	}360}361 362/**363 * ice_gnss_exit - Disable GNSS TTY support364 * @pf: Board private structure365 */366void ice_gnss_exit(struct ice_pf *pf)367{368	ice_gnss_deregister(pf);369	clear_bit(ICE_FLAG_GNSS, pf->flags);370 371	if (pf->gnss_serial) {372		struct gnss_serial *gnss = pf->gnss_serial;373 374		kthread_cancel_delayed_work_sync(&gnss->read_work);375		kthread_destroy_worker(gnss->kworker);376		gnss->kworker = NULL;377 378		kfree(gnss);379		pf->gnss_serial = NULL;380	}381}382 383/**384 * ice_gnss_is_gps_present - Check if GPS HW is present385 * @hw: pointer to HW struct386 */387bool ice_gnss_is_gps_present(struct ice_hw *hw)388{389	if (!hw->func_caps.ts_func_info.src_tmr_owned)390		return false;391 392	if (!ice_is_gps_in_netlist(hw))393		return false;394 395#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)396	if (ice_is_e810t(hw)) {397		int err;398		u8 data;399 400		err = ice_read_pca9575_reg_e810t(hw, ICE_PCA9575_P0_IN, &data);401		if (err || !!(data & ICE_E810T_P0_GNSS_PRSNT_N))402			return false;403	} else {404		return false;405	}406#else407	if (!ice_is_e810t(hw))408		return false;409#endif /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */410 411	return true;412}413