int ms_nxtmmx_register_out_port(struct ms_nxtmmx_data *mmx)
{
	struct lego_port_device *port = &mmx->port;
	int err;

	port->name = ms_nxtmmx_out_port_type.name;
	strncpy(port->address, mmx->address, LEGO_NAME_SIZE);
	port->num_modes = NUM_MS_NXTMMX_OUT_PORT_MODES;
	port->supported_modes = LEGO_PORT_ALL_MODES;
	port->mode_info = ms_nxtmmx_out_port_mode_info;
	port->set_mode = ms_nxtmmx_out_port_set_mode;
	port->tacho_motor_ops = &ms_nxtmmx_tacho_motor_ops;
	port->context = mmx;

	err = lego_port_register(port, &ms_nxtmmx_out_port_type, &mmx->i2c_client->dev);
	if (err)
		return err;
	err = ms_nxtmmx_out_port_set_mode(mmx, MS_NXTMMX_OUT_PORT_MODE_TACHO_MOTOR);
	if (err) {
		lego_port_unregister(port);
		return err;
	}

	return 0;
}
int brickpi_register_in_ports(struct brickpi_channel_data *ch_data,
			      struct device *parent)
{
	int i, err;

	for (i = 0; i < NUM_BRICKPI_PORT; i++) {
		struct lego_port_device *port = &ch_data->in_port[i].port;
		port->name = brickpi_in_port_type.name;
		snprintf(port->port_name, LEGO_PORT_NAME_SIZE, "%s:in%d",
			 dev_name(parent), ch_data->address * 2 + i - 1);
		port->num_modes = NUM_BRICKPI_IN_PORT_MODES;
		port->mode_info = brickpi_in_port_mode_info;
		port->set_mode = brickpi_in_port_set_mode;
		port->set_device = brickpi_in_port_set_device;
		port->context = &ch_data->in_port[i];
		port->nxt_analog_ops = &brickpi_in_port_nxt_analog_ops;
		//port->nxt_i2c_ops = &brickpi_in_port_nxt_i2c_ops;

		err = lego_port_register(port, &brickpi_in_port_type, parent);
		if (err) {
			dev_err(parent,
				"Failed to register BrickPi input port. (%d)\n",
				err);
			for (i--; i >= 0; i--)
				lego_port_unregister(port);
			return err;
		}
	}

	return 0;
}
int brickpi_register_in_ports(struct brickpi_channel_data *ch_data,
			      struct device *parent)
{
	int i, err;

	for (i = 0; i < NUM_BRICKPI_PORT; i++) {
		struct lego_port_device *port = &ch_data->in_port[i].port;
		port->name = brickpi_in_port_type.name;
		snprintf(port->address, LEGO_NAME_SIZE, "%s:S%d",
			 dev_name(parent), ch_data->address * 2 + i - 1);
		port->num_modes = NUM_BRICKPI_IN_PORT_MODES;
		port->supported_modes = BIT(BRICKPI_IN_PORT_MODE_NONE)
				      | BIT(BRICKPI_IN_PORT_MODE_NXT_ANALOG)
				      | BIT(BRICKPI_IN_PORT_MODE_NXT_COLOR)
				      | BIT(BRICKPI_IN_PORT_MODE_NXT_I2C);
		/* only firmware version 2 supports EV3 sensors */
		if (ch_data->fw_version >= 2) {
			port->supported_modes |= BIT(BRICKPI_IN_PORT_MODE_EV3_ANALOG)
					       | BIT(BRICKPI_IN_PORT_MODE_EV3_UART);
		}
		port->mode_info = brickpi_in_port_mode_info;
		port->set_mode = brickpi_in_port_set_mode;
		port->set_device = brickpi_in_port_set_device;
		port->ev3_uart_ops = &brickpi_ev3_uart_ops;
		port->context = &ch_data->in_port[i];
		port->nxt_analog_ops = &brickpi_in_port_nxt_analog_ops;
		//port->nxt_i2c_ops = &brickpi_in_port_nxt_i2c_ops;

		err = lego_port_register(port, &brickpi_in_port_type, parent);
		if (err) {
			dev_err(parent,
				"Failed to register BrickPi input port. (%d)\n",
				err);
			for (i--; i >= 0; i--)
				lego_port_unregister(port);
			return err;
		}
	}

	return 0;
}
struct lego_port_device
*ev3_output_port_register(struct ev3_output_port_platform_data *pdata,
			  struct device *parent)
{
	struct ev3_output_port_data *data;
	struct pwm_device *pwm;
	int err;

	if (WARN(!pdata, "Platform data is required."))
		return ERR_PTR(-EINVAL);

	data = kzalloc(sizeof(struct ev3_output_port_data), GFP_KERNEL);
	if (!data)
		return ERR_PTR(-ENOMEM);

	data->id = pdata->id;
	data->analog = get_legoev3_analog();
	if (IS_ERR(data->analog)) {
		dev_err(parent, "Could not get legoev3-analog device.\n");
		err = PTR_ERR(data->analog);
		goto err_request_legoev3_analog;
	}

	data->gpio[GPIO_PIN1].gpio	= pdata->pin1_gpio;
	data->gpio[GPIO_PIN1].flags	= GPIOF_IN;
	data->gpio[GPIO_PIN1].label	= "pin1";

	data->gpio[GPIO_PIN2].gpio	= pdata->pin2_gpio;
	data->gpio[GPIO_PIN2].flags	= GPIOF_IN;
	data->gpio[GPIO_PIN2].label	= "pin2";

	data->gpio[GPIO_PIN5].gpio	= pdata->pin5_gpio;
	data->gpio[GPIO_PIN5].flags	= GPIOF_IN;
	data->gpio[GPIO_PIN5].label	= "pin5";

	data->gpio[GPIO_PIN5_INT].gpio	= pdata->pin5_int_gpio;
	data->gpio[GPIO_PIN5_INT].flags	= GPIOF_IN;
	data->gpio[GPIO_PIN5_INT].label	= "pin5_tacho";

	data->gpio[GPIO_PIN6_DIR].gpio	= pdata->pin6_dir_gpio;
	data->gpio[GPIO_PIN6_DIR].flags	= GPIOF_IN;
	data->gpio[GPIO_PIN6_DIR].label	= "pin6";

	err = gpio_request_array(data->gpio, ARRAY_SIZE(data->gpio));
	if (err) {
		dev_err(parent, "Requesting GPIOs failed.\n");
		goto err_gpio_request_array;
	}

	data->out_port.name = ev3_output_port_type.name;
	snprintf(data->out_port.port_name, LEGO_PORT_NAME_SIZE, "out%c",
		 data->id + 'A');
	pwm = pwm_get(NULL, data->out_port.port_name);
	if (IS_ERR(pwm)) {
		dev_err(parent, "Could not get pwm! (%ld)\n", PTR_ERR(pwm));
		err = PTR_ERR(pwm);
		goto err_pwm_get;
	}

	err = pwm_config(pwm, 0, NSEC_PER_SEC / 10000);
	if (err) {
		dev_err(parent,
			"Failed to set pwm duty percent and frequency! (%d)\n",
			err);
		goto err_pwm_config;
	}

	err = pwm_enable(pwm);
	if (err) {
		dev_err(parent, "Failed to start pwm! (%d)\n", err);
		goto err_pwm_start;
	}
	/* This lets us set the pwm duty cycle in an atomic context */
	pm_runtime_irq_safe(pwm->chip->dev);
	data->pwm = pwm;

	data->out_port.num_modes = NUM_EV3_OUTPUT_PORT_MODE;
	data->out_port.mode_info = legoev3_output_port_mode_info;
	data->out_port.set_mode = ev3_output_port_set_mode;
	data->out_port.set_device = ev3_output_port_set_device;
	data->out_port.get_status = ev3_output_port_get_status;
	data->out_port.dc_motor_ops = &ev3_output_port_motor_ops;
	data->out_port.context = data;
	err = lego_port_register(&data->out_port, &ev3_output_port_type, parent);
	if (err) {
		dev_err(parent, "Failed to register lego_port_device. (%d)\n",
			err);
		goto err_lego_port_register;
	}

	INIT_WORK(&data->change_uevent_work, ev3_output_port_change_uevent_work);
	INIT_WORK(&data->work, NULL);

	data->con_state = CON_STATE_INIT;

	hrtimer_init(&data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	data->timer.function = ev3_output_port_timer_callback;
	hrtimer_start(&data->timer, ktime_set(0, OUTPUT_PORT_POLL_NS),
		      HRTIMER_MODE_REL);

	return &data->out_port;

err_lego_port_register:
	pwm_disable(pwm);
err_pwm_start:
err_pwm_config:
	pwm_put(pwm);
err_pwm_get:
	gpio_free_array(data->gpio, ARRAY_SIZE(data->gpio));
err_gpio_request_array:
	put_legoev3_analog(data->analog);
err_request_legoev3_analog:
	kfree(data);

	return ERR_PTR(err);
}