ice_gnss.c (9328B)
1// SPDX-License-Identifier: GPL-2.0 2/* Copyright (C) 2018-2021, Intel Corporation. */ 3 4#include "ice.h" 5#include "ice_lib.h" 6#include <linux/tty_driver.h> 7 8/** 9 * ice_gnss_read - Read data from internal GNSS module 10 * @work: GNSS read work structure 11 * 12 * Read the data from internal GNSS receiver, number of bytes read will be 13 * returned in *read_data parameter. 14 */ 15static void ice_gnss_read(struct kthread_work *work) 16{ 17 struct gnss_serial *gnss = container_of(work, struct gnss_serial, 18 read_work.work); 19 struct ice_aqc_link_topo_addr link_topo; 20 u8 i2c_params, bytes_read; 21 struct tty_port *port; 22 struct ice_pf *pf; 23 struct ice_hw *hw; 24 __be16 data_len_b; 25 char *buf = NULL; 26 u16 i, data_len; 27 int err = 0; 28 29 pf = gnss->back; 30 if (!pf || !gnss->tty || !gnss->tty->port) { 31 err = -EFAULT; 32 goto exit; 33 } 34 35 hw = &pf->hw; 36 port = gnss->tty->port; 37 38 buf = (char *)get_zeroed_page(GFP_KERNEL); 39 if (!buf) { 40 err = -ENOMEM; 41 goto exit; 42 } 43 44 memset(&link_topo, 0, sizeof(struct ice_aqc_link_topo_addr)); 45 link_topo.topo_params.index = ICE_E810T_GNSS_I2C_BUS; 46 link_topo.topo_params.node_type_ctx |= 47 FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M, 48 ICE_AQC_LINK_TOPO_NODE_CTX_OVERRIDE); 49 50 i2c_params = ICE_GNSS_UBX_DATA_LEN_WIDTH | 51 ICE_AQC_I2C_USE_REPEATED_START; 52 53 /* Read data length in a loop, when it's not 0 the data is ready */ 54 for (i = 0; i < ICE_MAX_UBX_READ_TRIES; i++) { 55 err = ice_aq_read_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR, 56 cpu_to_le16(ICE_GNSS_UBX_DATA_LEN_H), 57 i2c_params, (u8 *)&data_len_b, NULL); 58 if (err) 59 goto exit_buf; 60 61 data_len = be16_to_cpu(data_len_b); 62 if (data_len != 0 && data_len != U16_MAX) 63 break; 64 65 mdelay(10); 66 } 67 68 data_len = min(data_len, (u16)PAGE_SIZE); 69 data_len = tty_buffer_request_room(port, data_len); 70 if (!data_len) { 71 err = -ENOMEM; 72 goto exit_buf; 73 } 74 75 /* Read received data */ 76 for (i = 0; i < data_len; i += bytes_read) { 77 u16 bytes_left = data_len - i; 78 79 bytes_read = min_t(typeof(bytes_left), bytes_left, ICE_MAX_I2C_DATA_SIZE); 80 81 err = ice_aq_read_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR, 82 cpu_to_le16(ICE_GNSS_UBX_EMPTY_DATA), 83 bytes_read, &buf[i], NULL); 84 if (err) 85 goto exit_buf; 86 } 87 88 /* Send the data to the tty layer for users to read. This doesn't 89 * actually push the data through unless tty->low_latency is set. 90 */ 91 tty_insert_flip_string(port, buf, i); 92 tty_flip_buffer_push(port); 93 94exit_buf: 95 free_page((unsigned long)buf); 96 kthread_queue_delayed_work(gnss->kworker, &gnss->read_work, 97 ICE_GNSS_TIMER_DELAY_TIME); 98exit: 99 if (err) 100 dev_dbg(ice_pf_to_dev(pf), "GNSS failed to read err=%d\n", err); 101} 102 103/** 104 * ice_gnss_struct_init - Initialize GNSS structure for the TTY 105 * @pf: Board private structure 106 */ 107static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf) 108{ 109 struct device *dev = ice_pf_to_dev(pf); 110 struct kthread_worker *kworker; 111 struct gnss_serial *gnss; 112 113 gnss = kzalloc(sizeof(*gnss), GFP_KERNEL); 114 if (!gnss) 115 return NULL; 116 117 mutex_init(&gnss->gnss_mutex); 118 gnss->open_count = 0; 119 gnss->back = pf; 120 pf->gnss_serial = gnss; 121 122 kthread_init_delayed_work(&gnss->read_work, ice_gnss_read); 123 /* Allocate a kworker for handling work required for the GNSS TTY 124 * writes. 125 */ 126 kworker = kthread_create_worker(0, "ice-gnss-%s", dev_name(dev)); 127 if (IS_ERR(kworker)) { 128 kfree(gnss); 129 return NULL; 130 } 131 132 gnss->kworker = kworker; 133 134 return gnss; 135} 136 137/** 138 * ice_gnss_tty_open - Initialize GNSS structures on TTY device open 139 * @tty: pointer to the tty_struct 140 * @filp: pointer to the file 141 * 142 * This routine is mandatory. If this routine is not filled in, the attempted 143 * open will fail with ENODEV. 144 */ 145static int ice_gnss_tty_open(struct tty_struct *tty, struct file *filp) 146{ 147 struct gnss_serial *gnss; 148 struct ice_pf *pf; 149 150 pf = (struct ice_pf *)tty->driver->driver_state; 151 if (!pf) 152 return -EFAULT; 153 154 /* Clear the pointer in case something fails */ 155 tty->driver_data = NULL; 156 157 /* Get the serial object associated with this tty pointer */ 158 gnss = pf->gnss_serial; 159 if (!gnss) { 160 /* Initialize GNSS struct on the first device open */ 161 gnss = ice_gnss_struct_init(pf); 162 if (!gnss) 163 return -ENOMEM; 164 } 165 166 mutex_lock(&gnss->gnss_mutex); 167 168 /* Save our structure within the tty structure */ 169 tty->driver_data = gnss; 170 gnss->tty = tty; 171 gnss->open_count++; 172 kthread_queue_delayed_work(gnss->kworker, &gnss->read_work, 0); 173 174 mutex_unlock(&gnss->gnss_mutex); 175 176 return 0; 177} 178 179/** 180 * ice_gnss_tty_close - Cleanup GNSS structures on tty device close 181 * @tty: pointer to the tty_struct 182 * @filp: pointer to the file 183 */ 184static void ice_gnss_tty_close(struct tty_struct *tty, struct file *filp) 185{ 186 struct gnss_serial *gnss = tty->driver_data; 187 struct ice_pf *pf; 188 189 if (!gnss) 190 return; 191 192 pf = (struct ice_pf *)tty->driver->driver_state; 193 if (!pf) 194 return; 195 196 mutex_lock(&gnss->gnss_mutex); 197 198 if (!gnss->open_count) { 199 /* Port was never opened */ 200 dev_err(ice_pf_to_dev(pf), "GNSS port not opened\n"); 201 goto exit; 202 } 203 204 gnss->open_count--; 205 if (gnss->open_count <= 0) { 206 /* Port is in shutdown state */ 207 kthread_cancel_delayed_work_sync(&gnss->read_work); 208 } 209exit: 210 mutex_unlock(&gnss->gnss_mutex); 211} 212 213/** 214 * ice_gnss_tty_write - Dummy TTY write function to avoid kernel panic 215 * @tty: pointer to the tty_struct 216 * @buf: pointer to the user data 217 * @cnt: the number of characters that was able to be sent to the hardware (or 218 * queued to be sent at a later time) 219 */ 220static int 221ice_gnss_tty_write(struct tty_struct *tty, const unsigned char *buf, int cnt) 222{ 223 return 0; 224} 225 226/** 227 * ice_gnss_tty_write_room - Dummy TTY write_room function to avoid kernel panic 228 * @tty: pointer to the tty_struct 229 */ 230static unsigned int ice_gnss_tty_write_room(struct tty_struct *tty) 231{ 232 return 0; 233} 234 235static const struct tty_operations tty_gps_ops = { 236 .open = ice_gnss_tty_open, 237 .close = ice_gnss_tty_close, 238 .write = ice_gnss_tty_write, 239 .write_room = ice_gnss_tty_write_room, 240}; 241 242/** 243 * ice_gnss_create_tty_driver - Create a TTY driver for GNSS 244 * @pf: Board private structure 245 */ 246static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf) 247{ 248 struct device *dev = ice_pf_to_dev(pf); 249 const int ICE_TTYDRV_NAME_MAX = 14; 250 struct tty_driver *tty_driver; 251 char *ttydrv_name; 252 int err; 253 254 tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW); 255 if (IS_ERR(tty_driver)) { 256 dev_err(ice_pf_to_dev(pf), "Failed to allocate memory for GNSS TTY\n"); 257 return NULL; 258 } 259 260 ttydrv_name = kzalloc(ICE_TTYDRV_NAME_MAX, GFP_KERNEL); 261 if (!ttydrv_name) { 262 tty_driver_kref_put(tty_driver); 263 return NULL; 264 } 265 266 snprintf(ttydrv_name, ICE_TTYDRV_NAME_MAX, "ttyGNSS_%02x%02x_", 267 (u8)pf->pdev->bus->number, (u8)PCI_SLOT(pf->pdev->devfn)); 268 269 /* Initialize the tty driver*/ 270 tty_driver->owner = THIS_MODULE; 271 tty_driver->driver_name = dev_driver_string(dev); 272 tty_driver->name = (const char *)ttydrv_name; 273 tty_driver->type = TTY_DRIVER_TYPE_SERIAL; 274 tty_driver->subtype = SERIAL_TYPE_NORMAL; 275 tty_driver->init_termios = tty_std_termios; 276 tty_driver->init_termios.c_iflag &= ~INLCR; 277 tty_driver->init_termios.c_iflag |= IGNCR; 278 tty_driver->init_termios.c_oflag &= ~OPOST; 279 tty_driver->init_termios.c_lflag &= ~ICANON; 280 tty_driver->init_termios.c_cflag &= ~(CSIZE | CBAUD | CBAUDEX); 281 /* baud rate 9600 */ 282 tty_termios_encode_baud_rate(&tty_driver->init_termios, 9600, 9600); 283 tty_driver->driver_state = pf; 284 tty_set_operations(tty_driver, &tty_gps_ops); 285 286 pf->gnss_serial = NULL; 287 288 tty_port_init(&pf->gnss_tty_port); 289 tty_port_link_device(&pf->gnss_tty_port, tty_driver, 0); 290 291 err = tty_register_driver(tty_driver); 292 if (err) { 293 dev_err(ice_pf_to_dev(pf), "Failed to register TTY driver err=%d\n", 294 err); 295 296 tty_port_destroy(&pf->gnss_tty_port); 297 kfree(ttydrv_name); 298 tty_driver_kref_put(pf->ice_gnss_tty_driver); 299 300 return NULL; 301 } 302 303 return tty_driver; 304} 305 306/** 307 * ice_gnss_init - Initialize GNSS TTY support 308 * @pf: Board private structure 309 */ 310void ice_gnss_init(struct ice_pf *pf) 311{ 312 struct tty_driver *tty_driver; 313 314 tty_driver = ice_gnss_create_tty_driver(pf); 315 if (!tty_driver) 316 return; 317 318 pf->ice_gnss_tty_driver = tty_driver; 319 320 set_bit(ICE_FLAG_GNSS, pf->flags); 321 dev_info(ice_pf_to_dev(pf), "GNSS TTY init successful\n"); 322} 323 324/** 325 * ice_gnss_exit - Disable GNSS TTY support 326 * @pf: Board private structure 327 */ 328void ice_gnss_exit(struct ice_pf *pf) 329{ 330 if (!test_bit(ICE_FLAG_GNSS, pf->flags) || !pf->ice_gnss_tty_driver) 331 return; 332 333 tty_port_destroy(&pf->gnss_tty_port); 334 335 if (pf->gnss_serial) { 336 struct gnss_serial *gnss = pf->gnss_serial; 337 338 kthread_cancel_delayed_work_sync(&gnss->read_work); 339 kfree(gnss); 340 pf->gnss_serial = NULL; 341 } 342 343 tty_unregister_driver(pf->ice_gnss_tty_driver); 344 kfree(pf->ice_gnss_tty_driver->name); 345 tty_driver_kref_put(pf->ice_gnss_tty_driver); 346 pf->ice_gnss_tty_driver = NULL; 347} 348 349/** 350 * ice_gnss_is_gps_present - Check if GPS HW is present 351 * @hw: pointer to HW struct 352 */ 353bool ice_gnss_is_gps_present(struct ice_hw *hw) 354{ 355 if (!hw->func_caps.ts_func_info.src_tmr_owned) 356 return false; 357 358#if IS_ENABLED(CONFIG_PTP_1588_CLOCK) 359 if (ice_is_e810t(hw)) { 360 int err; 361 u8 data; 362 363 err = ice_read_pca9575_reg_e810t(hw, ICE_PCA9575_P0_IN, &data); 364 if (err || !!(data & ICE_E810T_P0_GNSS_PRSNT_N)) 365 return false; 366 } else { 367 return false; 368 } 369#else 370 if (!ice_is_e810t(hw)) 371 return false; 372#endif /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */ 373 374 return true; 375}