Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * NCI based driver for Samsung S3FWRN5 NFC chip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2015 Samsung Electrnoics
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  * Robert Baldyga <r.baldyga@samsung.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/completion.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/firmware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include "s3fwrn5.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include "nci.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) static int s3fwrn5_nci_prop_rsp(struct nci_dev *ndev, struct sk_buff *skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 	__u8 status = skb->data[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) 	nci_req_complete(ndev, status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) static struct nci_driver_ops s3fwrn5_nci_prop_ops[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 		.opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 				NCI_PROP_AGAIN),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 		.rsp = s3fwrn5_nci_prop_rsp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 		.opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 				NCI_PROP_GET_RFREG),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 		.rsp = s3fwrn5_nci_prop_rsp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 		.opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 				NCI_PROP_SET_RFREG),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 		.rsp = s3fwrn5_nci_prop_rsp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 		.opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 				NCI_PROP_GET_RFREG_VER),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 		.rsp = s3fwrn5_nci_prop_rsp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 		.opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 				NCI_PROP_SET_RFREG_VER),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 		.rsp = s3fwrn5_nci_prop_rsp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 		.opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 				NCI_PROP_START_RFREG),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 		.rsp = s3fwrn5_nci_prop_rsp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 		.opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 				NCI_PROP_STOP_RFREG),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 		.rsp = s3fwrn5_nci_prop_rsp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 		.opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 				NCI_PROP_FW_CFG),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 		.rsp = s3fwrn5_nci_prop_rsp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 		.opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 				NCI_PROP_WR_RESET),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 		.rsp = s3fwrn5_nci_prop_rsp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) void s3fwrn5_nci_get_prop_ops(struct nci_driver_ops **ops, size_t *n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	*ops = s3fwrn5_nci_prop_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	*n = ARRAY_SIZE(s3fwrn5_nci_prop_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) #define S3FWRN5_RFREG_SECTION_SIZE 252
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) int s3fwrn5_nci_rf_configure(struct s3fwrn5_info *info, const char *fw_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	const struct firmware *fw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	struct nci_prop_fw_cfg_cmd fw_cfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 	struct nci_prop_set_rfreg_cmd set_rfreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 	struct nci_prop_stop_rfreg_cmd stop_rfreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	u32 checksum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	int i, len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	ret = request_firmware(&fw, fw_name, &info->ndev->nfc_dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	/* Compute rfreg checksum */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	checksum = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	for (i = 0; i < fw->size; i += 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 		checksum += *((u32 *)(fw->data+i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	/* Set default clock configuration for external crystal */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	fw_cfg.clk_type = 0x01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	fw_cfg.clk_speed = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	fw_cfg.clk_req = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	ret = nci_prop_cmd(info->ndev, NCI_PROP_FW_CFG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 		sizeof(fw_cfg), (__u8 *)&fw_cfg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	/* Start rfreg configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	dev_info(&info->ndev->nfc_dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 		"rfreg configuration update: %s\n", fw_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	ret = nci_prop_cmd(info->ndev, NCI_PROP_START_RFREG, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 		dev_err(&info->ndev->nfc_dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 			"Unable to start rfreg update\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	/* Update rfreg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	set_rfreg.index = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	for (i = 0; i < fw->size; i += S3FWRN5_RFREG_SECTION_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		len = (fw->size - i < S3FWRN5_RFREG_SECTION_SIZE) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 			(fw->size - i) : S3FWRN5_RFREG_SECTION_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 		memcpy(set_rfreg.data, fw->data+i, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 		ret = nci_prop_cmd(info->ndev, NCI_PROP_SET_RFREG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 			len+1, (__u8 *)&set_rfreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 		if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 			dev_err(&info->ndev->nfc_dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 				"rfreg update error (code=%d)\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 		set_rfreg.index++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	/* Finish rfreg configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	stop_rfreg.checksum = checksum & 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	ret = nci_prop_cmd(info->ndev, NCI_PROP_STOP_RFREG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 		sizeof(stop_rfreg), (__u8 *)&stop_rfreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 		dev_err(&info->ndev->nfc_dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 			"Unable to stop rfreg update\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	dev_info(&info->ndev->nfc_dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 		"rfreg configuration update: success\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	release_firmware(fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }