viafb: Turn GPIO and i2c into proper platform devices
Another step toward making this thing a real multifunction device driver. Cc: ScottFang@viatech.com.cn Cc: JosephChan@via.com.tw Cc: Harald Welte <laforge@gnumonks.org> Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de> Signed-off-by: Jonathan Corbet <corbet@lwn.net>
This commit is contained in:
parent
75b035ace9
commit
7582eb9be8
6 changed files with 143 additions and 44 deletions
|
@ -190,6 +190,70 @@ static void __devexit via_pci_teardown_mmio(struct viafb_dev *vdev)
|
||||||
iounmap(vdev->engine_mmio);
|
iounmap(vdev->engine_mmio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create our subsidiary devices.
|
||||||
|
*/
|
||||||
|
static struct viafb_subdev_info {
|
||||||
|
char *name;
|
||||||
|
struct platform_device *platdev;
|
||||||
|
} viafb_subdevs[] = {
|
||||||
|
{
|
||||||
|
.name = "viafb-gpio",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "viafb-i2c",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#define N_SUBDEVS ARRAY_SIZE(viafb_subdevs)
|
||||||
|
|
||||||
|
static int __devinit via_create_subdev(struct viafb_dev *vdev,
|
||||||
|
struct viafb_subdev_info *info)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
info->platdev = platform_device_alloc(info->name, -1);
|
||||||
|
if (!info->platdev) {
|
||||||
|
dev_err(&vdev->pdev->dev, "Unable to allocate pdev %s\n",
|
||||||
|
info->name);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
info->platdev->dev.parent = &vdev->pdev->dev;
|
||||||
|
info->platdev->dev.platform_data = vdev;
|
||||||
|
ret = platform_device_add(info->platdev);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&vdev->pdev->dev, "Unable to add pdev %s\n",
|
||||||
|
info->name);
|
||||||
|
platform_device_put(info->platdev);
|
||||||
|
info->platdev = NULL;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __devinit via_setup_subdevs(struct viafb_dev *vdev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ignore return values. Even if some of the devices
|
||||||
|
* fail to be created, we'll still be able to use some
|
||||||
|
* of the rest.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < N_SUBDEVS; i++)
|
||||||
|
via_create_subdev(vdev, viafb_subdevs + i);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __devexit via_teardown_subdevs(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < N_SUBDEVS; i++)
|
||||||
|
if (viafb_subdevs[i].platdev) {
|
||||||
|
viafb_subdevs[i].platdev->dev.platform_data = NULL;
|
||||||
|
platform_device_unregister(viafb_subdevs[i].platdev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int __devinit via_pci_probe(struct pci_dev *pdev,
|
static int __devinit via_pci_probe(struct pci_dev *pdev,
|
||||||
const struct pci_device_id *ent)
|
const struct pci_device_id *ent)
|
||||||
|
@ -205,33 +269,25 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
|
||||||
memset(&global_dev, 0, sizeof(global_dev));
|
memset(&global_dev, 0, sizeof(global_dev));
|
||||||
global_dev.pdev = pdev;
|
global_dev.pdev = pdev;
|
||||||
global_dev.chip_type = ent->driver_data;
|
global_dev.chip_type = ent->driver_data;
|
||||||
|
global_dev.port_cfg = adap_configs;
|
||||||
spin_lock_init(&global_dev.reg_lock);
|
spin_lock_init(&global_dev.reg_lock);
|
||||||
ret = via_pci_setup_mmio(&global_dev);
|
ret = via_pci_setup_mmio(&global_dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_disable;
|
goto out_disable;
|
||||||
/*
|
/*
|
||||||
* Create the I2C busses. Bailing out on failure seems extreme,
|
* Create our subdevices. Continue even if some things fail.
|
||||||
* but that's what the code did before.
|
|
||||||
*/
|
*/
|
||||||
ret = viafb_create_i2c_busses(&global_dev, adap_configs);
|
via_setup_subdevs(&global_dev);
|
||||||
if (ret)
|
|
||||||
goto out_teardown;
|
|
||||||
/*
|
/*
|
||||||
* Set up the framebuffer.
|
* Set up the framebuffer.
|
||||||
*/
|
*/
|
||||||
ret = via_fb_pci_probe(&global_dev);
|
ret = via_fb_pci_probe(&global_dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_i2c;
|
goto out_subdevs;
|
||||||
/*
|
|
||||||
* Create the GPIOs. We continue whether or not this succeeds;
|
|
||||||
* the framebuffer might be useful even without GPIO ports.
|
|
||||||
*/
|
|
||||||
ret = viafb_create_gpios(&global_dev, adap_configs);
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_i2c:
|
out_subdevs:
|
||||||
viafb_delete_i2c_busses();
|
via_teardown_subdevs();
|
||||||
out_teardown:
|
|
||||||
via_pci_teardown_mmio(&global_dev);
|
via_pci_teardown_mmio(&global_dev);
|
||||||
out_disable:
|
out_disable:
|
||||||
pci_disable_device(pdev);
|
pci_disable_device(pdev);
|
||||||
|
@ -240,8 +296,7 @@ out_disable:
|
||||||
|
|
||||||
static void __devexit via_pci_remove(struct pci_dev *pdev)
|
static void __devexit via_pci_remove(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
viafb_destroy_gpios();
|
via_teardown_subdevs();
|
||||||
viafb_delete_i2c_busses();
|
|
||||||
via_fb_pci_remove(pdev);
|
via_fb_pci_remove(pdev);
|
||||||
via_pci_teardown_mmio(&global_dev);
|
via_pci_teardown_mmio(&global_dev);
|
||||||
pci_disable_device(pdev);
|
pci_disable_device(pdev);
|
||||||
|
@ -289,12 +344,16 @@ static int __init via_core_init(void)
|
||||||
ret = viafb_init();
|
ret = viafb_init();
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
viafb_i2c_init();
|
||||||
|
viafb_gpio_init();
|
||||||
return pci_register_driver(&via_driver);
|
return pci_register_driver(&via_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit via_core_exit(void)
|
static void __exit via_core_exit(void)
|
||||||
{
|
{
|
||||||
pci_unregister_driver(&via_driver);
|
pci_unregister_driver(&via_driver);
|
||||||
|
viafb_gpio_exit();
|
||||||
|
viafb_i2c_exit();
|
||||||
viafb_exit();
|
viafb_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ struct via_port_cfg {
|
||||||
struct viafb_dev {
|
struct viafb_dev {
|
||||||
struct pci_dev *pdev;
|
struct pci_dev *pdev;
|
||||||
int chip_type;
|
int chip_type;
|
||||||
|
struct via_port_cfg *port_cfg;
|
||||||
/*
|
/*
|
||||||
* Spinlock for access to device registers. Not yet
|
* Spinlock for access to device registers. Not yet
|
||||||
* globally used.
|
* globally used.
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
#include "via-core.h"
|
#include "via-core.h"
|
||||||
#include "via-gpio.h"
|
#include "via-gpio.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
@ -172,12 +173,27 @@ static void viafb_gpio_disable(struct viafb_gpio *gpio)
|
||||||
via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02);
|
via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look up a specific gpio and return the number it was assigned.
|
||||||
|
*/
|
||||||
int viafb_create_gpios(struct viafb_dev *vdev,
|
int viafb_gpio_lookup(const char *name)
|
||||||
const struct via_port_cfg *port_cfg)
|
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < gpio_config.gpio_chip.ngpio; i++)
|
||||||
|
if (!strcmp(name, gpio_config.active_gpios[i]->vg_name))
|
||||||
|
return gpio_config.gpio_chip.base + i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(viafb_gpio_lookup);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Platform device stuff.
|
||||||
|
*/
|
||||||
|
static __devinit int viafb_gpio_probe(struct platform_device *platdev)
|
||||||
|
{
|
||||||
|
struct viafb_dev *vdev = platdev->dev.platform_data;
|
||||||
|
struct via_port_cfg *port_cfg = vdev->port_cfg;
|
||||||
int i, ngpio = 0, ret;
|
int i, ngpio = 0, ret;
|
||||||
struct viafb_gpio *gpio;
|
struct viafb_gpio *gpio;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -222,11 +238,10 @@ int viafb_create_gpios(struct viafb_dev *vdev,
|
||||||
gpio_config.gpio_chip.ngpio = 0;
|
gpio_config.gpio_chip.ngpio = 0;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
/* Port enable ? */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int viafb_destroy_gpios(void)
|
static int viafb_gpio_remove(struct platform_device *platdev)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret = 0, i;
|
int ret = 0, i;
|
||||||
|
@ -253,16 +268,20 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static struct platform_driver via_gpio_driver = {
|
||||||
* Look up a specific gpio and return the number it was assigned.
|
.driver = {
|
||||||
*/
|
.name = "viafb-gpio",
|
||||||
int viafb_gpio_lookup(const char *name)
|
},
|
||||||
{
|
.probe = viafb_gpio_probe,
|
||||||
int i;
|
.remove = viafb_gpio_remove,
|
||||||
|
};
|
||||||
|
|
||||||
for (i = 0; i < gpio_config.gpio_chip.ngpio; i++)
|
int viafb_gpio_init(void)
|
||||||
if (!strcmp(name, gpio_config.active_gpios[i]->vg_name))
|
{
|
||||||
return gpio_config.gpio_chip.base + i;
|
return platform_driver_register(&via_gpio_driver);
|
||||||
return -1;
|
}
|
||||||
|
|
||||||
|
void viafb_gpio_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&via_gpio_driver);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(viafb_gpio_lookup);
|
|
||||||
|
|
|
@ -8,8 +8,7 @@
|
||||||
#ifndef __VIA_GPIO_H__
|
#ifndef __VIA_GPIO_H__
|
||||||
#define __VIA_GPIO_H__
|
#define __VIA_GPIO_H__
|
||||||
|
|
||||||
extern int viafb_create_gpios(struct viafb_dev *vdev,
|
|
||||||
const struct via_port_cfg *port_cfg);
|
|
||||||
extern int viafb_destroy_gpios(void);
|
|
||||||
extern int viafb_gpio_lookup(const char *name);
|
extern int viafb_gpio_lookup(const char *name);
|
||||||
|
extern int viafb_gpio_init(void);
|
||||||
|
extern void viafb_gpio_exit(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/platform_device.h>
|
||||||
#include "via-core.h"
|
#include "via-core.h"
|
||||||
#include "via_i2c.h"
|
#include "via_i2c.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
@ -185,11 +186,14 @@ static int create_i2c_bus(struct i2c_adapter *adapter,
|
||||||
return i2c_bit_add_bus(adapter);
|
return i2c_bit_add_bus(adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
int viafb_create_i2c_busses(struct viafb_dev *dev, struct via_port_cfg *configs)
|
static int viafb_i2c_probe(struct platform_device *platdev)
|
||||||
{
|
{
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
struct via_port_cfg *configs;
|
||||||
|
|
||||||
|
i2c_vdev = platdev->dev.platform_data;
|
||||||
|
configs = i2c_vdev->port_cfg;
|
||||||
|
|
||||||
i2c_vdev = dev;
|
|
||||||
for (i = 0; i < VIAFB_NUM_PORTS; i++) {
|
for (i = 0; i < VIAFB_NUM_PORTS; i++) {
|
||||||
struct via_port_cfg *adap_cfg = configs++;
|
struct via_port_cfg *adap_cfg = configs++;
|
||||||
struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i];
|
struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i];
|
||||||
|
@ -211,7 +215,7 @@ int viafb_create_i2c_busses(struct viafb_dev *dev, struct via_port_cfg *configs)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void viafb_delete_i2c_busses(void)
|
static int viafb_i2c_remove(struct platform_device *platdev)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -224,4 +228,23 @@ void viafb_delete_i2c_busses(void)
|
||||||
if (i2c_stuff->adapter.algo_data == &i2c_stuff->algo)
|
if (i2c_stuff->adapter.algo_data == &i2c_stuff->algo)
|
||||||
i2c_del_adapter(&i2c_stuff->adapter);
|
i2c_del_adapter(&i2c_stuff->adapter);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver via_i2c_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "viafb-i2c",
|
||||||
|
},
|
||||||
|
.probe = viafb_i2c_probe,
|
||||||
|
.remove = viafb_i2c_remove,
|
||||||
|
};
|
||||||
|
|
||||||
|
int viafb_i2c_init(void)
|
||||||
|
{
|
||||||
|
return platform_driver_register(&via_i2c_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
void viafb_i2c_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&via_i2c_driver);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,6 @@ int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata);
|
||||||
int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data);
|
int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data);
|
||||||
int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len);
|
int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len);
|
||||||
|
|
||||||
struct viafb_par;
|
extern int viafb_i2c_init(void);
|
||||||
int viafb_create_i2c_busses(struct viafb_dev *vdev, struct via_port_cfg *cfg);
|
extern void viafb_i2c_exit(void);
|
||||||
void viafb_delete_i2c_busses(void);
|
|
||||||
struct i2c_adapter *viafb_find_adapter(enum viafb_i2c_adap which);
|
|
||||||
#endif /* __VIA_I2C_H__ */
|
#endif /* __VIA_I2C_H__ */
|
||||||
|
|
Loading…
Add table
Reference in a new issue