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

Commit 7582eb9b authored by Jonathan Corbet's avatar Jonathan Corbet
Browse files

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: default avatarFlorian Tobias Schandinat <FlorianSchandinat@gmx.de>
Signed-off-by: default avatarJonathan Corbet <corbet@lwn.net>
parent 75b035ac
Loading
Loading
Loading
Loading
+75 −16
Original line number Diff line number Diff line
@@ -190,6 +190,70 @@ static void __devexit via_pci_teardown_mmio(struct viafb_dev *vdev)
	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,
		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));
	global_dev.pdev = pdev;
	global_dev.chip_type = ent->driver_data;
	global_dev.port_cfg = adap_configs;
	spin_lock_init(&global_dev.reg_lock);
	ret = via_pci_setup_mmio(&global_dev);
	if (ret)
		goto out_disable;
	/*
	 * Create the I2C busses.  Bailing out on failure seems extreme,
	 * but that's what the code did before.
	 * Create our subdevices.  Continue even if some things fail.
	 */
	ret = viafb_create_i2c_busses(&global_dev, adap_configs);
	if (ret)
		goto out_teardown;
	via_setup_subdevs(&global_dev);
	/*
	 * Set up the framebuffer.
	 */
	ret = via_fb_pci_probe(&global_dev);
	if (ret)
		goto out_i2c;
	/*
	 * 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);
		goto out_subdevs;
	return 0;

out_i2c:
	viafb_delete_i2c_busses();
out_teardown:
out_subdevs:
	via_teardown_subdevs();
	via_pci_teardown_mmio(&global_dev);
out_disable:
	pci_disable_device(pdev);
@@ -240,8 +296,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,

static void __devexit via_pci_remove(struct pci_dev *pdev)
{
	viafb_destroy_gpios();
	viafb_delete_i2c_busses();
	via_teardown_subdevs();
	via_fb_pci_remove(pdev);
	via_pci_teardown_mmio(&global_dev);
	pci_disable_device(pdev);
@@ -289,12 +344,16 @@ static int __init via_core_init(void)
	ret = viafb_init();
	if (ret)
		return ret;
	viafb_i2c_init();
	viafb_gpio_init();
	return pci_register_driver(&via_driver);
}

static void __exit via_core_exit(void)
{
	pci_unregister_driver(&via_driver);
	viafb_gpio_exit();
	viafb_i2c_exit();
	viafb_exit();
}

+1 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ struct via_port_cfg {
struct viafb_dev {
	struct pci_dev *pdev;
	int chip_type;
	struct via_port_cfg *port_cfg;
	/*
	 * Spinlock for access to device registers.  Not yet
	 * globally used.
+34 −15
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@

#include <linux/spinlock.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include "via-core.h"
#include "via-gpio.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);
}

/*
 * Look up a specific gpio and return the number it was assigned.
 */
int viafb_gpio_lookup(const char *name)
{
	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);


int viafb_create_gpios(struct viafb_dev *vdev,
		const struct via_port_cfg *port_cfg)
/*
 * 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;
	struct viafb_gpio *gpio;
	unsigned long flags;
@@ -222,11 +238,10 @@ int viafb_create_gpios(struct viafb_dev *vdev,
		gpio_config.gpio_chip.ngpio = 0;
	}
	return ret;
/* Port enable ? */
}


int viafb_destroy_gpios(void)
static int viafb_gpio_remove(struct platform_device *platdev)
{
	unsigned long flags;
	int ret = 0, i;
@@ -253,16 +268,20 @@ int viafb_destroy_gpios(void)
	return ret;
}

/*
 * Look up a specific gpio and return the number it was assigned.
 */
int viafb_gpio_lookup(const char *name)
static struct platform_driver via_gpio_driver = {
	.driver = {
		.name = "viafb-gpio",
	},
	.probe = viafb_gpio_probe,
	.remove = viafb_gpio_remove,
};

int viafb_gpio_init(void)
{
	int i;
	return platform_driver_register(&via_gpio_driver);
}

	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;
void viafb_gpio_exit(void)
{
	platform_driver_unregister(&via_gpio_driver);
}
EXPORT_SYMBOL_GPL(viafb_gpio_lookup);
+2 −3
Original line number Diff line number Diff line
@@ -8,8 +8,7 @@
#ifndef __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_init(void);
extern void viafb_gpio_exit(void);
#endif
+26 −3
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <linux/platform_device.h>
#include "via-core.h"
#include "via_i2c.h"
#include "global.h"
@@ -185,11 +186,14 @@ static int create_i2c_bus(struct i2c_adapter *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;
	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++) {
		struct via_port_cfg *adap_cfg = configs++;
		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;
}

void viafb_delete_i2c_busses(void)
static int viafb_i2c_remove(struct platform_device *platdev)
{
	int i;

@@ -224,4 +228,23 @@ void viafb_delete_i2c_busses(void)
		if (i2c_stuff->adapter.algo_data == &i2c_stuff->algo)
			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);
}
Loading