blob: 32876a2886e9b9d35de4402492bcb32590a49d7e [file] [log] [blame]
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/edge_wakeup_mmp.h>
#define GNSS_DEBUG 1
/* [0]struct init */
#define GPS_STATUS_LENS 16
struct mbtk_gnss_platform_data {
char chip_status[GPS_STATUS_LENS];
int gpio_enable;
int gpio_reset;
int gpio_boot;
};
static void mbtk_gnss_platform_data_init(
struct mbtk_gnss_platform_data *pdata)
{
/* all intems are invalid just after alloc */
memset(pdata->chip_status, 0, GPS_STATUS_LENS);
pdata->gpio_enable = -1;
}
static struct mbtk_gnss_platform_data
*mbtk_gnss_platform_data_alloc(struct platform_device *pdev)
{
struct mbtk_gnss_platform_data *pdata;
/* create a new one and init it */
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (pdata) {
mbtk_gnss_platform_data_init(pdata);
return pdata;
}
return NULL;
}
/* [1]GNSS ctrl */
#if 0//old for LDO
static int gnss_power_on(struct device *dev)
{
struct mbtk_gnss_platform_data *info = dev->platform_data;
if (info->gpio_enable >= 0) {
if (gpio_request(info->gpio_enable, "gnss enable")) {
pr_info("gpio %d request failed\n", info->gpio_enable);
return -1;
}
}
else{
pr_err("gpio %d dt error\n", info->gpio_enable);
return -1;
}
gpio_direction_output(info->gpio_enable, 1);
pr_info("gps chip powered on\n");
gpio_free(info->gpio_enable);
return 0;
}
static int gnss_power_off(struct device *dev)
{
struct mbtk_gnss_platform_data *info = dev->platform_data;
if (info->gpio_enable >= 0) {
if (gpio_request(info->gpio_enable, "gnss enable")) {
pr_info("gpio %d request failed\n", info->gpio_enable);
return -1;
}
}
else{
pr_err("gpio %d dt error\n", info->gpio_enable);
return -1;
}
gpio_direction_output(info->gpio_enable, 0);
pr_info("gps chip powered off\n");
gpio_free(info->gpio_enable);
return 0;
}
static int gnss_reset(struct device *dev)
{
struct mbtk_gnss_platform_data *info = dev->platform_data;
if (info->gpio_reset >= 0) {
if (gpio_request(info->gpio_reset, "gnss reset")) {
pr_info("gpio %d request failed\n", info->gpio_reset);
return -1;
}
}
else{
pr_err("gpio %d dt error\n", info->gpio_reset);
return -1;
}
gpio_direction_output(info->gpio_reset, 1);
msleep(150);
pr_info("gps chip reset\n");
gpio_direction_output(info->gpio_reset, 0);
gpio_free(info->gpio_reset);
return 0;
}
static int gnss_force_download(struct device *dev)
{
struct mbtk_gnss_platform_data *info = dev->platform_data;
if (info->gpio_enable >= 0) {
if (gpio_request(info->gpio_enable, "gnss enable")) {
pr_info("gpio %d request failed\n", info->gpio_enable);
return -1;
}
}
else{
pr_err("gpio %d dt error\n", info->gpio_enable);
return -1;
}
if (info->gpio_boot >= 0) {
if (gpio_request(info->gpio_boot, "gnss reset")) {
pr_info("gpio %d request failed\n", info->gpio_boot);
return -1;
}
}
else{
pr_err("gpio %d dt error\n", info->gpio_boot);
return -1;
}
if (info->gpio_reset >= 0) {
if (gpio_request(info->gpio_reset, "gnss reset")) {
pr_info("gpio %d request failed\n", info->gpio_reset);
return -1;
}
}
else{
pr_err("gpio %d dt error\n", info->gpio_reset);
return -1;
}
gpio_direction_output(info->gpio_enable, 1);
msleep(10);
gpio_direction_output(info->gpio_reset, 1);
msleep(10);
gpio_direction_output(info->gpio_boot, 0);
msleep(150);
gpio_direction_output(info->gpio_reset, 0);
msleep(100);
gpio_direction_input(info->gpio_boot);
gpio_free(info->gpio_enable);
gpio_free(info->gpio_boot);
gpio_free(info->gpio_reset);
return 0;
}
#if 0//wakeup TODO
static int gps_wakeup(struct mbtk_gnss_platform_data *info, int flag)
{
struct mbtk_gnss_platform_data *info = dev->platform_data;
gpio_direction_output(info->gpio_enable, 0);
msleep(50);
gpio_direction_output(info->gpio_enable, 1);
pr_debug("gps chip reset\n");
gpio_free(info->gpio_enable);
return 0;
}
#endif
#else //for VLDO5
static int gnss_reset(struct device *dev)
{
struct mbtk_gnss_platform_data *info = dev->platform_data;
if (info->gpio_reset >= 0) {
if (gpio_request(info->gpio_reset, "gnss reset")) {
pr_info("gpio %d request failed\n", info->gpio_reset);
return -1;
}
}
else{
pr_err("gpio %d dt error\n", info->gpio_reset);
return -1;
}
gpio_direction_output(info->gpio_reset, 1);
msleep(150);
pr_info("gps chip reset\n");
gpio_direction_output(info->gpio_reset, 0);
gpio_free(info->gpio_reset);
return 0;
}
static int gnss_force_download(struct device *dev)
{
struct mbtk_gnss_platform_data *info = dev->platform_data;
if (info->gpio_boot >= 0) {
if (gpio_request(info->gpio_boot, "gnss reset")) {
pr_info("gpio %d request failed\n", info->gpio_boot);
return -1;
}
}
else{
pr_err("gpio %d dt error\n", info->gpio_boot);
return -1;
}
if (info->gpio_reset >= 0) {
if (gpio_request(info->gpio_reset, "gnss reset")) {
pr_info("gpio %d request failed\n", info->gpio_reset);
return -1;
}
}
else{
pr_err("gpio %d dt error\n", info->gpio_reset);
return -1;
}
gpio_direction_output(info->gpio_reset, 1);
msleep(10);
gpio_direction_output(info->gpio_boot, 0);
msleep(150);
gpio_direction_output(info->gpio_reset, 0);
msleep(100);
gpio_direction_input(info->gpio_boot);
gpio_free(info->gpio_boot);
gpio_free(info->gpio_reset);
return 0;
}
#endif
static ssize_t gps_ctrl(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
static char msg[256];
struct mbtk_gnss_platform_data *info = dev->platform_data;
count = (count > 255) ? 255 : count;
memset(msg, 0, count);
sscanf(buf, "%s", info->chip_status);
if (!strncmp(buf, "off", 3)) {
strncpy(info->chip_status, "off", 4);
// gnss_power_off(dev);
}
else if (!strncmp(buf, "on", 2)) {
strncpy(info->chip_status, "on", 3);
// gnss_power_on(dev);
}
else if (!strncmp(buf, "reset", 5)) {
//strncpy(info->chip_status, "reset", 6);
gnss_reset(dev);
}
else if (!strncmp(buf, "fdl", 3)) {
strncpy(info->chip_status, "fdl", 4);
gnss_force_download(dev);
}
#if 0//wakeup TODO
else if (!strncmp(buf, "wakeup", 6)) {
strncpy(info->chip_status, "wakeup", 7);
ret = sscanf(buf, "%s %d", msg, &flag);
if (ret == 2)
gnss_wakeup(info, flag);
}
#endif
else{
pr_err("[mbtk_gnss error!]status only support on/off/reset\n");
}
return count;
}
static ssize_t gnss_status(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mbtk_gnss_platform_data *info = dev->platform_data;
return sprintf(buf, "status: %s\n", info->chip_status);
}
static DEVICE_ATTR(ctrl, S_IWUSR, gnss_status, gps_ctrl);
static DEVICE_ATTR(status, S_IRUSR, gnss_status, NULL);
static const struct attribute *gnss_attrs[] = {
&dev_attr_ctrl.attr,
&dev_attr_status.attr,
NULL,
};
static const struct attribute_group gnss_attr_group = {
.attrs = (struct attribute **)gnss_attrs,
};
/* [2]DT & probe */
//DT
#ifdef CONFIG_OF
static const struct of_device_id mbtk_gnss_of_match[] = {
{
.compatible = "mbtk,mbtk-gnss",
},
{},
};
MODULE_DEVICE_TABLE(of, mbtk_gnss_of_match);
static int mbtk_gnss_probe_dt(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
int enable_gpio = -1;
int reset_gpio = -1;
int boot_gpio = -1;
struct mbtk_gnss_platform_data *pdata = pdev->dev.platform_data;
/* get gpios from dt */
enable_gpio = of_get_named_gpio(np, "enable-gpio", 0);
if (likely(enable_gpio > 0)){
pdata->gpio_enable = enable_gpio;
pr_info("%s: enable-gpio = %d\n", __func__, pdata->gpio_enable);
} else {
dev_err(&pdev->dev, "enable-gpio undefined\n");
pdata->gpio_enable = -1;
}
reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
if (likely(reset_gpio > 0)){
pdata->gpio_reset = reset_gpio;
pr_info("%s: reset-gpio = %d\n", __func__, pdata->gpio_reset);
} else {
dev_err(&pdev->dev, "reset-gpio undefined\n");
pdata->gpio_reset = -1;
}
boot_gpio = of_get_named_gpio(np, "boot-gpio", 0);
if (likely(boot_gpio > 0)){
pdata->gpio_boot = boot_gpio;
pr_info("%s: boot-gpio = %d\n", __func__, pdata->gpio_boot);
} else {
dev_err(&pdev->dev, "boot-gpio undefined\n");
pdata->gpio_boot = -1;
}
#if 0//old
enable_gpio = of_get_named_gpio(np, "enable-gpio", 0);
if (unlikely(enable_gpio < 0)){
dev_err(&pdev->dev, "enable-gpio undefined\n");
pdata->gpio_enable = -1;
} else {
pdata->gpio_enable = enable_gpio;
pr_info("%s: enable-gpio = %d\n", __func__, pdata->gpio_enable);
}
reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
if (unlikely(reset_gpio < 0)){
dev_err(&pdev->dev, "reset-gpio undefined\n");
pdata->gpio_reset = -1;
} else {
pdata->gpio_reset = reset_gpio;
pr_info("%s: reset-gpio = %d\n", __func__, pdata->gpio_reset);
}
boot_gpio = of_get_named_gpio(np, "boot-gpio", 0);
if (unlikely(boot_gpio < 0)){
dev_err(&pdev->dev, "boot-gpio undefined\n");
pdata->gpio_boot = -1;
} else {
pdata->gpio_boot = boot_gpio;
pr_info("%s: boot-gpio = %d\n", __func__, pdata->gpio_boot);
}
#endif
return 0;
}
#else
static int mbtk_gnss_probe_dt(struct platform_device *pdev)
{
return 0;
}
#endif
//probe
static int mbtk_gnss_probe(struct platform_device *pdev)
{
struct mbtk_gnss_platform_data *pdata = NULL;
const struct of_device_id *match = NULL;
int ret = -1;
/* flag: whether pdata is passed from platform_data */
int pdata_passed = 1;
pr_info("[mbtk gnss]probe begin\n");
/* alloc */
pdata = pdev->dev.platform_data;
if (!pdata) {
/* if platform data do not pass the struct to us */
pdata_passed = 0;
pdata = mbtk_gnss_platform_data_alloc(pdev);
if (!pdata) {
pr_err("[mbtk gnss]ERROR! can't get mbtk_gnss_platform_data struct during probe!\n");
goto err_pdata;
}
pdev->dev.platform_data = pdata;
}
/* set value if DT pass them to us */
#ifdef CONFIG_OF
//pr_info("[mbtk gnss]CONFIG_OF entry\n");
match = of_match_device(of_match_ptr(mbtk_gnss_of_match), &pdev->dev);
#endif
if (match) {
ret = mbtk_gnss_probe_dt(pdev);
if (ret)
goto err_dt;
}
ret = sysfs_create_group(&pdev->dev.kobj, &gnss_attr_group);
if (ret) {
dev_err(&pdev->dev, "[mbtk gnss]ERROR! sysfs create mbtk_gnss node fail!\n");
return ret;
}
return 0;
err_dt:
pdev->dev.platform_data = NULL;
err_pdata:
return ret;
}
static int mbtk_gnss_remove(struct platform_device *pdev)
{
return 0;
}
/* [3]suspend & resume TODO*/
static int mbtk_gnss_suspend(struct platform_device *pdev, pm_message_t pm_state)
{
return 0;
}
static int mbtk_gnss_resume(struct platform_device *pdev)
{
return 0;
}
/* [4]platform driver init */
static struct platform_driver mbtk_gnss_platform_driver = {
.probe = mbtk_gnss_probe,
.remove = mbtk_gnss_remove,
.driver = {
.name = "mbtk_gnss",
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = mbtk_gnss_of_match,
#endif
},
.suspend = mbtk_gnss_suspend,
.resume = mbtk_gnss_resume,
};
static int __init mbtk_gnss_init(void)
{
return platform_driver_register(&mbtk_gnss_platform_driver);
}
static void __exit mbtk_gnss_exit(void)
{
platform_driver_unregister(&mbtk_gnss_platform_driver);
}
module_init(mbtk_gnss_init);
module_exit(mbtk_gnss_exit);
MODULE_ALIAS("platform:mbtk_gnss");
MODULE_DESCRIPTION("mbtk_gnss");
MODULE_AUTHOR("MBTK");
MODULE_LICENSE("GPL V2");