Path: blob/master/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
26285 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* AMD MP2 1.1 communication interfaces3*4* Copyright (c) 2022, Advanced Micro Devices, Inc.5* All Rights Reserved.6*7* Author: Basavaraj Natikar <[email protected]>8*/9#include <linux/amd-pmf-io.h>10#include <linux/io-64-nonatomic-lo-hi.h>11#include <linux/iopoll.h>1213#include "amd_sfh_interface.h"1415static struct amd_mp2_dev *emp2;1617static int amd_sfh_wait_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id)18{19struct sfh_cmd_response cmd_resp;2021/* Get response with status within a max of 10000 ms timeout */22if (!readl_poll_timeout(mp2->mmio + amd_get_p2c_val(mp2, 0), cmd_resp.resp,23(cmd_resp.response.response == 0 &&24cmd_resp.response.cmd_id == cmd_id && (sid == 0xff ||25cmd_resp.response.sensor_id == sid)), 500, 10000000))26return cmd_resp.response.response;2728return -1;29}3031static void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)32{33struct sfh_cmd_base cmd_base;3435cmd_base.ul = 0;36cmd_base.cmd.cmd_id = ENABLE_SENSOR;37cmd_base.cmd.intr_disable = 0;38cmd_base.cmd.sub_cmd_value = 1;39cmd_base.cmd.sensor_id = info.sensor_idx;4041writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));42}4344static void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx)45{46struct sfh_cmd_base cmd_base;4748cmd_base.ul = 0;49cmd_base.cmd.cmd_id = DISABLE_SENSOR;50cmd_base.cmd.intr_disable = 0;51cmd_base.cmd.sub_cmd_value = 1;52cmd_base.cmd.sensor_id = sensor_idx;5354writeq(0x0, privdata->mmio + amd_get_c2p_val(privdata, 1));55writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));56}5758static void amd_stop_all_sensor(struct amd_mp2_dev *privdata)59{60struct sfh_cmd_base cmd_base;6162cmd_base.ul = 0;63cmd_base.cmd.cmd_id = DISABLE_SENSOR;64cmd_base.cmd.intr_disable = 0;65/* 0xf indicates all sensors */66cmd_base.cmd.sensor_id = 0xf;6768writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));69}7071static struct amd_mp2_ops amd_sfh_ops = {72.start = amd_start_sensor,73.stop = amd_stop_sensor,74.stop_all = amd_stop_all_sensor,75.response = amd_sfh_wait_response,76};7778void sfh_deinit_emp2(void)79{80emp2 = NULL;81}8283void sfh_interface_init(struct amd_mp2_dev *mp2)84{85mp2->mp2_ops = &amd_sfh_ops;86emp2 = mp2;87}8889static int amd_sfh_mode_info(u32 *platform_type, u32 *laptop_placement)90{91struct sfh_op_mode mode;9293if (!platform_type || !laptop_placement)94return -EINVAL;9596if (!emp2 || !emp2->dev_en.is_sra_present)97return -ENODEV;9899mode.val = readl(emp2->mmio + amd_get_c2p_val(emp2, 3));100101*platform_type = mode.op_mode.devicemode;102103if (mode.op_mode.ontablestate == 1) {104*laptop_placement = ON_TABLE;105} else if (mode.op_mode.ontablestate == 2) {106*laptop_placement = ON_LAP_MOTION;107} else if (mode.op_mode.inbagstate == 1) {108*laptop_placement = IN_BAG;109} else if (mode.op_mode.outbagstate == 1) {110*laptop_placement = OUT_OF_BAG;111} else if (mode.op_mode.ontablestate == 0 || mode.op_mode.inbagstate == 0 ||112mode.op_mode.outbagstate == 0) {113*laptop_placement = LP_UNKNOWN;114pr_warn_once("Unknown laptop placement\n");115} else if (mode.op_mode.ontablestate == 3 || mode.op_mode.inbagstate == 3 ||116mode.op_mode.outbagstate == 3) {117*laptop_placement = LP_UNDEFINED;118pr_warn_once("Undefined laptop placement\n");119}120121return 0;122}123124static int amd_sfh_hpd_info(u8 *user_present)125{126struct hpd_status hpdstatus;127128if (!user_present)129return -EINVAL;130131if (!emp2 || !emp2->dev_en.is_hpd_present || !emp2->dev_en.is_hpd_enabled)132return -ENODEV;133134hpdstatus.val = readl(emp2->mmio + amd_get_c2p_val(emp2, 4));135*user_present = hpdstatus.shpd.presence;136137return 0;138}139140static int amd_sfh_als_info(u32 *ambient_light)141{142struct sfh_als_data als_data;143void __iomem *sensoraddr;144145if (!ambient_light)146return -EINVAL;147148if (!emp2 || !emp2->dev_en.is_als_present)149return -ENODEV;150151sensoraddr = emp2->vsbase +152(ALS_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) +153OFFSET_SENSOR_DATA_DEFAULT;154memcpy_fromio(&als_data, sensoraddr, sizeof(struct sfh_als_data));155*ambient_light = amd_sfh_float_to_int(als_data.lux);156157return 0;158}159160int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum sfh_message_type op)161{162if (sfh_info) {163switch (op) {164case MT_HPD:165return amd_sfh_hpd_info(&sfh_info->user_present);166case MT_ALS:167return amd_sfh_als_info(&sfh_info->ambient_light);168case MT_SRA:169return amd_sfh_mode_info(&sfh_info->platform_type,170&sfh_info->laptop_placement);171}172}173return -EINVAL;174}175EXPORT_SYMBOL_GPL(amd_get_sfh_info);176177178