Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/hid/amd-sfh-hid/sfh1_1/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 11 kB image not shown  

Quelle  amd_sfh_init.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * AMD MP2 1.1 communication driver
 *
 * Copyright (c) 2022, Advanced Micro Devices, Inc.
 * All Rights Reserved.
 *
 * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
 */


#include <linux/delay.h>
#include <linux/hid.h>

#include "amd_sfh_init.h"
#include "amd_sfh_interface.h"
#include "../hid_descriptor/amd_sfh_hid_desc.h"

static int amd_sfh_get_sensor_num(struct amd_mp2_dev *mp2, u8 *sensor_id)
{
 struct sfh_sensor_list *slist;
 struct sfh_base_info binfo;
 int num_of_sensors = 0;
 int i;

 memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info));
 slist = &binfo.sbase.s_list;

 for (i = 0; i < MAX_IDX; i++) {
  switch (i) {
  case ACCEL_IDX:
  case GYRO_IDX:
  case MAG_IDX:
  case SRA_IDX:
  case ALS_IDX:
  case HPD_IDX:
   if (BIT(i) & slist->sl.sensors)
    sensor_id[num_of_sensors++] = i;
   break;
  }
 }

 return num_of_sensors;
}

static u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id)
{
 if (mp2->mp2_ops->response)
  return mp2->mp2_ops->response(mp2, sid, cmd_id);

 return 0;
}

static const char *get_sensor_name(int idx)
{
 switch (idx) {
 case ACCEL_IDX:
  return "accelerometer";
 case GYRO_IDX:
  return "gyroscope";
 case MAG_IDX:
  return "magnetometer";
 case SRA_IDX:
  return "SRA";
 case ALS_IDX:
  return "ALS";
 case HPD_IDX:
  return "HPD";
 default:
  return "unknown sensor type";
 }
}

static int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)
{
 struct amdtp_cl_data *cl_data = privdata->cl_data;
 int i, status;

 for (i = 0; i < cl_data->num_hid_devices; i++) {
  switch (cl_data->sensor_idx[i]) {
  case HPD_IDX:
   privdata->dev_en.is_hpd_present = false;
   break;
  case ALS_IDX:
   privdata->dev_en.is_als_present = false;
   break;
  case SRA_IDX:
   privdata->dev_en.is_sra_present = false;
   break;
  }

  if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
   privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]);
   status = amd_sfh_wait_for_response
     (privdata, cl_data->sensor_idx[i], DISABLE_SENSOR);
   if (status == 0)
    cl_data->sensor_sts[i] = SENSOR_DISABLED;
   dev_dbg(&privdata->pdev->dev, "stopping sid 0x%x (%s) status 0x%x\n",
    cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
    cl_data->sensor_sts[i]);
  }
 }

 cancel_delayed_work_sync(&cl_data->work);
 cancel_delayed_work_sync(&cl_data->work_buffer);
 amdtp_hid_remove(cl_data);

 return 0;
}

static int amd_sfh1_1_hid_client_init(struct amd_mp2_dev *privdata)
{
 struct amd_input_data *in_data = &privdata->in_data;
 struct amdtp_cl_data *cl_data = privdata->cl_data;
 struct amd_mp2_ops *mp2_ops = privdata->mp2_ops;
 struct amd_mp2_sensor_info info;
 struct request_list *req_list;
 u32 feature_report_size;
 u32 input_report_size;
 struct device *dev;
 int rc, i, status;
 u8 cl_idx;

 req_list = &cl_data->req_list;
 dev = &privdata->pdev->dev;
 amd_sfh1_1_set_desc_ops(mp2_ops);

 cl_data->num_hid_devices = amd_sfh_get_sensor_num(privdata, &cl_data->sensor_idx[0]);
 if (cl_data->num_hid_devices == 0)
  return -ENODEV;
 cl_data->is_any_sensor_enabled = false;

 INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work);
 INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer);
 INIT_LIST_HEAD(&req_list->list);
 cl_data->in_data = in_data;

 for (i = 0; i < cl_data->num_hid_devices; i++) {
  cl_data->sensor_sts[i] = SENSOR_DISABLED;

  if (cl_data->sensor_idx[i] == SRA_IDX) {
   info.sensor_idx = cl_data->sensor_idx[i];
   writel(0, privdata->mmio + amd_get_p2c_val(privdata, 0));
   mp2_ops->start(privdata, info);
   status = amd_sfh_wait_for_response
    (privdata, cl_data->sensor_idx[i], ENABLE_SENSOR);

   cl_data->sensor_sts[i] = (status == 0) ? SENSOR_ENABLED : SENSOR_DISABLED;
   if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
    cl_data->is_any_sensor_enabled = true;
    privdata->dev_en.is_sra_present = true;
   }
   continue;
  }

  cl_data->sensor_requested_cnt[i] = 0;
  cl_data->cur_hid_dev = i;
  cl_idx = cl_data->sensor_idx[i];

  cl_data->report_descr_sz[i] = mp2_ops->get_desc_sz(cl_idx, descr_size);
  if (!cl_data->report_descr_sz[i]) {
   rc = -EINVAL;
   goto cleanup;
  }
  feature_report_size = mp2_ops->get_desc_sz(cl_idx, feature_size);
  if (!feature_report_size) {
   rc = -EINVAL;
   goto cleanup;
  }
  input_report_size =  mp2_ops->get_desc_sz(cl_idx, input_size);
  if (!input_report_size) {
   rc = -EINVAL;
   goto cleanup;
  }
  cl_data->feature_report[i] = devm_kzalloc(dev, feature_report_size, GFP_KERNEL);
  if (!cl_data->feature_report[i]) {
   rc = -ENOMEM;
   goto cleanup;
  }
  in_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL);
  if (!in_data->input_report[i]) {
   rc = -ENOMEM;
   goto cleanup;
  }

  info.sensor_idx = cl_idx;

  cl_data->report_descr[i] =
   devm_kzalloc(dev, cl_data->report_descr_sz[i], GFP_KERNEL);
  if (!cl_data->report_descr[i]) {
   rc = -ENOMEM;
   goto cleanup;
  }
  rc = mp2_ops->get_rep_desc(cl_idx, cl_data->report_descr[i]);
  if (rc)
   goto cleanup;

  writel(0, privdata->mmio + amd_get_p2c_val(privdata, 0));
  mp2_ops->start(privdata, info);
  status = amd_sfh_wait_for_response
    (privdata, cl_data->sensor_idx[i], ENABLE_SENSOR);

  cl_data->sensor_sts[i] = (status == 0) ? SENSOR_ENABLED : SENSOR_DISABLED;
 }

 for (i = 0; i < cl_data->num_hid_devices; i++) {
  if (cl_data->sensor_idx[i] == SRA_IDX)
   continue;
  cl_data->cur_hid_dev = i;
  if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
   cl_data->is_any_sensor_enabled = true;
   rc = amdtp_hid_probe(i, cl_data);
   if (rc)
    goto cleanup;
   switch (cl_data->sensor_idx[i]) {
   case HPD_IDX:
    privdata->dev_en.is_hpd_present = true;
    privdata->dev_en.is_hpd_enabled = true;
    amd_sfh_toggle_hpd(privdata, false);
    break;
   case ALS_IDX:
    privdata->dev_en.is_als_present = true;
    break;
   }
  }
  dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n",
   cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
   cl_data->sensor_sts[i]);
 }

 if (!cl_data->is_any_sensor_enabled) {
  dev_warn(dev, "No sensor registered, sensors not enabled is %d\n",
    cl_data->is_any_sensor_enabled);
  rc = -EOPNOTSUPP;
  goto cleanup;
 }

 schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
 return 0;

cleanup:
 amd_sfh_hid_client_deinit(privdata);
 for (i = 0; i < cl_data->num_hid_devices; i++) {
  if (cl_data->sensor_idx[i] == SRA_IDX)
   continue;
  devm_kfree(dev, cl_data->feature_report[i]);
  devm_kfree(dev, in_data->input_report[i]);
  devm_kfree(dev, cl_data->report_descr[i]);
 }
 return rc;
}

static void amd_sfh_resume(struct amd_mp2_dev *mp2)
{
 struct amdtp_cl_data *cl_data = mp2->cl_data;
 struct amd_mp2_sensor_info info;
 int i, status;

 if (!cl_data->is_any_sensor_enabled) {
  amd_sfh_clear_intr(mp2);
  return;
 }

 for (i = 0; i < cl_data->num_hid_devices; i++) {
  /* leave HPD alone; policy is controlled by sysfs */
  if (cl_data->sensor_idx[i] == HPD_IDX)
   continue;

  if (cl_data->sensor_sts[i] == SENSOR_DISABLED) {
   info.sensor_idx = cl_data->sensor_idx[i];
   mp2->mp2_ops->start(mp2, info);
   status = amd_sfh_wait_for_response
     (mp2, cl_data->sensor_idx[i], ENABLE_SENSOR);
   if (status == 0)
    status = SENSOR_ENABLED;
   if (status == SENSOR_ENABLED)
    cl_data->sensor_sts[i] = SENSOR_ENABLED;
   dev_dbg(&mp2->pdev->dev, "resume sid 0x%x (%s) status 0x%x\n",
    cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
    cl_data->sensor_sts[i]);
  }
 }

 schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
 amd_sfh_clear_intr(mp2);
}

static void amd_sfh_suspend(struct amd_mp2_dev *mp2)
{
 struct amdtp_cl_data *cl_data = mp2->cl_data;
 int i, status;

 if (!cl_data->is_any_sensor_enabled) {
  amd_sfh_clear_intr(mp2);
  return;
 }

 for (i = 0; i < cl_data->num_hid_devices; i++) {
  /* leave HPD alone; policy is controlled by sysfs */
  if (cl_data->sensor_idx[i] == HPD_IDX)
   continue;
  if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
   mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]);
   status = amd_sfh_wait_for_response
     (mp2, cl_data->sensor_idx[i], DISABLE_SENSOR);
   if (status == 0)
    status = SENSOR_DISABLED;
   if (status != SENSOR_ENABLED)
    cl_data->sensor_sts[i] = SENSOR_DISABLED;
   dev_dbg(&mp2->pdev->dev, "suspend sid 0x%x (%s) status 0x%x\n",
    cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
    cl_data->sensor_sts[i]);
  }
 }

 cancel_delayed_work_sync(&cl_data->work_buffer);
 amd_sfh_clear_intr(mp2);
}

void amd_sfh_toggle_hpd(struct amd_mp2_dev *mp2, bool enabled)
{
 struct amdtp_cl_data *cl_data = mp2->cl_data;
 struct amd_mp2_sensor_info info;
 int i, status;

 if (mp2->dev_en.is_hpd_enabled == enabled)
  return;

 for (i = 0; i < cl_data->num_hid_devices; i++) {
  if (cl_data->sensor_idx[i] != HPD_IDX)
   continue;
  info.sensor_idx = cl_data->sensor_idx[i];
  if (enabled) {
   mp2->mp2_ops->start(mp2, info);
   status = amd_sfh_wait_for_response
     (mp2, cl_data->sensor_idx[i], ENABLE_SENSOR);
   if (status == 0)
    status = SENSOR_ENABLED;
   if (status == SENSOR_ENABLED)
    cl_data->sensor_sts[i] = SENSOR_ENABLED;
  } else {
   mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]);
   status = amd_sfh_wait_for_response
     (mp2, cl_data->sensor_idx[i], DISABLE_SENSOR);
   if (status == 0)
    status = SENSOR_DISABLED;
   if (status != SENSOR_ENABLED)
    cl_data->sensor_sts[i] = SENSOR_DISABLED;
  }
  dev_dbg(&mp2->pdev->dev, "toggle sid 0x%x (%s) status 0x%x\n",
   cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
   cl_data->sensor_sts[i]);
  break;
 }
 mp2->dev_en.is_hpd_enabled = enabled;
}

static void amd_mp2_pci_remove(void *privdata)
{
 struct amd_mp2_dev *mp2 = privdata;

 sfh_deinit_emp2();
 amd_sfh_hid_client_deinit(privdata);
 mp2->mp2_ops->stop_all(mp2);
 pcim_intx(mp2->pdev, false);
 amd_sfh_clear_intr(mp2);
}

static void amd_sfh_set_ops(struct amd_mp2_dev *mp2)
{
 struct amd_mp2_ops *mp2_ops;

 sfh_interface_init(mp2);
 mp2_ops = mp2->mp2_ops;
 mp2_ops->clear_intr = amd_sfh_clear_intr_v2;
 mp2_ops->init_intr = amd_sfh_irq_init_v2;
 mp2_ops->suspend = amd_sfh_suspend;
 mp2_ops->resume = amd_sfh_resume;
 mp2_ops->remove = amd_mp2_pci_remove;
}

int amd_sfh1_1_init(struct amd_mp2_dev *mp2)
{
 u32 phy_base = readl(mp2->mmio + amd_get_c2p_val(mp2, 22));
 struct device *dev = &mp2->pdev->dev;
 struct sfh_base_info binfo;
 int rc;

 phy_base <<= 21;
 if (!devm_request_mem_region(dev, phy_base, 128 * 1024, "amd_sfh")) {
  dev_dbg(dev, "can't reserve mmio registers\n");
  return -ENOMEM;
 }

 mp2->vsbase = devm_ioremap(dev, phy_base, 128 * 1024);
 if (!mp2->vsbase) {
  dev_dbg(dev, "failed to remap vsbase\n");
  return -ENOMEM;
 }

 /* Before accessing give time for SFH firmware for processing configuration */
 msleep(5000);

 memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info));
 if (binfo.sbase.fw_info.fw_ver == 0 || binfo.sbase.s_list.sl.sensors == 0) {
  dev_dbg(dev, "No sensor registered\n");
  return -EOPNOTSUPP;
 }
 dev_dbg(dev, "firmware version 0x%x\n", binfo.sbase.fw_info.fw_ver);

 amd_sfh_set_ops(mp2);

 rc = amd_sfh_irq_init(mp2);
 if (rc) {
  sfh_deinit_emp2();
  dev_err(dev, "amd_sfh_irq_init failed\n");
  return rc;
 }

 rc = amd_sfh1_1_hid_client_init(mp2);
 if (rc) {
  sfh_deinit_emp2();
  if ((rc != -ENODEV) && (rc != -EOPNOTSUPP))
   dev_err(dev, "amd_sfh1_1_hid_client_init failed\n");
  return rc;
 }

 return rc;
}

Messung V0.5
C=98 H=96 G=96

¤ Dauer der Verarbeitung: 0.6 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.