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