Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 80560bd3 authored by Kyle Yan's avatar Kyle Yan Committed by Gerrit - the friendly Code Review server
Browse files

Merge "icnss: Add ICNSS platform driver" into msm-4.8

parents fef2bc5d 607051c4
Loading
Loading
Loading
Loading
+58 −0
Original line number Diff line number Diff line
* Qualcomm Technologies Inc Q6 Integrated connectivity Platform Driver

This platform driver adds support for the Integrated WLAN that runs
on Q6 based platforms. WLAN FW on these architecture runs on Q6. This
platform driver communicates with WLAN FW over QMI, WLAN on/off messages
to FW are communicated thru this interface. This driver also listens to
WLAN PD restart notifications.

Required properties:
  - compatible: "qcom,icnss"
  - reg: Memory regions defined as starting address and size
  - reg-names: Names of the memory regions defined in reg entry
  - interrupts: Copy engine interrupt table
  - qcom,wlan-msa-memory: MSA memory size
  - clocks: List of clock phandles
  - clock-names: List of clock names corresponding to the "clocks" property
  - iommus: SMMUs and corresponding Stream IDs needed by WLAN
  - qcom,wlan-smmu-iova-address: I/O virtual address range as <start length>
    format to be used for allocations associated between WLAN and SMMU
  - <supply-name>-supply: phandle to the regulator device tree node
                          Required "supply-name" is "vdd-0.8-cx-mx".
  - qcom,<supply>-config - specifies voltage levels for supply. Should be
                           specified in pairs (min, max), units uV.  There can
                           be optional load in uA and Regulator settle delay in
                           uS.

Optional properties:
  - qcom,icnss-vadc: VADC handle for vph_pwr read APIs.
  - qcom,icnss-adc_tm: VADC handle for vph_pwr notification APIs.

Example:

    qcom,icnss@0a000000 {
        compatible = "qcom,icnss";
        reg = <0x0a000000 0x1000000>;
        reg-names = "membase";
        clocks = <&clock_gcc clk_aggre2_noc_clk>;
        clock-names = "smmu_aggre2_noc_clk";
        iommus = <&anoc2_smmu 0x1900>,
                 <&anoc2_smmu 0x1901>;
        qcom,wlan-smmu-iova-address = <0 0x10000000>;
        interrupts =
		   <0 130 0 /* CE0 */ >,
		   <0 131 0 /* CE1 */ >,
		   <0 132 0 /* CE2 */ >,
		   <0 133 0 /* CE3 */ >,
		   <0 134 0 /* CE4 */ >,
		   <0 135 0 /* CE5 */ >,
		   <0 136 0 /* CE6 */ >,
		   <0 137 0 /* CE7 */ >,
		   <0 138 0 /* CE8 */ >,
		   <0 139 0 /* CE9 */ >,
		   <0 140 0 /* CE10 */ >,
		   <0 141 0 /* CE11 */ >;
        qcom,wlan-msa-memory = <0x200000>;
	vdd-0.8-cx-mx-supply = <&pm8998_l5>;
	qcom,vdd-0.8-cx-mx-config = <800000 800000 2400 1000>;
    };
+17 −0
Original line number Diff line number Diff line
@@ -433,3 +433,20 @@ config MSM_PIL_MSS_QDSP6V5
         calls then say Y here.

         If unsure, say N.

config ICNSS
        tristate "Platform driver for Q6 integrated connectivity"
        ---help---
          This module adds support for Q6 integrated WLAN connectivity
          subsystem. This module is responsible for communicating WLAN on/off
          control messages to FW over QMI channel. It is also responsible for
          handling WLAN PD restart notifications.

config ICNSS_DEBUG
        bool "ICNSS debug support"
        depends on ICNSS
        ---help---
          Say 'Y' here to enable ICNSS driver debug support. Debug support
          primarily consists of logs consisting of information related to
          hardware register access and enabling BUG_ON for certain cases to aid
          the debugging.
 No newline at end of file
+1 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ obj-$(CONFIG_MSM_GLINK_PKT) += msm_glink_pkt.o
obj-$(CONFIG_MSM_SYSTEM_HEALTH_MONITOR)	+=	system_health_monitor_v01.o
obj-$(CONFIG_MSM_SYSTEM_HEALTH_MONITOR)	+=	system_health_monitor.o
obj-$(CONFIG_MSM_SYSMON_GLINK_COMM) += sysmon-glink.o sysmon-qmi.o
obj-$(CONFIG_ICNSS) += icnss.o wlan_firmware_service_v01.o icnss_utils.o

obj-$(CONFIG_MSM_PIL_SSR_GENERIC) += subsys-pil-tz.o
obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-msa.o pil-q6v5-mss.o
+4773 −0

File added.

Preview size limit exceeded, changes collapsed.

+132 −0
Original line number Diff line number Diff line
/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/module.h>
#include <linux/slab.h>

#define ICNSS_MAX_CH_NUM 45

static DEFINE_MUTEX(unsafe_channel_list_lock);
static DEFINE_MUTEX(dfs_nol_info_lock);

static struct icnss_unsafe_channel_list {
	u16 unsafe_ch_count;
	u16 unsafe_ch_list[ICNSS_MAX_CH_NUM];
} unsafe_channel_list;

static struct icnss_dfs_nol_info {
	void *dfs_nol_info;
	u16 dfs_nol_info_len;
} dfs_nol_info;

int icnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count)
{
	mutex_lock(&unsafe_channel_list_lock);
	if ((!unsafe_ch_list) || (ch_count > ICNSS_MAX_CH_NUM)) {
		mutex_unlock(&unsafe_channel_list_lock);
		return -EINVAL;
	}

	unsafe_channel_list.unsafe_ch_count = ch_count;

	if (ch_count != 0) {
		memcpy(
		       (char *)unsafe_channel_list.unsafe_ch_list,
		       (char *)unsafe_ch_list, ch_count * sizeof(u16));
	}
	mutex_unlock(&unsafe_channel_list_lock);

	return 0;
}
EXPORT_SYMBOL(icnss_set_wlan_unsafe_channel);

int icnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list,
				  u16 *ch_count, u16 buf_len)
{
	mutex_lock(&unsafe_channel_list_lock);
	if (!unsafe_ch_list || !ch_count) {
		mutex_unlock(&unsafe_channel_list_lock);
		return -EINVAL;
	}

	if (buf_len < (unsafe_channel_list.unsafe_ch_count * sizeof(u16))) {
		mutex_unlock(&unsafe_channel_list_lock);
		return -ENOMEM;
	}

	*ch_count = unsafe_channel_list.unsafe_ch_count;
	memcpy(
		(char *)unsafe_ch_list,
		(char *)unsafe_channel_list.unsafe_ch_list,
		unsafe_channel_list.unsafe_ch_count * sizeof(u16));
	mutex_unlock(&unsafe_channel_list_lock);

	return 0;
}
EXPORT_SYMBOL(icnss_get_wlan_unsafe_channel);

int icnss_wlan_set_dfs_nol(const void *info, u16 info_len)
{
	void *temp;
	struct icnss_dfs_nol_info *dfs_info;

	mutex_lock(&dfs_nol_info_lock);
	if (!info || !info_len) {
		mutex_unlock(&dfs_nol_info_lock);
		return -EINVAL;
	}

	temp = kmalloc(info_len, GFP_KERNEL);
	if (!temp) {
		mutex_unlock(&dfs_nol_info_lock);
		return -ENOMEM;
	}

	memcpy(temp, info, info_len);
	dfs_info = &dfs_nol_info;
	kfree(dfs_info->dfs_nol_info);

	dfs_info->dfs_nol_info = temp;
	dfs_info->dfs_nol_info_len = info_len;
	mutex_unlock(&dfs_nol_info_lock);

	return 0;
}
EXPORT_SYMBOL(icnss_wlan_set_dfs_nol);

int icnss_wlan_get_dfs_nol(void *info, u16 info_len)
{
	int len;
	struct icnss_dfs_nol_info *dfs_info;

	mutex_lock(&dfs_nol_info_lock);
	if (!info || !info_len) {
		mutex_unlock(&dfs_nol_info_lock);
		return -EINVAL;
	}

	dfs_info = &dfs_nol_info;

	if (dfs_info->dfs_nol_info == NULL ||
	    dfs_info->dfs_nol_info_len == 0) {
		mutex_unlock(&dfs_nol_info_lock);
		return -ENOENT;
	}

	len = min(info_len, dfs_info->dfs_nol_info_len);

	memcpy(info, dfs_info->dfs_nol_info, len);
	mutex_unlock(&dfs_nol_info_lock);

	return len;
}
EXPORT_SYMBOL(icnss_wlan_get_dfs_nol);
Loading