blob: f8670e53ecd2f2d9aeaba7e952e67d6a2d54a4e2 [file] [log] [blame]
/* Copyright (c) 2011, Hewlett-Packard Development Company, All rights reserved.
*
* mdmgpio.c - Linux kernel modules for modem gppio control
*
* 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/platform_device.h>
#include <linux/gpio.h>
#include <linux/err.h>
#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/mdmgpio.h>
static ssize_t uim_cd_gpio_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int value = 0;
struct mdmgpio_platform_data *pdata;
pdata = (struct mdmgpio_platform_data *)dev->platform_data;
if (!pdata)
return -EINVAL;
if (pdata->get_gpio_value)
value = pdata->get_gpio_value(pdata->uim_cd_gpio);
else
return -EINVAL;
return sprintf(buf, "%u\n", value);
}
static ssize_t uim_cd_gpio_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
ssize_t ret = -EINVAL;
char *after;
struct mdmgpio_platform_data *pdata;
unsigned long value = simple_strtoul(buf, &after, 10);
size_t count = after - buf;
pdata = (struct mdmgpio_platform_data *)dev->platform_data;
if (!pdata)
return -EINVAL;
if (isspace(*after))
count++;
if (count == size) {
ret = count;
if (pdata->set_gpio_value)
pdata->set_gpio_value(pdata->uim_cd_gpio, !!value);
else
return -EINVAL;
}
return ret;
}
static ssize_t mdm_disable_gpio_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int value = 0;
struct mdmgpio_platform_data *pdata;
pdata = (struct mdmgpio_platform_data *)dev->platform_data;
if (!pdata)
return -EINVAL;
if (pdata->get_gpio_value)
value = pdata->get_gpio_value(pdata->mdm_disable_gpio);
else
return -EINVAL;
return sprintf(buf,"%u\n", value);
}
static ssize_t mdm_disable_gpio_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
ssize_t ret = -EINVAL;
char *after;
struct mdmgpio_platform_data *pdata;
unsigned long value = simple_strtoul(buf, &after, 10);
size_t count = after - buf;
pdata = (struct mdmgpio_platform_data *)dev->platform_data;
if (!pdata)
return -EINVAL;
if (isspace(*after))
count++;
if (count == size) {
ret = count;
if (pdata->set_gpio_value)
pdata->set_gpio_value(pdata->mdm_disable_gpio, !!value);
else
return -EINVAL;
}
return ret;
}
static ssize_t mdm_poweron_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int value = 0;
struct mdmgpio_platform_data *pdata;
pdata = (struct mdmgpio_platform_data *)dev->platform_data;
if (!pdata)
return -EINVAL;
if (pdata->mdm_poweron_status)
value = pdata->mdm_poweron_status();
return sprintf(buf,"%u\n", value);
}
static ssize_t mdm_poweron_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
ssize_t ret = -EINVAL;
char *after;
struct mdmgpio_platform_data *pdata;
unsigned long value = simple_strtoul(buf, &after, 10);
size_t count = after - buf;
pdata = (struct mdmgpio_platform_data *)dev->platform_data;
if (!pdata)
return -EINVAL;
if (isspace(*after))
count++;
if (count == size) {
ret = count;
if (pdata->mdm_poweron)
pdata->mdm_poweron(!!value);
}
return ret;
}
static struct device_attribute mdmgpio_attrs[] = {
__ATTR(uim_cd_gpio, 0644, uim_cd_gpio_show, uim_cd_gpio_store),
__ATTR(mdm_disable_gpio, 0644, mdm_disable_gpio_show, mdm_disable_gpio_store),
__ATTR(mdm_poweron, 0644, mdm_poweron_show, mdm_poweron_store),
__ATTR_NULL,
};
static int mdmgpio_probe(struct platform_device *pdev)
{
int ret = 0;
int i;
struct mdmgpio_platform_data *pdata;
printk("%s\n", __func__);
pdata = (struct mdmgpio_platform_data *)pdev->dev.platform_data;
if (pdata == NULL) {
printk(KERN_ERR"%s: null platform data\n", __func__);
return -EINVAL;
}
for( i = 0; attr_name(mdmgpio_attrs[i]); i++) {
ret = device_create_file(&pdev->dev, &mdmgpio_attrs[i]);
if (ret < 0) {
printk(KERN_ERR "%s:failed to create sysfs file %s\n",
__func__, attr_name(mdmgpio_attrs[i]));
break;
}
}
if (ret < 0)
while(--i >= 0)
device_remove_file(&pdev->dev, &mdmgpio_attrs[i]);
return ret;
}
static int mdmgpio_remove(struct platform_device *pdev)
{
int ret = 0;
int i;
struct mdmgpio_platform_data *pdata;
printk("%s\n", __func__);
pdata = (struct mdmgpio_platform_data *)pdev->dev.platform_data;
if (!pdata)
return -EINVAL;
for(i = 0; attr_name(mdmgpio_attrs[i]); i++) {
device_remove_file(&pdev->dev, &mdmgpio_attrs[i]);
}
return ret;
}
static struct platform_driver mdmgpio_driver = {
.probe = mdmgpio_probe,
.remove = mdmgpio_remove,
.driver = {
.name = "mdmgpio",
.owner = THIS_MODULE,
},
};
int __init mdmgpio_init(void)
{
printk("%s\n", __func__);
platform_driver_register(&mdmgpio_driver);
return 0;
}
static void __exit mdmgpio_exit(void)
{
printk("%s\n", __func__);
platform_driver_unregister(&mdmgpio_driver);
}
module_init(mdmgpio_init);
module_exit(mdmgpio_exit);
MODULE_AUTHOR("Hao Song<hao.song@hp.com>");
MODULE_LICENSE("GPL");