667 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2014, Samsung Electronics Co. Ltd. All Rights Reserved.4 */5 6#include <linux/iio/iio.h>7#include <linux/interrupt.h>8#include <linux/io.h>9#include <linux/mfd/core.h>10#include <linux/mod_devicetable.h>11#include <linux/module.h>12#include <linux/property.h>13 14#include "ssp.h"15 16#define SSP_WDT_TIME 1000017#define SSP_LIMIT_RESET_CNT 2018#define SSP_LIMIT_TIMEOUT_CNT 319 20/* It is possible that it is max clk rate for version 1.0 of bootcode */21#define SSP_BOOT_SPI_HZ 40000022 23/*24 * These fields can look enigmatic but this structure is used mainly to flat25 * some values and depends on command type.26 */27struct ssp_instruction {28 __le32 a;29 __le32 b;30 u8 c;31} __attribute__((__packed__));32 33static const u8 ssp_magnitude_table[] = {110, 85, 171, 71, 203, 195, 0, 67,34 208, 56, 175, 244, 206, 213, 0, 92, 250, 0, 55, 48, 189, 252, 171,35 243, 13, 45, 250};36 37static const struct ssp_sensorhub_info ssp_rinato_info = {38 .fw_name = "ssp_B2.fw",39 .fw_crashed_name = "ssp_crashed.fw",40 .fw_rev = 14052300,41 .mag_table = ssp_magnitude_table,42 .mag_length = ARRAY_SIZE(ssp_magnitude_table),43};44 45static const struct ssp_sensorhub_info ssp_thermostat_info = {46 .fw_name = "thermostat_B2.fw",47 .fw_crashed_name = "ssp_crashed.fw",48 .fw_rev = 14080600,49 .mag_table = ssp_magnitude_table,50 .mag_length = ARRAY_SIZE(ssp_magnitude_table),51};52 53static const struct mfd_cell sensorhub_sensor_devs[] = {54 {55 .name = "ssp-accelerometer",56 },57 {58 .name = "ssp-gyroscope",59 },60};61 62static void ssp_toggle_mcu_reset_gpio(struct ssp_data *data)63{64 gpiod_set_value(data->mcu_reset_gpiod, 0);65 usleep_range(1000, 1200);66 gpiod_set_value(data->mcu_reset_gpiod, 1);67 msleep(50);68}69 70static void ssp_sync_available_sensors(struct ssp_data *data)71{72 int i, ret;73 74 for (i = 0; i < SSP_SENSOR_MAX; ++i) {75 if (data->available_sensors & BIT(i)) {76 ret = ssp_enable_sensor(data, i, data->delay_buf[i]);77 if (ret < 0) {78 dev_err(&data->spi->dev,79 "Sync sensor nr: %d fail\n", i);80 continue;81 }82 }83 }84 85 ret = ssp_command(data, SSP_MSG2SSP_AP_MCU_SET_DUMPMODE,86 data->mcu_dump_mode);87 if (ret < 0)88 dev_err(&data->spi->dev,89 "SSP_MSG2SSP_AP_MCU_SET_DUMPMODE failed\n");90}91 92static void ssp_enable_mcu(struct ssp_data *data, bool enable)93{94 dev_info(&data->spi->dev, "current shutdown = %d, old = %d\n", enable,95 data->shut_down);96 97 if (enable && data->shut_down) {98 data->shut_down = false;99 enable_irq(data->spi->irq);100 enable_irq_wake(data->spi->irq);101 } else if (!enable && !data->shut_down) {102 data->shut_down = true;103 disable_irq(data->spi->irq);104 disable_irq_wake(data->spi->irq);105 } else {106 dev_warn(&data->spi->dev, "current shutdown = %d, old = %d\n",107 enable, data->shut_down);108 }109}110 111/*112 * This function is the first one which communicates with the mcu so it is113 * possible that the first attempt will fail114 */115static int ssp_check_fwbl(struct ssp_data *data)116{117 int retries = 0;118 119 while (retries++ < 5) {120 data->cur_firm_rev = ssp_get_firmware_rev(data);121 if (data->cur_firm_rev == SSP_INVALID_REVISION ||122 data->cur_firm_rev == SSP_INVALID_REVISION2) {123 dev_warn(&data->spi->dev,124 "Invalid revision, trying %d time\n", retries);125 } else {126 break;127 }128 }129 130 if (data->cur_firm_rev == SSP_INVALID_REVISION ||131 data->cur_firm_rev == SSP_INVALID_REVISION2) {132 dev_err(&data->spi->dev, "SSP_INVALID_REVISION\n");133 return SSP_FW_DL_STATE_NEED_TO_SCHEDULE;134 }135 136 dev_info(&data->spi->dev,137 "MCU Firm Rev : Old = %8u, New = %8u\n",138 data->cur_firm_rev,139 data->sensorhub_info->fw_rev);140 141 if (data->cur_firm_rev != data->sensorhub_info->fw_rev)142 return SSP_FW_DL_STATE_NEED_TO_SCHEDULE;143 144 return SSP_FW_DL_STATE_NONE;145}146 147static void ssp_reset_mcu(struct ssp_data *data)148{149 ssp_enable_mcu(data, false);150 ssp_clean_pending_list(data);151 ssp_toggle_mcu_reset_gpio(data);152 ssp_enable_mcu(data, true);153}154 155static void ssp_wdt_work_func(struct work_struct *work)156{157 struct ssp_data *data = container_of(work, struct ssp_data, work_wdt);158 159 dev_err(&data->spi->dev, "%s - Sensor state: 0x%x, RC: %u, CC: %u\n",160 __func__, data->available_sensors, data->reset_cnt,161 data->com_fail_cnt);162 163 ssp_reset_mcu(data);164 data->com_fail_cnt = 0;165 data->timeout_cnt = 0;166}167 168static void ssp_wdt_timer_func(struct timer_list *t)169{170 struct ssp_data *data = from_timer(data, t, wdt_timer);171 172 switch (data->fw_dl_state) {173 case SSP_FW_DL_STATE_FAIL:174 case SSP_FW_DL_STATE_DOWNLOADING:175 case SSP_FW_DL_STATE_SYNC:176 goto _mod;177 }178 179 if (data->timeout_cnt > SSP_LIMIT_TIMEOUT_CNT ||180 data->com_fail_cnt > SSP_LIMIT_RESET_CNT)181 queue_work(system_power_efficient_wq, &data->work_wdt);182_mod:183 mod_timer(&data->wdt_timer, jiffies + msecs_to_jiffies(SSP_WDT_TIME));184}185 186static void ssp_enable_wdt_timer(struct ssp_data *data)187{188 mod_timer(&data->wdt_timer, jiffies + msecs_to_jiffies(SSP_WDT_TIME));189}190 191static void ssp_disable_wdt_timer(struct ssp_data *data)192{193 del_timer_sync(&data->wdt_timer);194 cancel_work_sync(&data->work_wdt);195}196 197/**198 * ssp_get_sensor_delay() - gets sensor data acquisition period199 * @data: sensorhub structure200 * @type: SSP sensor type201 *202 * Returns acquisition period in ms203 */204u32 ssp_get_sensor_delay(struct ssp_data *data, enum ssp_sensor_type type)205{206 return data->delay_buf[type];207}208EXPORT_SYMBOL_NS(ssp_get_sensor_delay, IIO_SSP_SENSORS);209 210/**211 * ssp_enable_sensor() - enables data acquisition for sensor212 * @data: sensorhub structure213 * @type: SSP sensor type214 * @delay: delay in ms215 *216 * Returns 0 or negative value in case of error217 */218int ssp_enable_sensor(struct ssp_data *data, enum ssp_sensor_type type,219 u32 delay)220{221 int ret;222 struct ssp_instruction to_send;223 224 to_send.a = cpu_to_le32(delay);225 to_send.b = cpu_to_le32(data->batch_latency_buf[type]);226 to_send.c = data->batch_opt_buf[type];227 228 switch (data->check_status[type]) {229 case SSP_INITIALIZATION_STATE:230 /* do calibration step, now just enable */231 case SSP_ADD_SENSOR_STATE:232 ret = ssp_send_instruction(data,233 SSP_MSG2SSP_INST_BYPASS_SENSOR_ADD,234 type,235 (u8 *)&to_send, sizeof(to_send));236 if (ret < 0) {237 dev_err(&data->spi->dev, "Enabling sensor failed\n");238 data->check_status[type] = SSP_NO_SENSOR_STATE;239 goto derror;240 }241 242 data->sensor_enable |= BIT(type);243 data->check_status[type] = SSP_RUNNING_SENSOR_STATE;244 break;245 case SSP_RUNNING_SENSOR_STATE:246 ret = ssp_send_instruction(data,247 SSP_MSG2SSP_INST_CHANGE_DELAY, type,248 (u8 *)&to_send, sizeof(to_send));249 if (ret < 0) {250 dev_err(&data->spi->dev,251 "Changing sensor delay failed\n");252 goto derror;253 }254 break;255 default:256 data->check_status[type] = SSP_ADD_SENSOR_STATE;257 break;258 }259 260 data->delay_buf[type] = delay;261 262 if (atomic_inc_return(&data->enable_refcount) == 1)263 ssp_enable_wdt_timer(data);264 265 return 0;266 267derror:268 return ret;269}270EXPORT_SYMBOL_NS(ssp_enable_sensor, IIO_SSP_SENSORS);271 272/**273 * ssp_change_delay() - changes data acquisition for sensor274 * @data: sensorhub structure275 * @type: SSP sensor type276 * @delay: delay in ms277 *278 * Returns 0 or negative value in case of error279 */280int ssp_change_delay(struct ssp_data *data, enum ssp_sensor_type type,281 u32 delay)282{283 int ret;284 struct ssp_instruction to_send;285 286 to_send.a = cpu_to_le32(delay);287 to_send.b = cpu_to_le32(data->batch_latency_buf[type]);288 to_send.c = data->batch_opt_buf[type];289 290 ret = ssp_send_instruction(data, SSP_MSG2SSP_INST_CHANGE_DELAY, type,291 (u8 *)&to_send, sizeof(to_send));292 if (ret < 0) {293 dev_err(&data->spi->dev, "Changing sensor delay failed\n");294 return ret;295 }296 297 data->delay_buf[type] = delay;298 299 return 0;300}301EXPORT_SYMBOL_NS(ssp_change_delay, IIO_SSP_SENSORS);302 303/**304 * ssp_disable_sensor() - disables sensor305 *306 * @data: sensorhub structure307 * @type: SSP sensor type308 *309 * Returns 0 or negative value in case of error310 */311int ssp_disable_sensor(struct ssp_data *data, enum ssp_sensor_type type)312{313 int ret;314 __le32 command;315 316 if (data->sensor_enable & BIT(type)) {317 command = cpu_to_le32(data->delay_buf[type]);318 319 ret = ssp_send_instruction(data,320 SSP_MSG2SSP_INST_BYPASS_SENSOR_RM,321 type, (u8 *)&command,322 sizeof(command));323 if (ret < 0) {324 dev_err(&data->spi->dev, "Remove sensor fail\n");325 return ret;326 }327 328 data->sensor_enable &= ~BIT(type);329 }330 331 data->check_status[type] = SSP_ADD_SENSOR_STATE;332 333 if (atomic_dec_and_test(&data->enable_refcount))334 ssp_disable_wdt_timer(data);335 336 return 0;337}338EXPORT_SYMBOL_NS(ssp_disable_sensor, IIO_SSP_SENSORS);339 340static irqreturn_t ssp_irq_thread_fn(int irq, void *dev_id)341{342 struct ssp_data *data = dev_id;343 344 /*345 * This wrapper is done to preserve error path for ssp_irq_msg, also346 * it is defined in different file.347 */348 ssp_irq_msg(data);349 350 return IRQ_HANDLED;351}352 353static int ssp_initialize_mcu(struct ssp_data *data)354{355 int ret;356 357 ssp_clean_pending_list(data);358 359 ret = ssp_get_chipid(data);360 if (ret != SSP_DEVICE_ID) {361 dev_err(&data->spi->dev, "%s - MCU %s ret = %d\n", __func__,362 ret < 0 ? "is not working" : "identification failed",363 ret);364 return ret < 0 ? ret : -ENODEV;365 }366 367 dev_info(&data->spi->dev, "MCU device ID = %d\n", ret);368 369 /*370 * needs clarification, for now do not want to export all transfer371 * methods to sensors' drivers372 */373 ret = ssp_set_magnetic_matrix(data);374 if (ret < 0) {375 dev_err(&data->spi->dev,376 "%s - ssp_set_magnetic_matrix failed\n", __func__);377 return ret;378 }379 380 data->available_sensors = ssp_get_sensor_scanning_info(data);381 if (data->available_sensors == 0) {382 dev_err(&data->spi->dev,383 "%s - ssp_get_sensor_scanning_info failed\n", __func__);384 return -EIO;385 }386 387 data->cur_firm_rev = ssp_get_firmware_rev(data);388 dev_info(&data->spi->dev, "MCU Firm Rev : New = %8u\n",389 data->cur_firm_rev);390 391 return ssp_command(data, SSP_MSG2SSP_AP_MCU_DUMP_CHECK, 0);392}393 394/*395 * sensorhub can request its reinitialization as some brutal and rare error396 * handling. It can be requested from the MCU.397 */398static void ssp_refresh_task(struct work_struct *work)399{400 struct ssp_data *data = container_of((struct delayed_work *)work,401 struct ssp_data, work_refresh);402 403 dev_info(&data->spi->dev, "refreshing\n");404 405 data->reset_cnt++;406 407 if (ssp_initialize_mcu(data) >= 0) {408 ssp_sync_available_sensors(data);409 if (data->last_ap_state != 0)410 ssp_command(data, data->last_ap_state, 0);411 412 if (data->last_resume_state != 0)413 ssp_command(data, data->last_resume_state, 0);414 415 data->timeout_cnt = 0;416 data->com_fail_cnt = 0;417 }418}419 420int ssp_queue_ssp_refresh_task(struct ssp_data *data, unsigned int delay)421{422 cancel_delayed_work_sync(&data->work_refresh);423 424 return queue_delayed_work(system_power_efficient_wq,425 &data->work_refresh,426 msecs_to_jiffies(delay));427}428 429static const struct of_device_id ssp_of_match[] = {430 {431 .compatible = "samsung,sensorhub-rinato",432 .data = &ssp_rinato_info,433 }, {434 .compatible = "samsung,sensorhub-thermostat",435 .data = &ssp_thermostat_info,436 },437 {},438};439MODULE_DEVICE_TABLE(of, ssp_of_match);440 441static struct ssp_data *ssp_parse_dt(struct device *dev)442{443 struct ssp_data *data;444 445 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);446 if (!data)447 return NULL;448 449 data->mcu_ap_gpiod = devm_gpiod_get(dev, "mcu-ap", GPIOD_IN);450 if (IS_ERR(data->mcu_ap_gpiod))451 return NULL;452 453 data->ap_mcu_gpiod = devm_gpiod_get(dev, "ap-mcu", GPIOD_OUT_HIGH);454 if (IS_ERR(data->ap_mcu_gpiod))455 return NULL;456 457 data->mcu_reset_gpiod = devm_gpiod_get(dev, "mcu-reset",458 GPIOD_OUT_HIGH);459 if (IS_ERR(data->mcu_reset_gpiod))460 return NULL;461 462 data->sensorhub_info = device_get_match_data(dev);463 464 dev_set_drvdata(dev, data);465 466 return data;467}468 469/**470 * ssp_register_consumer() - registers iio consumer in ssp framework471 *472 * @indio_dev: consumer iio device473 * @type: ssp sensor type474 */475void ssp_register_consumer(struct iio_dev *indio_dev, enum ssp_sensor_type type)476{477 struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);478 479 data->sensor_devs[type] = indio_dev;480}481EXPORT_SYMBOL_NS(ssp_register_consumer, IIO_SSP_SENSORS);482 483static int ssp_probe(struct spi_device *spi)484{485 int ret, i;486 struct ssp_data *data;487 488 data = ssp_parse_dt(&spi->dev);489 if (!data) {490 dev_err(&spi->dev, "Failed to find platform data\n");491 return -ENODEV;492 }493 494 ret = mfd_add_devices(&spi->dev, PLATFORM_DEVID_NONE,495 sensorhub_sensor_devs,496 ARRAY_SIZE(sensorhub_sensor_devs), NULL, 0, NULL);497 if (ret < 0) {498 dev_err(&spi->dev, "mfd add devices fail\n");499 return ret;500 }501 502 spi->mode = SPI_MODE_1;503 ret = spi_setup(spi);504 if (ret < 0) {505 dev_err(&spi->dev, "Failed to setup spi\n");506 return ret;507 }508 509 data->fw_dl_state = SSP_FW_DL_STATE_NONE;510 data->spi = spi;511 spi_set_drvdata(spi, data);512 513 mutex_init(&data->comm_lock);514 515 for (i = 0; i < SSP_SENSOR_MAX; ++i) {516 data->delay_buf[i] = SSP_DEFAULT_POLLING_DELAY;517 data->batch_latency_buf[i] = 0;518 data->batch_opt_buf[i] = 0;519 data->check_status[i] = SSP_INITIALIZATION_STATE;520 }521 522 data->delay_buf[SSP_BIO_HRM_LIB] = 100;523 524 data->time_syncing = true;525 526 mutex_init(&data->pending_lock);527 INIT_LIST_HEAD(&data->pending_list);528 529 atomic_set(&data->enable_refcount, 0);530 531 INIT_WORK(&data->work_wdt, ssp_wdt_work_func);532 INIT_DELAYED_WORK(&data->work_refresh, ssp_refresh_task);533 534 timer_setup(&data->wdt_timer, ssp_wdt_timer_func, 0);535 536 ret = request_threaded_irq(data->spi->irq, NULL,537 ssp_irq_thread_fn,538 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,539 "SSP_Int", data);540 if (ret < 0) {541 dev_err(&spi->dev, "Irq request fail\n");542 goto err_setup_irq;543 }544 545 /* Let's start with enabled one so irq balance could be ok */546 data->shut_down = false;547 548 /* just to avoid unbalanced irq set wake up */549 enable_irq_wake(data->spi->irq);550 551 data->fw_dl_state = ssp_check_fwbl(data);552 if (data->fw_dl_state == SSP_FW_DL_STATE_NONE) {553 ret = ssp_initialize_mcu(data);554 if (ret < 0) {555 dev_err(&spi->dev, "Initialize_mcu failed\n");556 goto err_read_reg;557 }558 } else {559 dev_err(&spi->dev, "Firmware version not supported\n");560 ret = -EPERM;561 goto err_read_reg;562 }563 564 return 0;565 566err_read_reg:567 free_irq(data->spi->irq, data);568err_setup_irq:569 mutex_destroy(&data->pending_lock);570 mutex_destroy(&data->comm_lock);571 572 dev_err(&spi->dev, "Probe failed!\n");573 574 return ret;575}576 577static void ssp_remove(struct spi_device *spi)578{579 struct ssp_data *data = spi_get_drvdata(spi);580 581 if (ssp_command(data, SSP_MSG2SSP_AP_STATUS_SHUTDOWN, 0) < 0)582 dev_err(&data->spi->dev,583 "SSP_MSG2SSP_AP_STATUS_SHUTDOWN failed\n");584 585 ssp_enable_mcu(data, false);586 ssp_disable_wdt_timer(data);587 588 ssp_clean_pending_list(data);589 590 free_irq(data->spi->irq, data);591 592 del_timer_sync(&data->wdt_timer);593 cancel_work_sync(&data->work_wdt);594 595 mutex_destroy(&data->comm_lock);596 mutex_destroy(&data->pending_lock);597 598 mfd_remove_devices(&spi->dev);599}600 601static int ssp_suspend(struct device *dev)602{603 int ret;604 struct ssp_data *data = spi_get_drvdata(to_spi_device(dev));605 606 data->last_resume_state = SSP_MSG2SSP_AP_STATUS_SUSPEND;607 608 if (atomic_read(&data->enable_refcount) > 0)609 ssp_disable_wdt_timer(data);610 611 ret = ssp_command(data, SSP_MSG2SSP_AP_STATUS_SUSPEND, 0);612 if (ret < 0) {613 dev_err(&data->spi->dev,614 "%s SSP_MSG2SSP_AP_STATUS_SUSPEND failed\n", __func__);615 616 ssp_enable_wdt_timer(data);617 return ret;618 }619 620 data->time_syncing = false;621 disable_irq(data->spi->irq);622 623 return 0;624}625 626static int ssp_resume(struct device *dev)627{628 int ret;629 struct ssp_data *data = spi_get_drvdata(to_spi_device(dev));630 631 enable_irq(data->spi->irq);632 633 if (atomic_read(&data->enable_refcount) > 0)634 ssp_enable_wdt_timer(data);635 636 ret = ssp_command(data, SSP_MSG2SSP_AP_STATUS_RESUME, 0);637 if (ret < 0) {638 dev_err(&data->spi->dev,639 "%s SSP_MSG2SSP_AP_STATUS_RESUME failed\n", __func__);640 ssp_disable_wdt_timer(data);641 return ret;642 }643 644 /* timesyncing is set by MCU */645 data->last_resume_state = SSP_MSG2SSP_AP_STATUS_RESUME;646 647 return 0;648}649 650static DEFINE_SIMPLE_DEV_PM_OPS(ssp_pm_ops, ssp_suspend, ssp_resume);651 652static struct spi_driver ssp_driver = {653 .probe = ssp_probe,654 .remove = ssp_remove,655 .driver = {656 .pm = pm_sleep_ptr(&ssp_pm_ops),657 .of_match_table = ssp_of_match,658 .name = "sensorhub"659 },660};661 662module_spi_driver(ssp_driver);663 664MODULE_DESCRIPTION("ssp sensorhub driver");665MODULE_AUTHOR("Samsung Electronics");666MODULE_LICENSE("GPL");667