117614978SSven Van Asbroeck // SPDX-License-Identifier: GPL-2.0
217614978SSven Van Asbroeck /*
317614978SSven Van Asbroeck  * Arcx Anybus-S Controller driver
417614978SSven Van Asbroeck  *
517614978SSven Van Asbroeck  * Copyright (C) 2018 Arcx Inc
617614978SSven Van Asbroeck  */
717614978SSven Van Asbroeck 
817614978SSven Van Asbroeck #include <linux/kernel.h>
917614978SSven Van Asbroeck #include <linux/module.h>
1017614978SSven Van Asbroeck #include <linux/init.h>
1117614978SSven Van Asbroeck #include <linux/slab.h>
1217614978SSven Van Asbroeck #include <linux/platform_device.h>
1317614978SSven Van Asbroeck #include <linux/gpio/consumer.h>
1417614978SSven Van Asbroeck #include <linux/io.h>
1517614978SSven Van Asbroeck #include <linux/of.h>
1617614978SSven Van Asbroeck #include <linux/delay.h>
1717614978SSven Van Asbroeck #include <linux/idr.h>
1817614978SSven Van Asbroeck #include <linux/mutex.h>
1917614978SSven Van Asbroeck #include <linux/regulator/driver.h>
2017614978SSven Van Asbroeck #include <linux/regulator/machine.h>
2117614978SSven Van Asbroeck #include <linux/regmap.h>
2217614978SSven Van Asbroeck 
2317614978SSven Van Asbroeck /* move to <linux/anybuss-controller.h> when taking this out of staging */
2417614978SSven Van Asbroeck #include "anybuss-controller.h"
2517614978SSven Van Asbroeck 
2617614978SSven Van Asbroeck #define CPLD_STATUS1		0x80
2717614978SSven Van Asbroeck #define CPLD_CONTROL		0x80
2817614978SSven Van Asbroeck #define CPLD_CONTROL_CRST	0x40
2917614978SSven Van Asbroeck #define CPLD_CONTROL_RST1	0x04
3017614978SSven Van Asbroeck #define CPLD_CONTROL_RST2	0x80
3117614978SSven Van Asbroeck #define CPLD_STATUS1_AB		0x02
3217614978SSven Van Asbroeck #define CPLD_STATUS1_CAN_POWER	0x01
3317614978SSven Van Asbroeck #define CPLD_DESIGN_LO		0x81
3417614978SSven Van Asbroeck #define CPLD_DESIGN_HI		0x82
3517614978SSven Van Asbroeck #define CPLD_CAP		0x83
3617614978SSven Van Asbroeck #define CPLD_CAP_COMPAT		0x01
3717614978SSven Van Asbroeck #define CPLD_CAP_SEP_RESETS	0x02
3817614978SSven Van Asbroeck 
3917614978SSven Van Asbroeck struct controller_priv {
4017614978SSven Van Asbroeck 	struct device *class_dev;
4117614978SSven Van Asbroeck 	bool common_reset;
4217614978SSven Van Asbroeck 	struct gpio_desc *reset_gpiod;
4317614978SSven Van Asbroeck 	void __iomem *cpld_base;
4417614978SSven Van Asbroeck 	struct mutex ctrl_lock; /* protects CONTROL register */
4517614978SSven Van Asbroeck 	u8 control_reg;
4617614978SSven Van Asbroeck 	char version[3];
4717614978SSven Van Asbroeck 	u16 design_no;
4817614978SSven Van Asbroeck };
4917614978SSven Van Asbroeck 
do_reset(struct controller_priv * cd,u8 rst_bit,bool reset)5017614978SSven Van Asbroeck static void do_reset(struct controller_priv *cd, u8 rst_bit, bool reset)
5117614978SSven Van Asbroeck {
5217614978SSven Van Asbroeck 	mutex_lock(&cd->ctrl_lock);
5317614978SSven Van Asbroeck 	/*
5417614978SSven Van Asbroeck 	 * CPLD_CONTROL is write-only, so cache its value in
5517614978SSven Van Asbroeck 	 * cd->control_reg
5617614978SSven Van Asbroeck 	 */
5717614978SSven Van Asbroeck 	if (reset)
5817614978SSven Van Asbroeck 		cd->control_reg &= ~rst_bit;
5917614978SSven Van Asbroeck 	else
6017614978SSven Van Asbroeck 		cd->control_reg |= rst_bit;
6117614978SSven Van Asbroeck 	writeb(cd->control_reg, cd->cpld_base + CPLD_CONTROL);
6217614978SSven Van Asbroeck 	/*
6317614978SSven Van Asbroeck 	 * h/w work-around:
6417614978SSven Van Asbroeck 	 * the hardware is 'too fast', so a reset followed by an immediate
6517614978SSven Van Asbroeck 	 * not-reset will _not_ change the anybus reset line in any way,
6617614978SSven Van Asbroeck 	 * losing the reset. to prevent this from happening, introduce
6717614978SSven Van Asbroeck 	 * a minimum reset duration.
6817614978SSven Van Asbroeck 	 * Verified minimum safe duration required using a scope
6917614978SSven Van Asbroeck 	 * on 14-June-2018: 100 us.
7017614978SSven Van Asbroeck 	 */
7117614978SSven Van Asbroeck 	if (reset)
7217614978SSven Van Asbroeck 		usleep_range(100, 200);
7317614978SSven Van Asbroeck 	mutex_unlock(&cd->ctrl_lock);
7417614978SSven Van Asbroeck }
7517614978SSven Van Asbroeck 
anybuss_reset(struct controller_priv * cd,unsigned long id,bool reset)7617614978SSven Van Asbroeck static int anybuss_reset(struct controller_priv *cd,
7717614978SSven Van Asbroeck 			 unsigned long id, bool reset)
7817614978SSven Van Asbroeck {
7917614978SSven Van Asbroeck 	if (id >= 2)
8017614978SSven Van Asbroeck 		return -EINVAL;
8117614978SSven Van Asbroeck 	if (cd->common_reset)
8217614978SSven Van Asbroeck 		do_reset(cd, CPLD_CONTROL_CRST, reset);
8317614978SSven Van Asbroeck 	else
8417614978SSven Van Asbroeck 		do_reset(cd, id ? CPLD_CONTROL_RST2 : CPLD_CONTROL_RST1, reset);
8517614978SSven Van Asbroeck 	return 0;
8617614978SSven Van Asbroeck }
8717614978SSven Van Asbroeck 
export_reset_0(struct device * dev,bool assert)8817614978SSven Van Asbroeck static void export_reset_0(struct device *dev, bool assert)
8917614978SSven Van Asbroeck {
9017614978SSven Van Asbroeck 	struct controller_priv *cd = dev_get_drvdata(dev);
9117614978SSven Van Asbroeck 
9217614978SSven Van Asbroeck 	anybuss_reset(cd, 0, assert);
9317614978SSven Van Asbroeck }
9417614978SSven Van Asbroeck 
export_reset_1(struct device * dev,bool assert)9517614978SSven Van Asbroeck static void export_reset_1(struct device *dev, bool assert)
9617614978SSven Van Asbroeck {
9717614978SSven Van Asbroeck 	struct controller_priv *cd = dev_get_drvdata(dev);
9817614978SSven Van Asbroeck 
9917614978SSven Van Asbroeck 	anybuss_reset(cd, 1, assert);
10017614978SSven Van Asbroeck }
10117614978SSven Van Asbroeck 
10217614978SSven Van Asbroeck /*
10317614978SSven Van Asbroeck  * parallel bus limitation:
10417614978SSven Van Asbroeck  *
10517614978SSven Van Asbroeck  * the anybus is 8-bit wide. we can't assume that the hardware will translate
10617614978SSven Van Asbroeck  * word accesses on the parallel bus to multiple byte-accesses on the anybus.
10717614978SSven Van Asbroeck  *
10817614978SSven Van Asbroeck  * the imx WEIM bus does not provide this type of translation.
10917614978SSven Van Asbroeck  *
11017614978SSven Van Asbroeck  * to be safe, we will limit parallel bus accesses to a single byte
11117614978SSven Van Asbroeck  * at a time for now.
11217614978SSven Van Asbroeck  */
11317614978SSven Van Asbroeck 
1142411a336SSven Van Asbroeck static const struct regmap_config arcx_regmap_cfg = {
1152411a336SSven Van Asbroeck 	.reg_bits = 16,
11617614978SSven Van Asbroeck 	.val_bits = 8,
1172411a336SSven Van Asbroeck 	.max_register = 0x7ff,
1182411a336SSven Van Asbroeck 	.use_single_read = true,
1192411a336SSven Van Asbroeck 	.use_single_write = true,
12017614978SSven Van Asbroeck 	/*
12117614978SSven Van Asbroeck 	 * single-byte parallel bus accesses are atomic, so don't
12217614978SSven Van Asbroeck 	 * require any synchronization.
12317614978SSven Van Asbroeck 	 */
12417614978SSven Van Asbroeck 	.disable_locking = true,
12517614978SSven Van Asbroeck };
1262411a336SSven Van Asbroeck 
create_parallel_regmap(struct platform_device * pdev,int idx)1272411a336SSven Van Asbroeck static struct regmap *create_parallel_regmap(struct platform_device *pdev,
1282411a336SSven Van Asbroeck 					     int idx)
1292411a336SSven Van Asbroeck {
13017614978SSven Van Asbroeck 	void __iomem *base;
13117614978SSven Van Asbroeck 	struct device *dev = &pdev->dev;
13217614978SSven Van Asbroeck 
1332a8f0e9cSCristiane Naves 	base = devm_platform_ioremap_resource(pdev, idx + 1);
13417614978SSven Van Asbroeck 	if (IS_ERR(base))
13517614978SSven Van Asbroeck 		return ERR_CAST(base);
1362411a336SSven Van Asbroeck 	return devm_regmap_init_mmio(dev, base, &arcx_regmap_cfg);
13717614978SSven Van Asbroeck }
13817614978SSven Van Asbroeck 
13917614978SSven Van Asbroeck static struct anybuss_host *
create_anybus_host(struct platform_device * pdev,int idx)14017614978SSven Van Asbroeck create_anybus_host(struct platform_device *pdev, int idx)
14117614978SSven Van Asbroeck {
14217614978SSven Van Asbroeck 	struct anybuss_ops ops = {};
14317614978SSven Van Asbroeck 
14417614978SSven Van Asbroeck 	switch (idx) {
14517614978SSven Van Asbroeck 	case 0:
14617614978SSven Van Asbroeck 		ops.reset = export_reset_0;
14717614978SSven Van Asbroeck 		break;
14817614978SSven Van Asbroeck 	case 1:
14917614978SSven Van Asbroeck 		ops.reset = export_reset_1;
15017614978SSven Van Asbroeck 		break;
15117614978SSven Van Asbroeck 	default:
15217614978SSven Van Asbroeck 		return ERR_PTR(-EINVAL);
15317614978SSven Van Asbroeck 	}
15417614978SSven Van Asbroeck 	ops.host_idx = idx;
15517614978SSven Van Asbroeck 	ops.regmap = create_parallel_regmap(pdev, idx);
15617614978SSven Van Asbroeck 	if (IS_ERR(ops.regmap))
15717614978SSven Van Asbroeck 		return ERR_CAST(ops.regmap);
15817614978SSven Van Asbroeck 	ops.irq = platform_get_irq(pdev, idx);
159ac19020bSZhu Wang 	if (ops.irq < 0)
160ac19020bSZhu Wang 		return ERR_PTR(ops.irq);
16117614978SSven Van Asbroeck 	return devm_anybuss_host_common_probe(&pdev->dev, &ops);
16217614978SSven Van Asbroeck }
16317614978SSven Van Asbroeck 
version_show(struct device * dev,struct device_attribute * attr,char * buf)16417614978SSven Van Asbroeck static ssize_t version_show(struct device *dev,
16517614978SSven Van Asbroeck 			    struct device_attribute *attr, char *buf)
16617614978SSven Van Asbroeck {
16717614978SSven Van Asbroeck 	struct controller_priv *cd = dev_get_drvdata(dev);
16817614978SSven Van Asbroeck 
16917614978SSven Van Asbroeck 	return sprintf(buf, "%s\n", cd->version);
17017614978SSven Van Asbroeck }
17117614978SSven Van Asbroeck static DEVICE_ATTR_RO(version);
17217614978SSven Van Asbroeck 
design_number_show(struct device * dev,struct device_attribute * attr,char * buf)17317614978SSven Van Asbroeck static ssize_t design_number_show(struct device *dev,
17417614978SSven Van Asbroeck 				  struct device_attribute *attr, char *buf)
17517614978SSven Van Asbroeck {
17617614978SSven Van Asbroeck 	struct controller_priv *cd = dev_get_drvdata(dev);
17717614978SSven Van Asbroeck 
17817614978SSven Van Asbroeck 	return sprintf(buf, "%d\n", cd->design_no);
17917614978SSven Van Asbroeck }
18017614978SSven Van Asbroeck static DEVICE_ATTR_RO(design_number);
18117614978SSven Van Asbroeck 
18217614978SSven Van Asbroeck static struct attribute *controller_attributes[] = {
18317614978SSven Van Asbroeck 	&dev_attr_version.attr,
18417614978SSven Van Asbroeck 	&dev_attr_design_number.attr,
18517614978SSven Van Asbroeck 	NULL,
18617614978SSven Van Asbroeck };
18717614978SSven Van Asbroeck 
18856fb37efSRikard Falkeborn static const struct attribute_group controller_attribute_group = {
18917614978SSven Van Asbroeck 	.attrs = controller_attributes,
19017614978SSven Van Asbroeck };
19117614978SSven Van Asbroeck 
19217614978SSven Van Asbroeck static const struct attribute_group *controller_attribute_groups[] = {
19317614978SSven Van Asbroeck 	&controller_attribute_group,
19417614978SSven Van Asbroeck 	NULL,
19517614978SSven Van Asbroeck };
19617614978SSven Van Asbroeck 
controller_device_release(struct device * dev)19717614978SSven Van Asbroeck static void controller_device_release(struct device *dev)
19817614978SSven Van Asbroeck {
19917614978SSven Van Asbroeck 	kfree(dev);
20017614978SSven Van Asbroeck }
20117614978SSven Van Asbroeck 
can_power_is_enabled(struct regulator_dev * rdev)20217614978SSven Van Asbroeck static int can_power_is_enabled(struct regulator_dev *rdev)
20317614978SSven Van Asbroeck {
20417614978SSven Van Asbroeck 	struct controller_priv *cd = rdev_get_drvdata(rdev);
20517614978SSven Van Asbroeck 
20617614978SSven Van Asbroeck 	return !(readb(cd->cpld_base + CPLD_STATUS1) & CPLD_STATUS1_CAN_POWER);
20717614978SSven Van Asbroeck }
20817614978SSven Van Asbroeck 
20956fb37efSRikard Falkeborn static const struct regulator_ops can_power_ops = {
21017614978SSven Van Asbroeck 	.is_enabled = can_power_is_enabled,
21117614978SSven Van Asbroeck };
21217614978SSven Van Asbroeck 
21317614978SSven Van Asbroeck static const struct regulator_desc can_power_desc = {
21417614978SSven Van Asbroeck 	.name = "regulator-can-power",
21517614978SSven Van Asbroeck 	.id = -1,
21617614978SSven Van Asbroeck 	.type = REGULATOR_VOLTAGE,
21717614978SSven Van Asbroeck 	.owner = THIS_MODULE,
21817614978SSven Van Asbroeck 	.ops = &can_power_ops,
21917614978SSven Van Asbroeck };
22017614978SSven Van Asbroeck 
22117614978SSven Van Asbroeck static struct class *controller_class;
22217614978SSven Van Asbroeck static DEFINE_IDA(controller_index_ida);
22317614978SSven Van Asbroeck 
controller_probe(struct platform_device * pdev)22417614978SSven Van Asbroeck static int controller_probe(struct platform_device *pdev)
22517614978SSven Van Asbroeck {
22617614978SSven Van Asbroeck 	struct controller_priv *cd;
22717614978SSven Van Asbroeck 	struct device *dev = &pdev->dev;
22817614978SSven Van Asbroeck 	struct regulator_config config = { };
22917614978SSven Van Asbroeck 	struct regulator_dev *regulator;
23017614978SSven Van Asbroeck 	int err, id;
23117614978SSven Van Asbroeck 	struct anybuss_host *host;
23217614978SSven Van Asbroeck 	u8 status1, cap;
23317614978SSven Van Asbroeck 
23417614978SSven Van Asbroeck 	cd = devm_kzalloc(dev, sizeof(*cd), GFP_KERNEL);
23517614978SSven Van Asbroeck 	if (!cd)
23617614978SSven Van Asbroeck 		return -ENOMEM;
23717614978SSven Van Asbroeck 	dev_set_drvdata(dev, cd);
23817614978SSven Van Asbroeck 	mutex_init(&cd->ctrl_lock);
23917614978SSven Van Asbroeck 	cd->reset_gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
24017614978SSven Van Asbroeck 	if (IS_ERR(cd->reset_gpiod))
24117614978SSven Van Asbroeck 		return PTR_ERR(cd->reset_gpiod);
24217614978SSven Van Asbroeck 
24317614978SSven Van Asbroeck 	/* CPLD control memory, sits at index 0 */
2442a8f0e9cSCristiane Naves 	cd->cpld_base = devm_platform_ioremap_resource(pdev, 0);
24517614978SSven Van Asbroeck 	if (IS_ERR(cd->cpld_base)) {
24617614978SSven Van Asbroeck 		dev_err(dev,
24717614978SSven Van Asbroeck 			"failed to map cpld base address\n");
24817614978SSven Van Asbroeck 		err = PTR_ERR(cd->cpld_base);
24917614978SSven Van Asbroeck 		goto out_reset;
25017614978SSven Van Asbroeck 	}
25117614978SSven Van Asbroeck 
25217614978SSven Van Asbroeck 	/* identify cpld */
25317614978SSven Van Asbroeck 	status1 = readb(cd->cpld_base + CPLD_STATUS1);
25417614978SSven Van Asbroeck 	cd->design_no = (readb(cd->cpld_base + CPLD_DESIGN_HI) << 8) |
25517614978SSven Van Asbroeck 				readb(cd->cpld_base + CPLD_DESIGN_LO);
25617614978SSven Van Asbroeck 	snprintf(cd->version, sizeof(cd->version), "%c%d",
25717614978SSven Van Asbroeck 		 'A' + ((status1 >> 5) & 0x7),
25817614978SSven Van Asbroeck 		 (status1 >> 2) & 0x7);
25917614978SSven Van Asbroeck 	dev_info(dev, "design number %d, revision %s\n",
26017614978SSven Van Asbroeck 		 cd->design_no,
26117614978SSven Van Asbroeck 		cd->version);
26217614978SSven Van Asbroeck 	cap = readb(cd->cpld_base + CPLD_CAP);
26317614978SSven Van Asbroeck 	if (!(cap & CPLD_CAP_COMPAT)) {
26417614978SSven Van Asbroeck 		dev_err(dev, "unsupported controller [cap=0x%02X]", cap);
26517614978SSven Van Asbroeck 		err = -ENODEV;
26617614978SSven Van Asbroeck 		goto out_reset;
26717614978SSven Van Asbroeck 	}
26817614978SSven Van Asbroeck 
26917614978SSven Van Asbroeck 	if (status1 & CPLD_STATUS1_AB) {
27017614978SSven Van Asbroeck 		dev_info(dev, "has anybus-S slot(s)");
27117614978SSven Van Asbroeck 		cd->common_reset = !(cap & CPLD_CAP_SEP_RESETS);
27217614978SSven Van Asbroeck 		dev_info(dev, "supports %s", cd->common_reset ?
27317614978SSven Van Asbroeck 			"a common reset" : "separate resets");
27417614978SSven Van Asbroeck 		for (id = 0; id < 2; id++) {
27517614978SSven Van Asbroeck 			host = create_anybus_host(pdev, id);
27617614978SSven Van Asbroeck 			if (!IS_ERR(host))
27717614978SSven Van Asbroeck 				continue;
27817614978SSven Van Asbroeck 			err = PTR_ERR(host);
27917614978SSven Van Asbroeck 			/* -ENODEV is fine, it just means no card detected */
28017614978SSven Van Asbroeck 			if (err != -ENODEV)
28117614978SSven Van Asbroeck 				goto out_reset;
28217614978SSven Van Asbroeck 		}
28317614978SSven Van Asbroeck 	}
28417614978SSven Van Asbroeck 
28517614978SSven Van Asbroeck 	id = ida_simple_get(&controller_index_ida, 0, 0, GFP_KERNEL);
28617614978SSven Van Asbroeck 	if (id < 0) {
28717614978SSven Van Asbroeck 		err = id;
28817614978SSven Van Asbroeck 		goto out_reset;
28917614978SSven Van Asbroeck 	}
29017614978SSven Van Asbroeck 	/* export can power readout as a regulator */
29117614978SSven Van Asbroeck 	config.dev = dev;
29217614978SSven Van Asbroeck 	config.driver_data = cd;
29317614978SSven Van Asbroeck 	regulator = devm_regulator_register(dev, &can_power_desc, &config);
29417614978SSven Van Asbroeck 	if (IS_ERR(regulator)) {
29517614978SSven Van Asbroeck 		err = PTR_ERR(regulator);
2967e97e4cbSJing Xiangfeng 		goto out_ida;
29717614978SSven Van Asbroeck 	}
29817614978SSven Van Asbroeck 	/* make controller info visible to userspace */
29917614978SSven Van Asbroeck 	cd->class_dev = kzalloc(sizeof(*cd->class_dev), GFP_KERNEL);
30017614978SSven Van Asbroeck 	if (!cd->class_dev) {
30117614978SSven Van Asbroeck 		err = -ENOMEM;
30217614978SSven Van Asbroeck 		goto out_ida;
30317614978SSven Van Asbroeck 	}
30417614978SSven Van Asbroeck 	cd->class_dev->class = controller_class;
30517614978SSven Van Asbroeck 	cd->class_dev->groups = controller_attribute_groups;
30617614978SSven Van Asbroeck 	cd->class_dev->parent = dev;
30717614978SSven Van Asbroeck 	cd->class_dev->id = id;
30817614978SSven Van Asbroeck 	cd->class_dev->release = controller_device_release;
30917614978SSven Van Asbroeck 	dev_set_name(cd->class_dev, "%d", cd->class_dev->id);
31017614978SSven Van Asbroeck 	dev_set_drvdata(cd->class_dev, cd);
31117614978SSven Van Asbroeck 	err = device_register(cd->class_dev);
31217614978SSven Van Asbroeck 	if (err)
31317614978SSven Van Asbroeck 		goto out_dev;
31417614978SSven Van Asbroeck 	return 0;
31517614978SSven Van Asbroeck out_dev:
31617614978SSven Van Asbroeck 	put_device(cd->class_dev);
31717614978SSven Van Asbroeck out_ida:
31817614978SSven Van Asbroeck 	ida_simple_remove(&controller_index_ida, id);
31917614978SSven Van Asbroeck out_reset:
32017614978SSven Van Asbroeck 	gpiod_set_value_cansleep(cd->reset_gpiod, 1);
32117614978SSven Van Asbroeck 	return err;
32217614978SSven Van Asbroeck }
32317614978SSven Van Asbroeck 
controller_remove(struct platform_device * pdev)324ba110722SUwe Kleine-König static void controller_remove(struct platform_device *pdev)
32517614978SSven Van Asbroeck {
32617614978SSven Van Asbroeck 	struct controller_priv *cd = platform_get_drvdata(pdev);
32717614978SSven Van Asbroeck 	int id = cd->class_dev->id;
32817614978SSven Van Asbroeck 
32917614978SSven Van Asbroeck 	device_unregister(cd->class_dev);
33017614978SSven Van Asbroeck 	ida_simple_remove(&controller_index_ida, id);
33117614978SSven Van Asbroeck 	gpiod_set_value_cansleep(cd->reset_gpiod, 1);
33217614978SSven Van Asbroeck }
33317614978SSven Van Asbroeck 
33417614978SSven Van Asbroeck static const struct of_device_id controller_of_match[] = {
33517614978SSven Van Asbroeck 	{ .compatible = "arcx,anybus-controller" },
33617614978SSven Van Asbroeck 	{ }
33717614978SSven Van Asbroeck };
33817614978SSven Van Asbroeck 
33917614978SSven Van Asbroeck MODULE_DEVICE_TABLE(of, controller_of_match);
34017614978SSven Van Asbroeck 
34117614978SSven Van Asbroeck static struct platform_driver controller_driver = {
34217614978SSven Van Asbroeck 	.probe = controller_probe,
343ba110722SUwe Kleine-König 	.remove_new = controller_remove,
34417614978SSven Van Asbroeck 	.driver		= {
34517614978SSven Van Asbroeck 		.name   = "arcx-anybus-controller",
346*656ae4f4SRuan Jinjie 		.of_match_table	= controller_of_match,
34717614978SSven Van Asbroeck 	},
34817614978SSven Van Asbroeck };
34917614978SSven Van Asbroeck 
controller_init(void)35017614978SSven Van Asbroeck static int __init controller_init(void)
35117614978SSven Van Asbroeck {
35217614978SSven Van Asbroeck 	int err;
35317614978SSven Van Asbroeck 
3541aaba11dSGreg Kroah-Hartman 	controller_class = class_create("arcx_anybus_controller");
35517614978SSven Van Asbroeck 	if (IS_ERR(controller_class))
35617614978SSven Van Asbroeck 		return PTR_ERR(controller_class);
35717614978SSven Van Asbroeck 	err = platform_driver_register(&controller_driver);
35817614978SSven Van Asbroeck 	if (err)
35917614978SSven Van Asbroeck 		class_destroy(controller_class);
36017614978SSven Van Asbroeck 
36117614978SSven Van Asbroeck 	return err;
36217614978SSven Van Asbroeck }
36317614978SSven Van Asbroeck 
controller_exit(void)36417614978SSven Van Asbroeck static void __exit controller_exit(void)
36517614978SSven Van Asbroeck {
36617614978SSven Van Asbroeck 	platform_driver_unregister(&controller_driver);
36717614978SSven Van Asbroeck 	class_destroy(controller_class);
36817614978SSven Van Asbroeck 	ida_destroy(&controller_index_ida);
36917614978SSven Van Asbroeck }
37017614978SSven Van Asbroeck 
37117614978SSven Van Asbroeck module_init(controller_init);
37217614978SSven Van Asbroeck module_exit(controller_exit);
37317614978SSven Van Asbroeck 
37417614978SSven Van Asbroeck MODULE_DESCRIPTION("Arcx Anybus-S Controller driver");
37517614978SSven Van Asbroeck MODULE_AUTHOR("Sven Van Asbroeck <TheSven73@gmail.com>");
37617614978SSven Van Asbroeck MODULE_LICENSE("GPL v2");
377