brintos

brintos / linux-shallow public Read only

0
0
Text · 7.5 KiB · 1cb7b90 Raw
332 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * PWM Greybus driver.4 *5 * Copyright 2014 Google Inc.6 * Copyright 2014 Linaro Ltd.7 */8 9#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/slab.h>12#include <linux/pwm.h>13#include <linux/greybus.h>14 15#include "gbphy.h"16 17struct gb_pwm_chip {18	struct gb_connection	*connection;19	struct pwm_chip		chip;20};21 22static inline struct gb_pwm_chip *pwm_chip_to_gb_pwm_chip(struct pwm_chip *chip)23{24	return container_of(chip, struct gb_pwm_chip, chip);25}26 27static int gb_pwm_get_npwm(struct gb_connection *connection)28{29	struct gb_pwm_count_response response;30	int ret;31 32	ret = gb_operation_sync(connection, GB_PWM_TYPE_PWM_COUNT,33				NULL, 0, &response, sizeof(response));34	if (ret)35		return ret;36 37	/*38	 * The request returns the highest allowed PWM id parameter. So add one39	 * to get the number of PWMs.40	 */41	return response.count + 1;42}43 44static int gb_pwm_activate_operation(struct pwm_chip *chip, u8 which)45{46	struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);47	struct gb_pwm_activate_request request;48	struct gbphy_device *gbphy_dev;49	int ret;50 51	request.which = which;52 53	gbphy_dev = to_gbphy_dev(pwmchip_parent(chip));54	ret = gbphy_runtime_get_sync(gbphy_dev);55	if (ret)56		return ret;57 58	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_ACTIVATE,59				&request, sizeof(request), NULL, 0);60 61	gbphy_runtime_put_autosuspend(gbphy_dev);62 63	return ret;64}65 66static int gb_pwm_deactivate_operation(struct pwm_chip *chip, u8 which)67{68	struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);69	struct gb_pwm_deactivate_request request;70	struct gbphy_device *gbphy_dev;71	int ret;72 73	request.which = which;74 75	gbphy_dev = to_gbphy_dev(pwmchip_parent(chip));76	ret = gbphy_runtime_get_sync(gbphy_dev);77	if (ret)78		return ret;79 80	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DEACTIVATE,81				&request, sizeof(request), NULL, 0);82 83	gbphy_runtime_put_autosuspend(gbphy_dev);84 85	return ret;86}87 88static int gb_pwm_config_operation(struct pwm_chip *chip,89				   u8 which, u32 duty, u32 period)90{91	struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);92	struct gb_pwm_config_request request;93	struct gbphy_device *gbphy_dev;94	int ret;95 96	request.which = which;97	request.duty = cpu_to_le32(duty);98	request.period = cpu_to_le32(period);99 100	gbphy_dev = to_gbphy_dev(pwmchip_parent(chip));101	ret = gbphy_runtime_get_sync(gbphy_dev);102	if (ret)103		return ret;104 105	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_CONFIG,106				&request, sizeof(request), NULL, 0);107 108	gbphy_runtime_put_autosuspend(gbphy_dev);109 110	return ret;111}112 113static int gb_pwm_set_polarity_operation(struct pwm_chip *chip,114					 u8 which, u8 polarity)115{116	struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);117	struct gb_pwm_polarity_request request;118	struct gbphy_device *gbphy_dev;119	int ret;120 121	request.which = which;122	request.polarity = polarity;123 124	gbphy_dev = to_gbphy_dev(pwmchip_parent(chip));125	ret = gbphy_runtime_get_sync(gbphy_dev);126	if (ret)127		return ret;128 129	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_POLARITY,130				&request, sizeof(request), NULL, 0);131 132	gbphy_runtime_put_autosuspend(gbphy_dev);133 134	return ret;135}136 137static int gb_pwm_enable_operation(struct pwm_chip *chip, u8 which)138{139	struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);140	struct gb_pwm_enable_request request;141	struct gbphy_device *gbphy_dev;142	int ret;143 144	request.which = which;145 146	gbphy_dev = to_gbphy_dev(pwmchip_parent(chip));147	ret = gbphy_runtime_get_sync(gbphy_dev);148	if (ret)149		return ret;150 151	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_ENABLE,152				&request, sizeof(request), NULL, 0);153	if (ret)154		gbphy_runtime_put_autosuspend(gbphy_dev);155 156	return ret;157}158 159static int gb_pwm_disable_operation(struct pwm_chip *chip, u8 which)160{161	struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);162	struct gb_pwm_disable_request request;163	struct gbphy_device *gbphy_dev;164	int ret;165 166	request.which = which;167 168	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DISABLE,169				&request, sizeof(request), NULL, 0);170 171	gbphy_dev = to_gbphy_dev(pwmchip_parent(chip));172	gbphy_runtime_put_autosuspend(gbphy_dev);173 174	return ret;175}176 177static int gb_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)178{179	return gb_pwm_activate_operation(chip, pwm->hwpwm);180};181 182static void gb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)183{184	if (pwm_is_enabled(pwm))185		dev_warn(pwmchip_parent(chip), "freeing PWM device without disabling\n");186 187	gb_pwm_deactivate_operation(chip, pwm->hwpwm);188}189 190static int gb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,191			const struct pwm_state *state)192{193	int err;194	bool enabled = pwm->state.enabled;195	u64 period = state->period;196	u64 duty_cycle = state->duty_cycle;197 198	/* Set polarity */199	if (state->polarity != pwm->state.polarity) {200		if (enabled) {201			gb_pwm_disable_operation(chip, pwm->hwpwm);202			enabled = false;203		}204		err = gb_pwm_set_polarity_operation(chip, pwm->hwpwm, state->polarity);205		if (err)206			return err;207	}208 209	if (!state->enabled) {210		if (enabled)211			gb_pwm_disable_operation(chip, pwm->hwpwm);212		return 0;213	}214 215	/*216	 * Set period and duty cycle217	 *218	 * PWM privodes 64-bit period and duty_cycle, but greybus only accepts219	 * 32-bit, so their values have to be limited to U32_MAX.220	 */221	if (period > U32_MAX)222		period = U32_MAX;223 224	if (duty_cycle > period)225		duty_cycle = period;226 227	err = gb_pwm_config_operation(chip, pwm->hwpwm, duty_cycle, period);228	if (err)229		return err;230 231	/* enable/disable */232	if (!enabled)233		return gb_pwm_enable_operation(chip, pwm->hwpwm);234 235	return 0;236}237 238static const struct pwm_ops gb_pwm_ops = {239	.request = gb_pwm_request,240	.free = gb_pwm_free,241	.apply = gb_pwm_apply,242};243 244static int gb_pwm_probe(struct gbphy_device *gbphy_dev,245			const struct gbphy_device_id *id)246{247	struct gb_connection *connection;248	struct gb_pwm_chip *pwmc;249	struct pwm_chip *chip;250	int ret, npwm;251 252	connection = gb_connection_create(gbphy_dev->bundle,253					  le16_to_cpu(gbphy_dev->cport_desc->id),254					  NULL);255	if (IS_ERR(connection))256		return PTR_ERR(connection);257 258	ret = gb_connection_enable(connection);259	if (ret)260		goto exit_connection_destroy;261 262	/* Query number of pwms present */263	ret = gb_pwm_get_npwm(connection);264	if (ret < 0)265		goto exit_connection_disable;266	npwm = ret;267 268	chip = pwmchip_alloc(&gbphy_dev->dev, npwm, sizeof(*pwmc));269	if (IS_ERR(chip)) {270		ret = PTR_ERR(chip);271		goto exit_connection_disable;272	}273	gb_gbphy_set_data(gbphy_dev, chip);274 275	pwmc = pwm_chip_to_gb_pwm_chip(chip);276	pwmc->connection = connection;277 278	chip->ops = &gb_pwm_ops;279 280	ret = pwmchip_add(chip);281	if (ret) {282		dev_err(&gbphy_dev->dev,283			"failed to register PWM: %d\n", ret);284		goto exit_pwmchip_put;285	}286 287	gbphy_runtime_put_autosuspend(gbphy_dev);288	return 0;289 290exit_pwmchip_put:291	pwmchip_put(chip);292exit_connection_disable:293	gb_connection_disable(connection);294exit_connection_destroy:295	gb_connection_destroy(connection);296	return ret;297}298 299static void gb_pwm_remove(struct gbphy_device *gbphy_dev)300{301	struct pwm_chip *chip = gb_gbphy_get_data(gbphy_dev);302	struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);303	struct gb_connection *connection = pwmc->connection;304	int ret;305 306	ret = gbphy_runtime_get_sync(gbphy_dev);307	if (ret)308		gbphy_runtime_get_noresume(gbphy_dev);309 310	pwmchip_remove(chip);311	pwmchip_put(chip);312	gb_connection_disable(connection);313	gb_connection_destroy(connection);314}315 316static const struct gbphy_device_id gb_pwm_id_table[] = {317	{ GBPHY_PROTOCOL(GREYBUS_PROTOCOL_PWM) },318	{ },319};320MODULE_DEVICE_TABLE(gbphy, gb_pwm_id_table);321 322static struct gbphy_driver pwm_driver = {323	.name		= "pwm",324	.probe		= gb_pwm_probe,325	.remove		= gb_pwm_remove,326	.id_table	= gb_pwm_id_table,327};328 329module_gbphy_driver(pwm_driver);330MODULE_DESCRIPTION("PWM Greybus driver");331MODULE_LICENSE("GPL v2");332