Initial bringup for FM elan module & use fm_ctrl.ko

As request from RF team, for fmradio signal lose issue in new HW design,
need to add elna module for ensure fmradio performance.

Change-Id: I9c21f63788fbef4c28785e9d985631f1ef248105
Reviewed-on: https://gerrit.mot.com/1376704
SME-Granted: SME Approvals Granted
SLTApproved: Slta Waiver
Tested-by: Jira Key
Reviewed-by: Qiu Feng <fengqiu1@lenovo.com>
Reviewed-by: Tao Sun <suntao2@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
liaoxl 2019-07-02 17:22:56 +08:00 • committed by Xianglong Liao
commit 03d5170904
4 changed files with 224 additions and 0 deletions

10
drivers/fm/Android.mk Normal file
View file

@ -0,0 +1,10 @@
ifeq ($(BOARD_HAS_FM_ELNA), true)
DLKM_DIR := motorola/kernel/modules
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := fm_ctrl.ko
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/AndroidKernelModule.mk
endif

4
drivers/fm/Kbuild Normal file
View file

@ -0,0 +1,4 @@
# add -Wall to try to catch everything we can.
EXTRA_CFLAGS += -Wall
obj-m += fm_ctrl.o

11
drivers/fm/Makefile Normal file
View file

@ -0,0 +1,11 @@
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS)
modules_install:
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install
clean:
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean

199
drivers/fm/fm_ctrl.c Normal file
View file

@ -0,0 +1,199 @@
/*
* Copyright (C) 2019 Motorola Mobility LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#define DRIVER_VERSION "0.0.1"
struct fm_ctrl_drvdata {
struct device *dev;
struct pinctrl *pinctrl;
struct pinctrl_state *pstate_default;
struct pinctrl_state *pstate_active;
struct pinctrl_state *pstate_suspend;
};
static ssize_t device_name_read(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct fm_ctrl_drvdata *data = dev_get_drvdata(dev);
if (!data) {
pr_err("fm_ctrl drvdata is NULL\n");
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE, "moto fm control intf\n");
}
static ssize_t elna_en_read(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct fm_ctrl_drvdata *data = dev_get_drvdata(dev);
if (!data) {
pr_err("fm_ctrl drvdata is NULL\n");
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE, "fm_ctrl: not support!\n");
}
static ssize_t elna_en_write(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
struct fm_ctrl_drvdata *data = dev_get_drvdata(dev);
int ret = 0;
unsigned int res = 0;
if (!data) {
pr_err("fm_ctrl drvdata is NULL\n");
return -EINVAL;
}
ret = kstrtouint(buf, 0, &res);
if(ret) {
pr_err("fm_ctrl failed to get data, set as default!\n");
}
if(1 == res) {
ret = pinctrl_select_state(data->pinctrl, data->pstate_active);
}
else {
ret = pinctrl_select_state(data->pinctrl, data->pstate_suspend);
}
if(ret) {
pr_err("fm_ctrl failed to set pinctrl!\n");
}
else {
pr_info("fm_ctrl set elan=%u\n", res);
}
return count;
}
static DEVICE_ATTR(device_name, 0444, device_name_read, NULL);
static DEVICE_ATTR(elna_en, 0644, elna_en_read, elna_en_write);
static struct attribute *fm_ctrl_sysfs_attrs[] = {
&dev_attr_device_name.attr,
&dev_attr_elna_en.attr,
NULL,
};
static struct attribute_group fm_ctrl_sysfs_attr_grp = {
.attrs = fm_ctrl_sysfs_attrs,
};
static int fm_ctrl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct fm_ctrl_drvdata *drvdata;
int ret = 0;
dev_dbg(&pdev->dev, "%s begin\n", __func__);
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
/* Get pinctrl if target uses pinctrl */
drvdata->pinctrl = devm_pinctrl_get(dev);
if (IS_ERR_OR_NULL(drvdata->pinctrl)) {
ret = PTR_ERR(drvdata->pinctrl);
pr_err("%s: Pincontrol DT property returned %X\n", __func__, ret);
return ret;
}
drvdata->pstate_default = pinctrl_lookup_state(drvdata->pinctrl,
"default");
if (IS_ERR_OR_NULL(drvdata->pstate_default)) {
ret = PTR_ERR(drvdata->pstate_default);
pr_err("Can not lookup default pinstate %d\n", ret);
return -ENOENT;
}
drvdata->pstate_active = pinctrl_lookup_state(drvdata->pinctrl,
"elna_active");
if (IS_ERR_OR_NULL(drvdata->pstate_active)) {
ret = PTR_ERR(drvdata->pstate_active);
pr_err("Can not lookup active pinstate %d\n", ret);
return ret;
}
drvdata->pstate_suspend = pinctrl_lookup_state(drvdata->pinctrl,
"elna_suspend");
if (IS_ERR_OR_NULL(drvdata->pstate_suspend)) {
ret = PTR_ERR(drvdata->pstate_suspend);
pr_err("Can not lookup suspend pinstate %d\n", ret);
return ret;
}
ret = sysfs_create_group(&dev->kobj, &fm_ctrl_sysfs_attr_grp);
if (ret) {
pr_err("%s: sysfs group creation failed %d\n", __func__, ret);
return ret;
}
device_init_wakeup(&pdev->dev, 1);
dev_info(&pdev->dev, "probe: All success !\n");
return ret;
}
static int fm_ctrl_remove(struct platform_device *pdev)
{
device_init_wakeup(&pdev->dev, 0);
return 0;
}
static const struct of_device_id fm_ctrl_match[] = {
{ .compatible = "moto,fmctrl" },
{}
};
static struct platform_driver fm_ctrl_plat_driver = {
.probe = fm_ctrl_probe,
.remove = fm_ctrl_remove,
.driver = {
.name = "fm_ctrl",
.owner = THIS_MODULE,
.of_match_table = fm_ctrl_match,
},
};
module_platform_driver(fm_ctrl_plat_driver);
MODULE_AUTHOR("Motorola Mobiity");
MODULE_DESCRIPTION("FMRadio control interface driver");
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");