brintos

brintos / linux-shallow public Read only

0
0
Text · 8.4 KiB · 6adcad2 Raw
359 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Greybus Bridged-Phy Bus driver4 *5 * Copyright 2014 Google Inc.6 * Copyright 2014 Linaro Ltd.7 */8 9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt10 11#include <linux/types.h>12#include <linux/module.h>13#include <linux/kernel.h>14#include <linux/slab.h>15#include <linux/device.h>16#include <linux/greybus.h>17 18#include "gbphy.h"19 20#define GB_GBPHY_AUTOSUSPEND_MS	300021 22struct gbphy_host {23	struct gb_bundle *bundle;24	struct list_head devices;25};26 27static DEFINE_IDA(gbphy_id);28 29static ssize_t protocol_id_show(struct device *dev,30				struct device_attribute *attr, char *buf)31{32	struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);33 34	return sprintf(buf, "0x%02x\n", gbphy_dev->cport_desc->protocol_id);35}36static DEVICE_ATTR_RO(protocol_id);37 38static struct attribute *gbphy_dev_attrs[] = {39	&dev_attr_protocol_id.attr,40	NULL,41};42 43ATTRIBUTE_GROUPS(gbphy_dev);44 45static void gbphy_dev_release(struct device *dev)46{47	struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);48 49	ida_free(&gbphy_id, gbphy_dev->id);50	kfree(gbphy_dev);51}52 53#ifdef CONFIG_PM54static int gb_gbphy_idle(struct device *dev)55{56	pm_runtime_mark_last_busy(dev);57	pm_request_autosuspend(dev);58	return 0;59}60#endif61 62static const struct dev_pm_ops gb_gbphy_pm_ops = {63	SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend,64			   pm_generic_runtime_resume,65			   gb_gbphy_idle)66};67 68static const struct device_type greybus_gbphy_dev_type = {69	.name	 =	"gbphy_device",70	.release =	gbphy_dev_release,71	.pm	=	&gb_gbphy_pm_ops,72};73 74static int gbphy_dev_uevent(const struct device *dev, struct kobj_uevent_env *env)75{76	const struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);77	const struct greybus_descriptor_cport *cport_desc = gbphy_dev->cport_desc;78	const struct gb_bundle *bundle = gbphy_dev->bundle;79	const struct gb_interface *intf = bundle->intf;80	const struct gb_module *module = intf->module;81	const struct gb_host_device *hd = intf->hd;82 83	if (add_uevent_var(env, "BUS=%u", hd->bus_id))84		return -ENOMEM;85	if (add_uevent_var(env, "MODULE=%u", module->module_id))86		return -ENOMEM;87	if (add_uevent_var(env, "INTERFACE=%u", intf->interface_id))88		return -ENOMEM;89	if (add_uevent_var(env, "GREYBUS_ID=%08x/%08x",90			   intf->vendor_id, intf->product_id))91		return -ENOMEM;92	if (add_uevent_var(env, "BUNDLE=%u", gbphy_dev->bundle->id))93		return -ENOMEM;94	if (add_uevent_var(env, "BUNDLE_CLASS=%02x", bundle->class))95		return -ENOMEM;96	if (add_uevent_var(env, "GBPHY=%u", gbphy_dev->id))97		return -ENOMEM;98	if (add_uevent_var(env, "PROTOCOL_ID=%02x", cport_desc->protocol_id))99		return -ENOMEM;100 101	return 0;102}103 104static const struct gbphy_device_id *105gbphy_dev_match_id(struct gbphy_device *gbphy_dev,106		   struct gbphy_driver *gbphy_drv)107{108	const struct gbphy_device_id *id = gbphy_drv->id_table;109 110	if (!id)111		return NULL;112 113	for (; id->protocol_id; id++)114		if (id->protocol_id == gbphy_dev->cport_desc->protocol_id)115			return id;116 117	return NULL;118}119 120static int gbphy_dev_match(struct device *dev, const struct device_driver *drv)121{122	struct gbphy_driver *gbphy_drv = to_gbphy_driver(drv);123	struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);124	const struct gbphy_device_id *id;125 126	id = gbphy_dev_match_id(gbphy_dev, gbphy_drv);127	if (id)128		return 1;129 130	return 0;131}132 133static int gbphy_dev_probe(struct device *dev)134{135	struct gbphy_driver *gbphy_drv = to_gbphy_driver(dev->driver);136	struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);137	const struct gbphy_device_id *id;138	int ret;139 140	id = gbphy_dev_match_id(gbphy_dev, gbphy_drv);141	if (!id)142		return -ENODEV;143 144	/* for old kernels we need get_sync to resume parent devices */145	ret = gb_pm_runtime_get_sync(gbphy_dev->bundle);146	if (ret < 0)147		return ret;148 149	pm_runtime_set_autosuspend_delay(dev, GB_GBPHY_AUTOSUSPEND_MS);150	pm_runtime_use_autosuspend(dev);151	pm_runtime_get_noresume(dev);152	pm_runtime_set_active(dev);153	pm_runtime_enable(dev);154 155	/*156	 * Drivers should call put on the gbphy dev before returning157	 * from probe if they support runtime pm.158	 */159	ret = gbphy_drv->probe(gbphy_dev, id);160	if (ret) {161		pm_runtime_disable(dev);162		pm_runtime_set_suspended(dev);163		pm_runtime_put_noidle(dev);164		pm_runtime_dont_use_autosuspend(dev);165	}166 167	gb_pm_runtime_put_autosuspend(gbphy_dev->bundle);168 169	return ret;170}171 172static void gbphy_dev_remove(struct device *dev)173{174	struct gbphy_driver *gbphy_drv = to_gbphy_driver(dev->driver);175	struct gbphy_device *gbphy_dev = to_gbphy_dev(dev);176 177	gbphy_drv->remove(gbphy_dev);178 179	pm_runtime_disable(dev);180	pm_runtime_set_suspended(dev);181	pm_runtime_put_noidle(dev);182	pm_runtime_dont_use_autosuspend(dev);183}184 185static const struct bus_type gbphy_bus_type = {186	.name =		"gbphy",187	.match =	gbphy_dev_match,188	.probe =	gbphy_dev_probe,189	.remove =	gbphy_dev_remove,190	.uevent =	gbphy_dev_uevent,191};192 193int gb_gbphy_register_driver(struct gbphy_driver *driver,194			     struct module *owner, const char *mod_name)195{196	int retval;197 198	if (greybus_disabled())199		return -ENODEV;200 201	driver->driver.bus = &gbphy_bus_type;202	driver->driver.name = driver->name;203	driver->driver.owner = owner;204	driver->driver.mod_name = mod_name;205 206	retval = driver_register(&driver->driver);207	if (retval)208		return retval;209 210	pr_info("registered new driver %s\n", driver->name);211	return 0;212}213EXPORT_SYMBOL_GPL(gb_gbphy_register_driver);214 215void gb_gbphy_deregister_driver(struct gbphy_driver *driver)216{217	driver_unregister(&driver->driver);218}219EXPORT_SYMBOL_GPL(gb_gbphy_deregister_driver);220 221static struct gbphy_device *gb_gbphy_create_dev(struct gb_bundle *bundle,222						struct greybus_descriptor_cport *cport_desc)223{224	struct gbphy_device *gbphy_dev;225	int retval;226	int id;227 228	id = ida_alloc_min(&gbphy_id, 1, GFP_KERNEL);229	if (id < 0)230		return ERR_PTR(id);231 232	gbphy_dev = kzalloc(sizeof(*gbphy_dev), GFP_KERNEL);233	if (!gbphy_dev) {234		ida_free(&gbphy_id, id);235		return ERR_PTR(-ENOMEM);236	}237 238	gbphy_dev->id = id;239	gbphy_dev->bundle = bundle;240	gbphy_dev->cport_desc = cport_desc;241	gbphy_dev->dev.parent = &bundle->dev;242	gbphy_dev->dev.bus = &gbphy_bus_type;243	gbphy_dev->dev.type = &greybus_gbphy_dev_type;244	gbphy_dev->dev.groups = gbphy_dev_groups;245	gbphy_dev->dev.dma_mask = bundle->dev.dma_mask;246	dev_set_name(&gbphy_dev->dev, "gbphy%d", id);247 248	retval = device_register(&gbphy_dev->dev);249	if (retval) {250		put_device(&gbphy_dev->dev);251		return ERR_PTR(retval);252	}253 254	return gbphy_dev;255}256 257static void gb_gbphy_disconnect(struct gb_bundle *bundle)258{259	struct gbphy_host *gbphy_host = greybus_get_drvdata(bundle);260	struct gbphy_device *gbphy_dev, *temp;261	int ret;262 263	ret = gb_pm_runtime_get_sync(bundle);264	if (ret < 0)265		gb_pm_runtime_get_noresume(bundle);266 267	list_for_each_entry_safe(gbphy_dev, temp, &gbphy_host->devices, list) {268		list_del(&gbphy_dev->list);269		device_unregister(&gbphy_dev->dev);270	}271 272	kfree(gbphy_host);273}274 275static int gb_gbphy_probe(struct gb_bundle *bundle,276			  const struct greybus_bundle_id *id)277{278	struct gbphy_host *gbphy_host;279	struct gbphy_device *gbphy_dev;280	int i;281 282	if (bundle->num_cports == 0)283		return -ENODEV;284 285	gbphy_host = kzalloc(sizeof(*gbphy_host), GFP_KERNEL);286	if (!gbphy_host)287		return -ENOMEM;288 289	gbphy_host->bundle = bundle;290	INIT_LIST_HEAD(&gbphy_host->devices);291	greybus_set_drvdata(bundle, gbphy_host);292 293	/*294	 * Create a bunch of children devices, one per cport, and bind the295	 * bridged phy drivers to them.296	 */297	for (i = 0; i < bundle->num_cports; ++i) {298		gbphy_dev = gb_gbphy_create_dev(bundle, &bundle->cport_desc[i]);299		if (IS_ERR(gbphy_dev)) {300			gb_gbphy_disconnect(bundle);301			return PTR_ERR(gbphy_dev);302		}303		list_add(&gbphy_dev->list, &gbphy_host->devices);304	}305 306	gb_pm_runtime_put_autosuspend(bundle);307 308	return 0;309}310 311static const struct greybus_bundle_id gb_gbphy_id_table[] = {312	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_BRIDGED_PHY) },313	{ },314};315MODULE_DEVICE_TABLE(greybus, gb_gbphy_id_table);316 317static struct greybus_driver gb_gbphy_driver = {318	.name		= "gbphy",319	.probe		= gb_gbphy_probe,320	.disconnect	= gb_gbphy_disconnect,321	.id_table	= gb_gbphy_id_table,322};323 324static int __init gbphy_init(void)325{326	int retval;327 328	retval = bus_register(&gbphy_bus_type);329	if (retval) {330		pr_err("gbphy bus register failed (%d)\n", retval);331		return retval;332	}333 334	retval = greybus_register(&gb_gbphy_driver);335	if (retval) {336		pr_err("error registering greybus driver\n");337		goto error_gbphy;338	}339 340	return 0;341 342error_gbphy:343	bus_unregister(&gbphy_bus_type);344	ida_destroy(&gbphy_id);345	return retval;346}347module_init(gbphy_init);348 349static void __exit gbphy_exit(void)350{351	greybus_deregister(&gb_gbphy_driver);352	bus_unregister(&gbphy_bus_type);353	ida_destroy(&gbphy_id);354}355module_exit(gbphy_exit);356 357MODULE_DESCRIPTION("Greybus Bridged-Phy Bus driver");358MODULE_LICENSE("GPL v2");359